Ambient context acquires a shared dependency through static or globally accessible methods rather than explicit injection. It hides the dependency, makes changes harder, and complicates testing. section 8.6 section 11.6
Treat the pattern as a warning sign, not a convenience. If explicit injection is too awkward, reduce excessive logging or unnecessary layers of indirection instead of hiding the dependency. section 8.6
Prefer these alternatives:
- Inject a logger through a method argument or constructor. section 8.6
- Inject time explicitly as a plain value when possible; otherwise inject a service at the operation boundary and pass its value inward. section 11.6
- Move cross-cutting behavior toward domain events when direct logging creates excessive coupling. section 8.6
Static time versus explicit time
A DateTimeServer with static Now and Init methods lets production code and tests replace the clock globally. An injected IDateTimeServer instead supplies time through InquiryController, which passes the resulting DateTime value to the domain operation. section 11.6
Listing 11.16. Current date and time as an ambient context
public static class DateTimeServer
{
private static Func<DateTime> _func;
public static DateTime Now => _func();
public static void Init(Func<DateTime> func)
{
_func = func;
}
}
DateTimeServer.Init(() => DateTime.Now); #1
DateTimeServer.Init(() => new DateTime(2020, 1, 1)); #2
Compare the static clock setup with the explicit dependency version to see how shared test state becomes an injected collaborator. section 11.6
