It's 2019 and DI is a well-known and established technique on all major platforms and languages. So why can't we still have a clear answer to the questions like 'is DI/IoC container a mandatory thing to apply DI?' or 'what is a true way to implement DI in language/platform X?' or ‘is it even a good/useful thing?’.
Let's find those answers together and refresh our memory on the initial goals and targets of DI and its surrounding design patterns.
3. Who am I?
Dev (C#, Python) in Opsy (Docker, k8s, GCP) world
Attendee: NDC (Oslo), New Crafts (Paris)
Speaker: BuildStuff (Vilnius), XP Days & .Net Fest (Kyiv)
Religious about engineering practices and team culture,
software design and good code
Toolsmith at Unity Technologies, based in Odessa
Twitter: @k04a
Linkedin: Igor Kochetov
4. @k04a
Why we even talk about DI in 2019?
There are conflicting opinions on the
subject of DI
Is it even still relevant?
4
6. @k04a
Nice one, but there are still questions...
Who’s “we” who make sure you have
what you need?
How do we state “the need” in the code?
Why one would use it? What are the
benefits, actually?
6
7. Known benefits
Dependency Injection
❏ Reducing dependencies of
components (and implementation
details of those dependencies)
❏ Reusable code / swapping of
components
❏ More testable code
❏ More readable code (by defining
dependencies clearly)
Loose coupling
Isolated components are easier to:
❏ Modify, reuse or compose
differently
❏ Test
❏ Reason about
7
8. @k04a
It is about Dependencies...
Identifying dependencies in our
code (and types of dependencies)
Managing dependencies
8
9. @k04a
Programming to interfaces and D in SOLID
High-level modules should not depend
on low-level modules. Both should
depend on abstractions.
Abstractions should not depend on
details. Details should depend on
abstractions.
9
10. @k04a
Also related: who owns the abstractions?
Model abstractions around
domain-specific scenarios instead
of low-level implementation details
“Adapt” external dependencies to
match your domain concepts
Hexagonal architecture or
“Ports & Adapters”:
10
13. @k04a
Resolve dependencies using Service Locator
At first, looks like very good idea,
which makes it even more
dangerous.
But now we introduce new
dependency (on the container)
We also hide actual dependencies
How would you write tests for it?
13
14. @k04a
Constructor Injection is the way to go
❏ Explicitly lists
dependencies
❏ Gives clues about what
class might do
❏ Also an indicator of
possible SRP violations
14
16. Who’s “we” who make sure you have
what you need?
Or “Mommy and Daddy providing a drink”
16
17. @k04a
Many platforms provide out-of-the box DI capabilities
.NET MVC / .NET Core MVC
Spring in Java
Angular JS
Kind of making it a de-facto standard
17
18. Myth: DI is a software library or a
framework
Or at least requires one to be done properly
@k04a 18
19. @k04a
IoC Container or DI Container
Container - software library that
‘resolves dependencies’ and manages
their ‘lifetime’
❏ Simplifies wiring and reduces
maintenance
❏ Simplifies testing
❏ Allows for dynamic configuration
❏ Supports AOP
But… Is it?
19
21. @k04a
Composition Root and Pure DI
Creating all the stuff
‘normally’ in
Composition Root
(console app example)
21
22. @k04a
Is it OK to have all the components in the app root?
It is good idea to keep individual
components separated
Until we have to actually assemble
working application
22
23. @k04a
Explicit is better than implicit (Zen of Python)
Cost of writing vs cost of reading (or imagine
bringing a new member of the team into the
codebase)
Let IDE and code analysis tools be your
friends
It is actually IMPORTANT to know, what
your app does (well-structured Composition
Root serves as documentation providing
bird-eye view on high-level features and use-
cases)
23
29. @k04a
Applying SOLID to extreme pushes you toward FP
A lot of single-method
interfaces and small focused
classes (implementations)
Which is good, until you have
to write Decorators for every of
them
29
30. @k04a
CQS and Parameter Object
Single generic
abstraction
Implementation
consists of two types:
❏ Command
❏ CommandHandler
30
31. @k04a
Decorator over generic ICommandHandler
Now every ‘aspect’
becomes single
Decorator over
generic
ICommandHandler
<TCommand>
interface
31
33. @k04a
Conclusions & takeaways
Container is a dependency itself
It also might be a sign your codebase
grew too big (read “monolith”)
DI ≠ Container
DI is useful as a design pattern and
allows greater flexibility and more
manageable codebase (easier to test,
modify and reason about)
33
34. @k04a
The big idea (or what those have in common?)
❏ Dependency Injection (DI)
❏ Continuous Integration (CI) / Continuous Deployment (CD)
❏ Scrum, Lean or any Agile methodology / framework of your
choice
❏ DevOps
Answer: Those were meant to be PRACTICES (not Tools)
34