You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.rst
+37-16Lines changed: 37 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -57,14 +57,25 @@ It helps implementing the dependency injection principle.
57
57
What is dependency injection?
58
58
-----------------------------
59
59
60
-
Dependency injection is a principle that helps to decrease coupling and increase cohesion. Your
61
-
code becomes more flexible, clear and it is easier to test it.
60
+
Dependency injection is a principle that helps to decrease coupling and increase cohesion.
61
+
62
+
What is coupling and cohesion?
63
+
64
+
Coupling and cohesion are about how tough the components are tied.
65
+
66
+
- **High coupling**. If the coupling is high it's like using a superglue or welding. No easy way
67
+
to disassemble.
68
+
- **High cohesion**. High cohesion is like using the screws. Very easy to disassemble and
69
+
assemble back or assemble a different way. It is an alternative to high coupling.
70
+
71
+
When the cohesion is high the coupling is low.
72
+
73
+
High cohesion brings the flexibility. Your code becomes easier to change and test.
62
74
63
75
How to implement dependency injection?
64
76
--------------------------------------
65
77
66
-
Objects do not create each other anymore. They provide a way to inject the needed dependencies
67
-
instead.
78
+
Objects do not create each other anymore. They provide a way to inject the dependencies instead.
68
79
69
80
Before:
70
81
@@ -76,14 +87,14 @@ Before:
76
87
classApiClient:
77
88
78
89
def__init__(self):
79
-
self.api_key = os.getenv('API_KEY')
80
-
self.timeout = os.getenv('TIMEOUT')
90
+
self.api_key = os.getenv('API_KEY')# <-- the dependency
91
+
self.timeout = os.getenv('TIMEOUT')# <-- the dependency
81
92
82
93
83
94
classService:
84
95
85
96
def__init__(self):
86
-
self.api_client = ApiClient()
97
+
self.api_client = ApiClient()# <-- the dependency
87
98
88
99
89
100
if__name__=='__main__':
@@ -100,28 +111,36 @@ After:
100
111
classApiClient:
101
112
102
113
def__init__(self, api_key: str, timeout: int):
103
-
self.api_key = api_key
104
-
self.timeout = timeout
114
+
self.api_key = api_key# <-- the dependency is injected
115
+
self.timeout = timeout# <-- the dependency is injected
105
116
106
117
107
118
classService:
108
119
109
120
def__init__(self, api_client: ApiClient):
110
-
self.api_client = api_client
121
+
self.api_client = api_client# <-- the dependency is injected
111
122
112
123
113
124
if__name__=='__main__':
114
125
service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
115
126
116
127
117
-
Flexibility comes with a price: now you need to assemble your objects like this
128
+
``ApiClient`` is decoupled from knowing where the options come from. You can read a key and a
129
+
timeout from a configuration file or even get them from a database.
130
+
131
+
``Service`` is decoupled from the ``ApiClient``. It does not create it anymore. You can provide a
132
+
stub or other compatible object.
133
+
134
+
Flexibility comes with a price.
135
+
136
+
Now you need to assemble your objects like this
118
137
``Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))``. The assembly code might get
119
138
duplicated and it'll become harder to change the application structure.
120
139
121
140
What does Dependency Injector do?
122
141
---------------------------------
123
142
124
-
``Dependency Injector`` helps you assemble the objects.
143
+
``Dependency Injector`` helps to assemble the objects.
125
144
126
145
It provides you the container and the providers that help you describe objects assembly. When you
127
146
need an object you get it from the container. The rest of the assembly work is done by the
@@ -170,8 +189,11 @@ framework:
170
189
171
190
Retrieving of the ``Service`` instance now is done like this ``container.service()``.
172
191
173
-
Also ``Dependency Injector`` provides a bonus in overriding any of the providers with the
174
-
``.override()`` method:
192
+
The responsibility of assembling the object is consolidated in the container. When you need to
193
+
make a change you do it in one place.
194
+
195
+
When doing the testing you call the ``container.api_client.override()`` to replace the real API
196
+
client with a mock:
175
197
176
198
.. code-block:: python
177
199
@@ -180,7 +202,6 @@ Also ``Dependency Injector`` provides a bonus in overriding any of the providers
180
202
181
203
with container.api_client.override(mock.Mock()):
182
204
service = container.service()
183
-
assertisinstance(service.api_client, mock.Mock)
184
205
185
206
It helps in a testing. Also you can use it for configuring project for the different environments:
186
207
replace an API client with a stub on the dev or stage.
@@ -217,7 +238,7 @@ Concept
217
238
- Explicit is better than implicit (PEP20).
218
239
- Do no magic to your code.
219
240
220
-
How does it different from the other frameworks?
241
+
How is it different from the other frameworks?
221
242
222
243
- **No autowiring.** The framework does NOT do any autowiring / autoresolving of the dependencies. You need to specify everything explicitly. Because *"Explicit is better than implicit" (PEP20)*.
223
244
- **Does not pollute your code.** Your application does NOT know and does NOT depend on the framework. No ``@inject`` decorators, annotations, patching or any other magic tricks.
0 commit comments