Design patterns·topic 3 of 10
Wiring: injection, containers and lifetimes
Somewhere a decision gets made about which concrete thing your code actually gets, and the whole testability of a codebase turns on where that somewhere is. This is the vocabulary of moving it out of the class and into one place.
Read in order · tick what you already know
- 01
the class constructs its own collaborator inside a method, so testing it means standing up the real thing.
Hard-coded dependency
- 02
you stopped writing the loop and started writing the thing the framework calls, and you no longer decide when.
Inversion of control
- 03
you register your code and something else decides when it runs, which is the opposite of how a library feels.
Hollywood principle
- 04
the class asks for what it needs in its constructor and never goes looking, so a test can hand it anything.
Dependency injection
- 05
you cannot create the object without giving it what it needs, so there is no moment where it exists half-wired.
Constructor injection
- 06
the object is constructed first and wired afterwards, so there is a window where calling it throws a null reference.
Setter injection
- 07
there is exactly one file that knows every concrete class, and it is the one that runs at startup.
Composition root
- 08
one request for the top-level object built nineteen things underneath it, and you only asked for one.
Object graph
- 09
the wiring is forty lines of ordinary constructor calls at startup, and you can step through every one of them.
Pure dependency injection
- 10
you registered an interface against a class once, and everything that needs it gets one without anybody passing it.
Dependency injection container
- 11
nothing in the code says where the implementation came from, and the answer is that a scan found exactly one.
Autowiring
- 12
you put the file in the expected folder with the expected name and it was picked up, with nothing declaring it.
Convention over configuration
- 13
the same registration served one shared instance in one place and a new one per request in another, and that was configuration.
Lifetime scope
- 14
a long-lived object held a per-request one, and every request after the first got the first request's data.
Captive dependency
- 15
the class asks a global object for what it needs mid-method, so its dependencies are invisible until it runs.
Service locator
- 16
the code called a static Current property for the clock or the user, and nothing in the signature admitted it.
Ambient context
- 17
which implementation runs was decided when the program started, from a config value, not when it was compiled.
Late binding