Skip to content

docs: teach the composition root and DI anti-patterns#97

Merged
vbreuss merged 4 commits into
mainfrom
docs/principles-composition-root
Jul 8, 2026
Merged

docs: teach the composition root and DI anti-patterns#97
vbreuss merged 4 commits into
mainfrom
docs/principles-composition-root

Conversation

@vbreuss

@vbreuss vbreuss commented Jul 8, 2026

Copy link
Copy Markdown
Member

Add Docs/pages/02-principles.md, a design-focused page that sits after getting-started. The feature pages teach the mechanics Awaiten enforces (lifetimes, cycles, async); this page teaches the design those mechanics serve, which no tool can enforce. It covers what DI is really for, the composition root and the domain-must-not-reference-Awaiten rule, volatile vs. stable dependencies with a decision rule, the four anti-patterns (Control Freak, Service Locator, Ambient Context, Constrained Construction) each with an "In Awaiten" note, keeping DI out of the domain via the container-side idioms, and when a powerful feature is smoothing over a design that wants to be split.

Reflect the current attribute surface rather than the original issue text: [FromServices] is gone in favor of the container-side [ImportService], so the escape hatches are the three consumer-side attributes [Arg], [FromKey], and [Inject]. The Service Locator note states the rule and frames boundary enforcement as a recommended architecture test, since the analyzer for it is not shipped.

Link the page from the docs index and the README, and add a "When not to reach for this" caution to keyed-services, scanning, property-injection, and context-aware-factories, each pointing back to the principles page.

@vbreuss vbreuss self-assigned this Jul 8, 2026
@vbreuss vbreuss added the documentation Improvements or additions to documentation label Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

Test Results

   18 files  ±0     18 suites  ±0   7m 11s ⏱️ - 1m 5s
1 038 tests ±0  1 037 ✅ ±0  1 💤 ±0  0 ❌ ±0 
5 160 runs  ±0  5 159 ✅ ±0  1 💤 ±0  0 ❌ ±0 

Results for commit 015257c. ± Comparison against base commit d312537.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

👽 Mutation Results

Mutation testing badge

Awaiten

Details
File Score Killed Survived Timeout No Coverage Ignored Compile Errors Runtime Errors Total Detected Total Undetected Total Mutants

The final mutation score is NaN%

Coverage Thresholds: high:80 low:60 break:0

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

