Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

The Thesis

Convention over Configuration was a revolution. It eliminated thousands of lines of XML and replaced them with naming rules and folder structures.

But Convention has a hidden cost: you must document every convention (wikis, ADRs, onboarding guides) and enforce every convention (ArchUnit, NetArchTest, custom analyzers, CI scripts). That is work done twice — and both artifacts drift independently from the codebase they describe.

What if the compiler could replace all of that? What if a single attribute — [AggregateRoot], [Injectable], [Validated] — drove a Source Generator that produced the correct code, and a Roslyn Analyzer that guarded the boundaries? No convention to document. No enforcement code to maintain. The attribute IS the documentation. The generated code IS the implementation.

This series calls that fourth era Contention — where the compiler contends with the developer, not through convention policing, but through type-safe code generation.


Part I: The Four Eras

Code, Configuration, Convention, Contention — four ways to tell a system what to do. Each era improves on the last. The Convention Tax: why documenting and enforcing invisible rules is double the cost of just generating the right code. The Rosetta Stone example: [AggregateRoot] across all four eras.

Part II: Dependency Injection

From new UserService(new UserRepository(...)) to XML containers to Scrutor assembly scanning to [Injectable(Lifetime.Scoped)]. The convention era requires a naming doc, a scanning config, and an integration test. Contention: one attribute, zero enforcement code.

Part III: Validation

From manual if-checks to DataAnnotations to FluentValidation to [Validated] source-generated validators. Convention says "every command must have a validator" — but who checks? Contention: the SG generates the validator from required properties. Nothing to forget.

Part IV: API Contracts and Serialization

From hand-built JSON responses to Swagger annotations to Minimal APIs to [TypedEndpoint] that generates the endpoint, OpenAPI spec, and typed client in one pass. Convention says "all endpoints return Result" — but the coding standard drifts from the codebase within weeks.

Part V: Database Mapping and EF Core

From ADO.NET to NHibernate XML to EF Core conventions to [AggregateRoot] / [ValueObject] driving EF configuration, repository interfaces, and factory generation. The flagship example from the CMF DDD DSL — where Convention required folder structure docs, EF convention docs, and NetArchTest rules. Contention: one attribute per entity.

Part VI: Testing and Requirements

From random tests to [Trait] metadata to folder naming conventions to [ForRequirement(typeof(Feature))] with a source-generated compliance matrix. Convention required a test plan document, a naming convention wiki, and a custom compliance scanner. Contention: the type system IS the traceability matrix.

Part VII: Architecture Enforcement

From wiki pages to NDepend XML to NetArchTest to [Layer("Domain")] with source-generated project constraints. Convention: an ADR, a NetArchTest suite, a CI check. Contention: one attribute, and the SG generates InternalsVisibleTo restrictions that make illegal dependencies a compile error.

Part VIII: Configuration and Options

From AppSettings["key"] to appsettings.json to IOptions<T> to [StronglyTypedOptions("Smtp")] with source-generated binders and validators. Convention: an options documentation page, a validation convention doc, and a startup integration test. Contention: one attribute.

Part IX: Error Handling and Result Types

From try/catch to exception hierarchies to Result<T> to [MustHandle] analyzers with source-generated exhaustive Match() methods. Convention says "always pattern-match your Results" — but code review is the only enforcement. Contention: the analyzer refuses to compile unmatched Results.

Part X: Logging and Security

From Console.WriteLine to NLog XML to ILogger<T> to [LoggerMessage] source generation. From if (user.Role == "Admin") to [Authorize(Policy)] to [RequiresPermission(Permission.ManageUsers)] with source-generated policy registration. Two domains, one pattern: Convention documents and polices. Contention generates and guards.

Part XI: The Compiler as Architect

The Grand Convention Tax Table across all 10 domains. The meta-pattern: Attribute → Source Generator → Generated Code → Analyzer → Diagnostic. When contention goes too far. The thesis restated: Convention is an honor system with expensive policing. Contention is a type system with free generation.


How to Read This Series

Architects evaluating the approach should read Parts I, V, VII, and XI — the thesis, the DDD flagship, architecture enforcement, and the synthesis.

Developers adopting Source Generators should read Parts I-III for the fundamentals, then jump to whichever domain matches their current work.

Tech leads frustrated with convention drift should read Parts I and XI, then the domain that hurts most on their team.

Anyone in a hurry should read Part I (the framework) and Part XI (the verdict).


Prerequisites

  • Familiarity with C# and .NET (the examples use .NET 8+)
  • Basic understanding of Source Generators (or willingness to learn — Part I covers the essentials)
  • Experience with at least one "Convention over Configuration" framework (ASP.NET Core, Rails, Spring Boot)

This series builds on and references: