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 No-Spec Cost

Scaling Requirements in Industrial Monorepos

A six-part series on why industrial monorepos fail and how to fix them. Most 50-project .NET solutions grew organically -- ServiceProvider god-objects mediate everything, DLLs are the only boundaries, and nobody knows which code implements which business feature. The cost is measured in developer hours, production incidents, and failed audits.

The fix is structural: two new projects (.Requirements and .Specifications) that create compiler-enforced logical boundaries. Features become types. Acceptance criteria become abstract methods. The compiler refuses to build until every AC is specified, implemented, and tested. Migration is incremental -- one feature per sprint, no big-bang rewrite.


Table of Contents

Part 1: The Industrial Monorepo Nobody Planned

How a 50-project .NET solution grows organically over a decade. The ServiceProvider god-object. The 400-file grab bag. The new developer who asks "which code implements order processing?" and gets no answer. The dependency graph nobody drew.

Part 2: Physical Boundaries Are Not Architecture

DLLs are packaging, not design. Namespaces are naming, not access control. The two ServiceProvider anti-patterns dissected with full implementations and sequence diagrams. The contracts grab-bag. The testing illusion (95% code coverage, 0% requirement coverage). What's missing: logical boundaries.

Part 3: Requirements and Specifications ARE Projects

The core thesis -- the longest post. Two new projects create typed boundaries. OrderProcessingFeature with 8 ACs spanning 5 services. Complete specification interfaces, implementations, tests, and generated artifacts. The validator bridge. The CI pipeline. The structured dependency graph -- after.

Part 4: What Changes at 50+ Projects

The AC cascade: add one abstract method, the build breaks across 5 teams until everyone implements and tests it. Feature traceability across 15+ projects in 1 second (not 2.5 hours). The compiler as cross-team coordination mechanism. Scaling characteristics: build time, memory, IDE responsiveness.

Part 5: Migration -- One Feature at a Time

Space migration: project by project. Time migration: feature by feature. The hybrid Program.cs with old ServiceProvider and new typed chain coexisting. The adapter pattern for legacy code. Sprint-by-sprint roadmap from 100% ServiceLocator to 0%. Common challenges and solutions.

Part 6: ROI and Maintenance Costs

The business case. Cost of the status quo: $740K--$2.4M per year in developer waste, defects, and compliance. Cost of migration: $112K one-time. Payback period: 2 months. 3-year ROI: 500%--1900%. Metric trends: defect density, onboarding ramp, build time, AC coverage.

Part 7: Inverted Dependencies -- Production-Clean Requirement Tracking

Invert the dependency direction: production artifacts have zero knowledge of requirements. Requirements references production via typeof()/nameof() and InternalsVisibleTo. Fluent builder mappings, Roslyn analyzer in inverted mode, drift detection, cross-repo tracking, and the decision guide for choosing between original and inverted approaches.


How to Read This Series

Architects and tech leads should read all seven parts in order. Part 3 is the core design; Part 6 is the business case; Part 7 is the advanced variant for sensitive environments.

Senior developers should start with Part 1--2 (the problem), then Part 3 (the solution), then Part 5 (migration) for practical adoption. Read Part 7 if production DLL cleanliness matters.

Engineering managers should read Part 1 (the problem in business terms), Part 4 (multi-team coordination), Part 6 (ROI and costs), and Part 7 Section 14 (security implications).

QA engineers should focus on Part 3 (the traceability matrix, [Verifies] attributes, compiler diagnostics), Part 6 (coverage metrics), and Part 7 Section 7 (test mapping in inverted mode).


Prerequisites

  • Familiarity with C# / .NET and large-scale solution architecture
  • Experience with dependency injection (Microsoft.Extensions.DependencyInjection)
  • Understanding of the ServiceLocator anti-pattern (the series explains it, but recognition helps)
  • The Requirements as Code post provides the foundational design this series scales

Key Concepts

Concept Meaning
Physical boundary DLL, project, folder, namespace -- answers "where does this code live?"
Logical boundary Feature type, specification interface -- answers "what does this code implement?"
AC Cascade Adding an acceptance criterion breaks the build across all implementing projects
ServiceLocator The god-object anti-pattern where every class resolves dependencies at runtime
Specification interface A typed contract that the compiler enforces -- replaces ServiceLocator as the mediation layer
Traceability matrix Source-generated mapping from requirement to spec to implementation to test

Nothing in this series is hypothetical. The architecture is designed for -- and stress-tested against -- the kind of 50-project, 15-team monorepo that exists in every enterprise. The compiler doesn't care how big the monorepo is. It cares whether the types are satisfied.