Dependency injection is a technique in which an object receives other objects it depends on.
It is actually one form of the broader technique inversion of control.
🧵👇🏻
1⃣ What is it?
Dependency injection is a technique where every other object (service) an object (client) depends on is injected from the outside.
So instead of simply instantiating everything on its own, a class relies on it being passed in from the outside.
You can also view it this way:
Imagine your favorite RPG character could only wear the equipment they started with. No way to change the equipment or the look of your character's equipment from the outside.
Would be boring and inflexible, wouldn't it?
This is why modern RPGs let you change your character's equipment. And you can compare this to DI!
Every slot requires a certain type of equipment. And you can change your character's equipment on the fly, by dropping a new piece into a fitting slot.
The analogy/example is of course one of a mutable object, but I want you to get the general idea of what it is.
And it would be pretty bad if you had to kill your character and recreate it every time you wanted to change your main hand weapon, wouldn't it? 😉
👇🏻
2⃣ What is it good for?
In the strictest form one could possibly think of, DI helps you to respect the single responsibility principle:
A class should be good at one thing.
But knowing how to do your own job and how to create other objects are two things already!
But it does even more.
It helps you to make your code loosely coupled and to make it testable.
DI, in fact, also encourages you to use interfaces instead of specific types as injectables (services).
This means that the client only expects a certain interface to be...
...satisfied, which specific implementations can do, and then be used as services.
Dependencies become replaceable, and interchangeable, which is also a pretty great benefit of it!
👇🏻
3⃣ An example problem
To actually get an idea of the benefits, imagine the following example:
You have a service-level implementation in one of your APIs to fetch user data, and this implementation depends on a...
...user repository, which handles the database access for you.
You have already made a great first step to put the persistence logic into a repository, and use it within your service, but whenever you want to test your service you need a database. That's bad!
And what's even worse:
You can't change the way you access your user's data without changing existing code. Not good...
If you try to test this code, you'll get a lot of "fun", because you will most likely need at least an in-memory database, even for a trivial unit test.
👇🏻
4⃣ Solving the issue
By making only a small change you can decouple your client from its services!
Making this change in a statically typed language would, of course, involve a little more work, as you'd have to create an interface, make your repository implement it, etc.
But now you have a lot more flexibility.
Unit tests can now inject a mock that doesn't require any form of database anymore. This is great!
And you could now also implement a repository that doesn't use a relational database, but a NoSQL one, e.g.
• • •
Missing some Tweet in this thread? You can try to
force a refresh
Although I am not a data scientist by any means, I was recently asked what knowledge of math someone would need to be able to efficiently get into the field.
Well, I researched a little and came up with the following course track, starting with the basics.
🧵👇
Calculus 1 will cover a lot of the basics, relevant especially to optimization problems which are quite common in data science.
The Dependency Inversion Principle is a part of SOLID, a mnemonic acronym which bundles a total of 5 design principles.
It is often associated with clean code.
But what exactly is it, is it important to you, should you even care?
🧵👇
1⃣ What does it state?
It states:
Modules that encapsulate high-level policy should not depend upon modules that implement details. Rather, both kinds of modules should depend upon abstractions.
This may sound a little complicated, but you can break it up, as follows:
1. High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g., interfaces).
2. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.