Skip to content

Commit 8b95579

Browse files
committed
html update for david stuff
1 parent d141c3c commit 8b95579

28 files changed

Lines changed: 4155 additions & 1767 deletions
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<title>cosmic_python</title>
6+
<meta charset="utf-8">
7+
<meta name="viewport" content="width=device-width, initial-scale=1">
8+
<meta name="author" content="Harry Percival and Bob Gregory">
9+
<meta name="description" content="">
10+
<meta property="og:title" content="cosmic_python" />
11+
<meta property="og:type" content="website" />
12+
<meta property="og:url" content="https://www.cosmicpython.com/blog/2019-04-15-inversion-of-control.html" />
13+
<meta property="og:image" content="https://www.cosmicpython.com/images/lobster_nebula.jpg" />
14+
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
15+
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.css">
16+
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/milligram/1.3.0/milligram.css">
17+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pygments-css@1.0.0/friendly.css">
18+
<link rel="stylesheet" href="/styles.css">
19+
20+
</head>
21+
22+
<body>
23+
<main class="wrapper">
24+
25+
<nav class="navigation">
26+
<section class="container">
27+
<a class="navigation-title" href="/">
28+
<h1 class="title">Cosmic Python</h1>
29+
</a>
30+
</section>
31+
</nav>
32+
33+
<section class="container">
34+
35+
<h1> What is Inversion of Control and Why Does it Matter?</h1>
36+
<p>by David, 2019-04-15</p>
37+
38+
39+
<div class="row">
40+
<div class="column">
41+
<img src="/images/upside-down.jpg" />
42+
43+
</div>
44+
</div>
45+
46+
47+
<div class="content">
48+
<p>When I first learned to program, the code I wrote all followed a particular pattern: I wrote instructions to the computer
49+
that it would execute, one by one. If I wanted to make use of utilities written elsewhere, such as in a third party library,
50+
I would call those utilities directly from my code. Code like this could be described as employing the &lsquo;traditional flow of control&rsquo;.
51+
Perhaps it&rsquo;s just my bias, but this still seems to me to be the <em>obvious</em> way to program.</p>
52+
<p>Despite this, there is a wider context that the majority of the code I write today runs in; a context where <em>control is being inverted</em>.
53+
This is because I&rsquo;m usually using some kind of framework, which is passing control to my code, despite having no direct dependency on it.
54+
Rather than my code calling the more generic code, the framework allows me to plug in custom behaviour.
55+
Systems designed like this are using what is known as <em><a href="https://en.wikipedia.org/wiki/Inversion_of_control">Inversion of Control</a></em>
56+
(IoC for short).</p>
57+
<p>This situation can be depicted like so: the generic framework providing points where the custom code can insert its behaviour.</p>
58+
<p><img src="/images/why-di/framework-plugins.png" alt="Framework with custom behaviours plugged in" /></p>
59+
<p>Even though many of us are familiar with coding in the context of such a framework, we tend to be reticent to apply the
60+
same ideas in the software that <em>we</em> design. Indeed, it may seem a bizarre or even impossible thing to do. It is certainly
61+
not the &lsquo;obvious&rsquo; way to program.</p>
62+
<p>But IoC need not be limited to frameworks &mdash; on the contrary, it is a particularly useful tool in a programmer&rsquo;s belt.
63+
For more complex systems, it&rsquo;s one of the best ways to avoid our code getting into a mess. Let me tell you why.</p>
64+
<h1>Striving for modularity</h1>
65+
<p>Software gets complicated easily. Every programmer has experienced tangled, difficult-to-work with code.
66+
Here&rsquo;s a diagram of such a system:</p>
67+
<p><img src="/images/why-di/big.png" alt="A single complicated system" /></p>
68+
<p>Perhaps not such a helpful diagram, but some systems can feel like this to work with: a forbidding mass
69+
of code that feels impossible to wrap one&rsquo;s head around.</p>
70+
<p>A common approach to tackling such complexity is to break up the system into smaller, more manageable parts.
71+
By separating it into simpler subsystems, the aim is to reduce complexity and allow us to think more clearly
72+
about each one in turn.</p>
73+
<p><img src="/images/why-di/modular.png" alt="A system composed of small simple modules" /></p>
74+
<p>We call this quality of a system its <em>modularity</em>, and we can refer to these subsystems as <em>modules</em>.</p>
75+
<h1>Separation of concerns</h1>
76+
<p>Most of us recognise the value of modularity, and put effort into organising our code into smaller parts. We have to
77+
decide what goes into which part, and the way we do this is by the <em>separation of concerns</em>.</p>
78+
<p>This separation can take different forms. We might organize things by feature area
79+
(the authentication system, the shopping cart, the blog) or by level of detail
80+
(the user interface, the business logic, the database), or both.</p>
81+
<p>When we do this, we tend to be aiming at modularity. Except for some reason, the system remains complicated.
82+
In practice, working on one module needs to ask questions of another part of the system,
83+
which calls another, which calls back to the original one. Soon our heads hurt and we need to have
84+
a lie down. What&rsquo;s going wrong?</p>
85+
<h2>Separation of concerns is not enough</h2>
86+
<p>The sad fact is, if the only organizing factor of code is separation of concerns, a system will not be
87+
modular after all. Instead, separate parts will tangle together.</p>
88+
<p>Pretty quickly, our efforts to organise what goes into each module are undermined by the <em>relationships between those
89+
modules</em>.</p>
90+
<p>This is naturally what happens to software if you don&rsquo;t think about relationships. This is because in the real world
91+
things <em>are</em> a messy, interconnected web. As we build functionality, we realise that one module needs to know about
92+
another. Later on, that other module needs to know about the first. Soon, everything knows about everything else.</p>
93+
<p><img src="/images/why-di/complicated-modular.png" alt="A complicated system with lots of arrows between the modules" /></p>
94+
<p>The problem with software like this is that, because of the web of relationships, it is not a collection of smaller
95+
subsystems. Instead, it is a single, large system - and large systems tend to be more complicated than smaller ones.</p>
96+
<h1>Improving modularity through decoupling</h1>
97+
<p>The crucial problem here is that the modules, while appearing separate, are <em>tightly coupled</em> by their dependencies
98+
upon one other. Let&rsquo;s take two modules as an example:</p>
99+
<p><img src="/images/why-di/a-b-cycle.png" alt="Arrows pointing in both directions between A and B" /></p>
100+
<p>In this diagram we see that <code>A</code> depends on <code>B</code>, but <code>B</code> also depends upon <code>A</code>. It&rsquo;s a
101+
circular dependency. As a result, these two modules are in fact no less complicated than a single module.
102+
How can we improve things?</p>
103+
<h2>Removing cycles by inverting control</h2>
104+
<p>There are a few ways to tackle a circular dependency. You may be able to extract a shared dependency into a separate
105+
module, that the other two modules depend on. You may be able to create an extra module that coordinates the two modules,
106+
instead of them calling each other. Or you can use inversion of control.</p>
107+
<p>At the moment, each module calls each other. We can pick one of the calls (let&rsquo;s say <code>A</code>&lsquo;s call to <code>B</code>) and invert
108+
control so that <code>A</code> no longer needs to know anything about <code>B</code>. Instead, it exposes a way of plugging into its
109+
behaviour, that <code>B</code> can then exploit. This can be diagrammed like so:</p>
110+
<p><img src="/images/why-di/plugin.png" alt="B plugging into A" /></p>
111+
<p>Now that <code>A</code> has no specific knowledge of <code>B</code>, we think about <code>A</code> in isolation. We&rsquo;ve just reduced our mental overhead,
112+
and made the system more modular.</p>
113+
<p>The tactic remains useful for larger groups of modules. For example, three modules may depend upon each other, in
114+
a cycle:</p>
115+
<p><img src="/images/why-di/abc_cycle.png" alt="Arrows pointing from A to B to C, and back to A" /></p>
116+
<p>In this case, we can invert one of the dependencies, gaining us a single direction of flow:</p>
117+
<p><img src="/images/why-di/plugin-3.png" alt="B plugging into A" /></p>
118+
<p>Again, inversion of control has come to the rescue.</p>
119+
<h1>Inversion of control in practice</h1>
120+
<p>In practice, inverting control can sometimes feel impossible. Surely, if a module needs to call another, there is no way
121+
to reverse this merely by refactoring? But I have good news. You should <em>always</em> be able to avoid circular dependencies
122+
through some form of inversion (if you think you&rsquo;ve found an example where it isn&rsquo;t, please tell me).
123+
It&rsquo;s not always the most obvious way to write code, but it can make your code base significantly easier to work with.</p>
124+
<p>There are several different techniques for <em>how</em> you do this. One such technique that is often
125+
talked about is dependency injection. I will cover some of these techniques in <a href="/blog/2019-08-03-ioc-techniques.html">part two of this series</a>.</p>
126+
<p>There is also more to be said about how to apply this approach across the wider code base: if the system consists of
127+
more than a handful of files, where do we start? Again, I&rsquo;ll cover this later in the series.</p>
128+
<h1>Conclusion: complex is better than complicated</h1>
129+
<p>If you want to avoid your code getting into a mess, it&rsquo;s not enough merely to separate concerns. You must control the
130+
<em>relationships</em> between those concerns. In order to gain the benefits of a more modular system, you will sometimes need
131+
to use inversion of control to make control flow in the opposite direction to what comes naturally.</p>
132+
<p>The <a href="https://en.wikipedia.org/wiki/Zen_of_Python">Zen of Python</a> states:</p>
133+
<div class="codehilite"><pre><span></span><code>Simple is better than complex.
134+
</code></pre></div>
135+
136+
137+
<p>But also that</p>
138+
<div class="codehilite"><pre><span></span><code>Complex is better than complicated.
139+
</code></pre></div>
140+
141+
142+
<p>I think of inversion of control as an example of choosing the complex over the complicated. If we don&rsquo;t use it when
143+
it&rsquo;s needed, our efforts to create a simple system will tangle into complications. Inverting dependencies allows us,
144+
at the cost of a small amount of complexity, to make our systems less complicated.</p>
145+
<h1>Further information</h1>
146+
<ul>
147+
<li>Part two of this series: <a href="/blog/2019-08-03-ioc-techniques.html">Three Techniques for Inverting Control, in Python</a>.</li>
148+
</ul>
149+
</div>
150+
151+
<div id="disqus_thread" style="margin: 10px"></div>
152+
<script>
153+
154+
var disqus_config = function () {
155+
this.page.url = 'https://www.cosmicpython.com/blog/2019-04-15-inversion-of-control.html';
156+
this.page.identifier = 'cosmic-python--blog-2019-04-15-inversion-of-control';
157+
};
158+
159+
(function() { // DON'T EDIT BELOW THIS LINE
160+
var d = document, s = d.createElement('script');
161+
s.src = 'https://cosmic-python.disqus.com/embed.js';
162+
s.setAttribute('data-timestamp', +new Date());
163+
(d.head || d.body).appendChild(s);
164+
})();
165+
</script>
166+
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
167+
168+
<!-- Global site tag (gtag.js) - Google Analytics -->
169+
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-40928035-3"></script>
170+
<script>
171+
window.dataLayer = window.dataLayer || [];
172+
function gtag(){dataLayer.push(arguments);}
173+
gtag('js', new Date());
174+
175+
gtag('config', 'UA-40928035-3');
176+
</script>
177+
178+
</section>
179+
</main>
180+
</body>
181+
</html>

0 commit comments

Comments
 (0)