🚀 Benchmark Results

Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.301
[Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Resolve Size Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 8 7.802 ns 0.0062 ns 0.0049 ns 1.00 - NA
Awaiten 8 7.818 ns 0.0989 ns 0.0877 ns 1.00 - NA
MsDI 8 10.964 ns 0.0090 ns 0.0084 ns 1.40 - NA
Autofac 8 117.382 ns 0.9147 ns 0.8556 ns 15.02 656 B NA
Jab 8 3.146 ns 0.1041 ns 0.0869 ns 0.40 - NA
PureDI 8 5.115 ns 0.0142 ns 0.0119 ns 0.65 - NA
DryIoc 8 8.599 ns 0.1924 ns 0.1800 ns 1.10 - NA
SimpleInjector 8 10.578 ns 0.0380 ns 0.0336 ns 1.35 - NA
baseline* 256 8.442 ns 0.0063 ns 0.0053 ns 0.94 - NA
Awaiten 256 8.995 ns 0.1514 ns 0.1416 ns 1.00 - NA
MsDI 256 8.354 ns 0.0300 ns 0.0266 ns 0.93 - NA
Autofac 256 111.700 ns 1.6755 ns 1.5672 ns 12.42 656 B NA
Jab 256 46.941 ns 0.0230 ns 0.0204 ns 5.22 - NA
PureDI 256 7.938 ns 0.0149 ns 0.0124 ns 0.88 - NA
DryIoc 256 8.720 ns 0.1877 ns 0.1568 ns 0.97 - NA
SimpleInjector 256 14.425 ns 0.1261 ns 0.1179 ns 1.60 - NA
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.301
[Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Realistic Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 248.6 ns 2.64 ns 2.47 ns 0.97 568 B 1.00
Awaiten 256.3 ns 8.31 ns 7.77 ns 1.00 568 B 1.00
MsDI 636.4 ns 13.18 ns 11.68 ns 2.48 1104 B 1.94
Autofac 8,560.7 ns 78.57 ns 69.65 ns 33.43 13696 B 24.11
Jab 187.6 ns 3.01 ns 2.81 ns 0.73 432 B 0.76
DryIoc 423.1 ns 8.45 ns 7.91 ns 1.65 944 B 1.66
SimpleInjector 753.3 ns 5.99 ns 5.60 ns 2.94 1096 B 1.93
PureDI 191.9 ns 7.53 ns 7.04 ns 0.75 632 B 1.11
Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 7763 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.301
[Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Build Size Mean Error StdDev Ratio Allocated Alloc Ratio
baseline* 8 18.459 ns 0.8885 ns 0.8311 ns 1.11 144 B 1.00
Awaiten 8 16.61 ns 0.124 ns 0.110 ns 1.00 144 B 1.00
MsDI 8 1,452.39 ns 19.422 ns 18.167 ns 87.45 5688 B 39.50
Autofac 8 31,007.55 ns 196.272 ns 173.990 ns 1,867.01 33098 B 229.85
Jab 8 11.57 ns 0.833 ns 0.738 ns 0.70 96 B 0.67
PureDI 8 15.22 ns 0.454 ns 0.425 ns 0.92 128 B 0.89
DryIoc 8 687.92 ns 7.635 ns 5.961 ns 41.42 1528 B 10.61
SimpleInjector 8 11,907.31 ns 222.832 ns 208.437 ns 716.95 24760 B 171.94
baseline* 256 94.116 ns 1.4229 ns 1.3310 ns 1.02 2128 B 1.00
Awaiten 256 92.06 ns 2.351 ns 1.963 ns 1.00 2128 B 1.00
MsDI 256 14,663.12 ns 539.683 ns 504.820 ns 159.35 61016 B 28.67
Autofac 256 765,975.07 ns 10,894.793 ns 9,097.645 ns 8,324.09 740935 B 348.18
Jab 256 87.25 ns 2.290 ns 2.142 ns 0.95 2080 B 0.98
PureDI 256 88.26 ns 0.879 ns 0.779 ns 0.96 2112 B 0.99
DryIoc 256 43,027.13 ns 762.196 ns 712.958 ns 467.59 80679 B 37.91
SimpleInjector 256 351,069.05 ns 4,358.474 ns 4,076.919 ns 3,815.18 573110 B 269.32

baseline* rows show the corresponding Awaiten benchmark from the most recent successful main branch build with results, for regression comparison.

vbreuss added 2 commits July 8, 2026 17:57
Add Docs/pages/02-principles.md, a design-focused page that sits after getting-started. The feature pages teach the mechanics Awaiten enforces (lifetimes, cycles, async); this page teaches the design those mechanics serve, which no tool can enforce. It covers what DI is really for, the composition root and the domain-must-not-reference-Awaiten rule, volatile vs. stable dependencies with a decision rule, the four anti-patterns (Control Freak, Service Locator, Ambient Context, Constrained Construction) each with an "In Awaiten" note, keeping DI out of the domain via the container-side idioms, and when a powerful feature is smoothing over a design that wants to be split.

Reflect the current attribute surface rather than the original issue text: [FromServices] is gone in favor of the container-side [ImportService<T>], so the escape hatches are the three consumer-side attributes [Arg], [FromKey], and [Inject]. The Service Locator note states the rule and frames boundary enforcement as a recommended architecture test, since the analyzer for it is not shipped.

Link the page from the docs index and the README, and add a "When not to reach for this" caution to keyed-services, scanning, property-injection, and context-aware-factories, each pointing back to the principles page.
The composition-boundary and service-locator anti-patterns are now enforced by suppressible analyzer warnings, so update the two "not enforced yet" notes on the principles page. The Service Locator rule now points at AWT135 (holding a resolver in anything but the [Container]); the boundary note points at AWT134 (a composition attribute in an assembly that declares no [Container]) and keeps the architecture test as the complementary cross-assembly enforcement, since AWT134 is a best-effort in-assembly guard.
@vbreuss vbreuss force-pushed the docs/principles-composition-root branch from b061755 to 172030d Compare July 8, 2026 15:57
vbreuss added 2 commits July 8, 2026 18:32
…ystem

- attribute the four anti-patterns to van Deursen & Seemann's book and
  Seemann's blog; re-theme the examples to the coffee shop
- replace the vague 'the book' phrasing with a concrete aweXpect.Reflection
  architecture test asserting the domain carries no reference to Awaiten
- add that test to Awaiten.ExampleTests over a clean CoffeeShop domain
  (aweXpect.Reflection 2.0.0), verified red on a violation
- swap IClock for Testably's ITimeSystem throughout the doc examples
- insert principles at sidebar position 2 and shift the rest by one
- link the composition root and Pure DI posts where each concept appears
- back the opinionated claims with Fowler, Microsoft DI guidelines, and the
  dependency-inversion / explicit-dependencies principles, not just Seemann
- rewrite the four-anti-patterns intro to lead with substance over attribution
- replace all em-dashes with colons, sentence breaks, or parentheses
@vbreuss vbreuss enabled auto-merge (squash) July 8, 2026 16:45
@sonarqubecloud

sonarqubecloud Bot commented Jul 8, 2026

Copy link
Copy Markdown

@vbreuss vbreuss merged commit 6657202 into main Jul 8, 2026
15 checks passed
@vbreuss vbreuss deleted the docs/principles-composition-root branch July 8, 2026 16:47
github-actions Bot added a commit that referenced this pull request Jul 8, 2026
github-actions Bot added a commit that referenced this pull request Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

This is addressed in release v0.4.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation state: released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant