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 Problem with Requirement Silos

In most software projects, requirements live in Jira. Code lives in a repository. Tests live somewhere else again. When a developer asks "which code implements Feature-456?", the answer requires jumping between systems, reading comments, grepping for magic strings, and hoping someone documented things correctly.

In a wide solution -- or worse, a multi-solution mega mono-repo -- this problem is exponentially worse. A single Feature like "Order Processing" spans OrderService.dll (API server), PaymentGateway.dll (separate service on another machine), NotificationWorker.dll (background worker), and OrderTests.dll (verification). A developer touching one of these has no way to know which Feature it belongs to, which acceptance criteria are validated, which tests cover them, or what the Product Owner actually specified. The requirement silo isn't just an inconvenience -- it's a structural gap that makes large-scale development fragile.

Common "solutions" make it worse:

// String-based approach: looks safe, is not
[Feature(Id = "FEATURE-456", AcceptanceCriteria = new[] { "Admin can assign roles" })]
public class UserRoleFeature { }  // Empty marker class — dead code

[Implements("FEATURE-456")]       // String. Typo? Compiles fine.
public void AssignRole() { }

[FeatureTest("FEATURE-456", 0)]   // Index 0? What if someone reorders the array?
public void AdminCanAssign() { }

The problems are structural:

  1. Requirements are metadata on marker classes -- not real types with behavior
  2. Links are string-based -- "FEATURE-456" is not checked by the compiler. Typos, renames, and deletions are silent
  3. Acceptance criteria are string arrays -- "Admin can assign roles" says nothing the compiler can verify
  4. Tests reference requirements by index -- AC[0] breaks when someone reorders the acceptance criteria list
  5. No compile-time guarantee that an implementation actually satisfies a specification

What if requirements were types? What if acceptance criteria were abstract methods? What if the compiler refused to build until every AC was implemented and tested?

This approach applies the same principle as DDD -- model the problem domain first, let the compiler enforce the model -- and the same meta-metamodeling architecture: requirements become M2 concepts, and specific features become M1 instances that the source generator validates at build time.


The Chain: Six Projects, One Compiler

The design is six C# projects linked by <ProjectReference>. Each boundary is enforced by the C# type system. Each project compiles to a DLL artifact with a clear role:

MyApp.sln
├── src/
│   ├── MyApp.Requirements/          ← Features as types, ACs as abstract methods
│   ├── MyApp.SharedKernel/          ← Domain types (User, Role, Permission)
│   ├── MyApp.Specifications/        ← Interfaces the domain must implement
│   ├── MyApp.Domain/                ← Domain implementation (: ISpec)
│   └── MyApp.Api/                   ← Production host (DI, controllers, middleware)
├── test/
│   └── MyApp.Tests/                 ← Type-linked verification
└── tools/
    └── MyApp.Requirements.Analyzers/ ← Source generator (registry, matrix, diagnostics)

Project reference graph:

Requirements ──┐
               ├──> Specifications ──> Domain ← Api
SharedKernel ──┘         │                │
                         └────────────────┴──> Tests
Project DLL Artifact Role Depends On
Requirements MyApp.Requirements.dll Features as types, AC methods, generated attributes Nothing
SharedKernel MyApp.SharedKernel.dll Domain value types (User, Role, Permission, Result) Nothing
Specifications MyApp.Specifications.dll Interfaces per feature, validator bridges Requirements + SharedKernel
Domain MyApp.Domain.dll Implements spec interfaces -- compiler enforces Specifications
Api MyApp.Api.dll Production host: DI, controllers, middleware Domain
Tests MyApp.Tests.dll Verifies implementation via type refs Domain + Specifications

Every link between layers uses typeof() or nameof() -- Ctrl+Click navigable in the IDE, rename-safe, compiler-checked.

⬇ Download