Skip to content

Commit d429cea

Browse files
committed
update blog and html
1 parent febc000 commit d429cea

33 files changed

+2075
-1993
lines changed

blog/2017-09-07-introducing-command-handler.html

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ <h1> Introducing Command Handler</h1>
160160
<span class="n">problem_description</span><span class="p">:</span> <span class="nb">str</span>
161161
</code></pre></div>
162162

163-
164163
<p>A command object is a small object that represents a state-changing action that
165164
can happen in the system. Commands have no behaviour, they&rsquo;re pure data
166165
structures. There&rsquo;s no reason why you have to represent them with classes, since
@@ -209,7 +208,6 @@ <h1> Introducing Command Handler</h1>
209208
<span class="bp">self</span><span class="o">.</span><span class="n">issue_log</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">issue</span><span class="p">)</span>
210209
</code></pre></div>
211210

212-
213211
<p>Command handlers are stateless objects that orchestrate the behaviour of a
214212
system. They are a kind of glue code, and manage the boring work of fetching and
215213
saving objects, and then notifying other parts of the system. In keeping with
@@ -240,7 +238,6 @@ <h1> Introducing Command Handler</h1>
240238
<span class="n">issue</span><span class="o">.</span><span class="n">mark_as_resolved</span><span class="p">(</span><span class="n">cmd</span><span class="o">.</span><span class="n">resolution</span><span class="p">)</span>
241239
</code></pre></div>
242240

243-
244241
<p>This handler violates our glue-code principle because it encodes a business
245242
rule: &ldquo;If an issue is already resolved, then it can&rsquo;t be resolved a second
246243
time&rdquo;. This rule belongs in our domain model, probably in the mark_as_resolved
@@ -258,15 +255,13 @@ <h1> Introducing Command Handler</h1>
258255
<span class="n">issue_log</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">issue</span><span class="p">)</span>
259256
</code></pre></div>
260257

261-
262258
<p>If magic methods make you feel queasy, you can define a handler to be a class
263259
that exposes a handle method like this:</p>
264260
<div class="codehilite"><pre><span></span><code><span class="k">class</span> <span class="nc">ReportIssueHandler</span><span class="p">:</span>
265261
<span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cmd</span><span class="p">):</span>
266262
<span class="o">...</span>
267263
</code></pre></div>
268264

269-
270265
<p>However you structure them, the important ideas of commands and handlers are:</p>
271266
<ol>
272267
<li>Commands are logic-free data structures with a name and a bunch of values.</li>
@@ -375,7 +370,6 @@ <h1> Introducing Command Handler</h1>
375370
<span class="n">expect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">issues</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">description</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">equal</span><span class="p">(</span><span class="n">desc</span><span class="p">))</span>
376371
</code></pre></div>
377372

378-
379373
<p>There&rsquo;s not a lot of functionality here, and our issue log has a couple of
380374
problems, firstly there&rsquo;s no way to see the issues in the log yet, and secondly
381375
we&rsquo;ll lose all of our data every time we restart the process. We&rsquo;ll fix the

blog/2017-09-08-repository-and-unit-of-work-pattern-in-python.html

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ <h1> Repository and Unit of Work Pattern</h1>
7474
<span class="n">issue_log</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">issue</span><span class="p">)</span>
7575
</code></pre></div>
7676

77-
7877
<p>The IssueLog is a term from our conversation with the domain expert. It&rsquo;s the
7978
place that they record the list of all issues. This is part of the jargon used
8079
by our customers, and so it clearly belongs in the domain, but it&rsquo;s also the
@@ -106,7 +105,6 @@ <h1> Repository and Unit of Work Pattern</h1>
106105
<span class="bp">self</span><span class="o">.</span><span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
107106
</code></pre></div>
108107

109-
110108
<p>Because we had the great foresight to use standardised ports, we can plug any
111109
number of different devices into our circuit. For example, we could attach a
112110
light-detector to the input and a buzzer to the output, or we could attach a
@@ -133,7 +131,6 @@ <h1> Repository and Unit of Work Pattern</h1>
133131
<span class="bp">self</span><span class="o">.</span><span class="n">on</span> <span class="o">=</span> <span class="kc">False</span>
134132
</code></pre></div>
135133

136-
137134
<p>Considered in isolation, this is just an example of good OO practice: we are
138135
extending our system through composition. What makes this a ports-and-adapters
139136
architecture is the idea that there is an internal world consisting of the
@@ -161,7 +158,6 @@ <h1> Repository and Unit of Work Pattern</h1>
161158
<span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
162159
</code></pre></div>
163160

164-
165161
<p>By analogy to our circuit example, the IssueLog is a WriteablePort - it&rsquo;s a way
166162
for us to get data out of the system. SqlAlchemy and the file system are two
167163
types of adapter that we can plug in, just like the Buzzer or Light classes. In
@@ -186,7 +182,6 @@ <h1> Repository and Unit of Work Pattern</h1>
186182
<span class="nb">filter</span><span class="p">(</span><span class="n">foo</span><span class="o">.</span><span class="n">latitude</span> <span class="o">==</span> <span class="n">latitude</span><span class="p">)</span>
187183
</code></pre></div>
188184

189-
190185
<p>We expose a few methods, one to add new items, one to get items by their id, and
191186
a third to find items by some criterion. This FooRepository is using a
192187
SqlAlchemy session
@@ -209,7 +204,6 @@ <h1> Repository and Unit of Work Pattern</h1>
209204
<span class="k">if</span> <span class="n">item</span><span class="o">.</span><span class="n">latitude</span> <span class="o">==</span> <span class="n">latitude</span><span class="p">)</span>
210205
</code></pre></div>
211206

212-
213207
<p>This adapter works just the same as the one backed by a real database, but does
214208
so without any external state. This allows us to test our code without resorting
215209
to Setup/Teardown scripts on our database, or monkey patching our ORM to return
@@ -267,7 +261,6 @@ <h1> Repository and Unit of Work Pattern</h1>
267261
<span class="k">return</span> <span class="n">IssueRepository</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="p">)</span>
268262
</code></pre></div>
269263

270-
271264
<p>This code is taken from a current production system - the code to implement
272265
these patterns really isn&rsquo;t complex. The only thing missing here is some logging
273266
and error handling in the commit method. Our unit-of-work manager creates a new
@@ -287,7 +280,6 @@ <h1> Repository and Unit of Work Pattern</h1>
287280
<span class="n">unit_of_work</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
288281
</code></pre></div>
289282

290-
291283
<p>Our command handler looks more or less the same, except that it&rsquo;s now
292284
responsible for starting a unit-of-work, and committing the unit-of-work when it
293285
has finished. This is in keeping with our rule #1 - we will clearly define the
@@ -341,7 +333,6 @@ <h1> Repository and Unit of Work Pattern</h1>
341333
<span class="n">expect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">uow</span><span class="o">.</span><span class="n">was_committed</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">be_true</span><span class="p">)</span>
342334
</code></pre></div>
343335

344-
345336
<p>Next time [https://io.made.com/blog/commands-and-queries-handlers-and-views]
346337
we&rsquo;ll look at how to get data back out of the system.</p>
347338
</div>

blog/2017-09-13-commands-and-queries-handlers-and-views.html

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ <h3>What is CQS ?</h3>
8787
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">light_is_on</span>
8888
</code></pre></div>
8989

90-
9190
<p>In this class, the is_on method is referentially transparent - I can replace it
9291
with the value True or False without any loss of functionality, but the method
9392
toggle_light is side-effectual: replacing its calls with a static value would
@@ -116,7 +115,6 @@ <h3>What is CQS ?</h3>
116115
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">open_issues</span><span class="p">)</span>
117116
</code></pre></div>
118117

119-
120118
<p>This is totally fine unless you have complex formatting, or multiple entrypoints
121119
to your system. The problem with using your repositories directly in this way is
122120
that it&rsquo;s a slippery slope. Sooner or later you&rsquo;re going to have a tight
@@ -130,7 +128,6 @@ <h3>What is CQS ?</h3>
130128
<span class="n">uow</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
131129
</code></pre></div>
132130

133-
134131
<p>Super convenient, but then you need to add some error handling and some logging
135132
and an email notification.</p>
136133
<div class="codehilite"><pre><span></span><code><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">&#39;/issues/&lt;issue_id&gt;&#39;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;DELETE&#39;</span><span class="p">])</span>
@@ -157,7 +154,6 @@ <h3>What is CQS ?</h3>
157154
<span class="k">return</span> <span class="s2">&quot;Deleted!&quot;</span><span class="p">,</span> <span class="mi">202</span>
158155
</code></pre></div>
159156

160-
161157
<p>Aaaaand, we&rsquo;re back to where we started: business logic mixed with glue code,
162158
and the whole mess slowly congealing in our web controllers. Of course, the
163159
slippery slope argument isn&rsquo;t a good reason not to do something, so if your
@@ -185,7 +181,6 @@ <h3>What is CQS ?</h3>
185181
<span class="k">return</span> <span class="n">jsonify</span><span class="p">(</span><span class="n">view_builder</span><span class="o">.</span><span class="n">fetch</span><span class="p">())</span>
186182
</code></pre></div>
187183

188-
189184
<p>This is my favourite part of teaching ports and adapters to junior programmers,
190185
because the conversation inevitably goes like this:</p>
191186
<blockquote>
@@ -225,7 +220,6 @@ <h3>Why have a separate read-model?</h3>
225220
<span class="n">assignee</span><span class="o">.</span><span class="n">queues</span><span class="o">.</span><span class="n">inbox</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
226221
</code></pre></div>
227222

228-
229223
<p>ORMs make it very easy to &ldquo;dot&rdquo; through the object model this way, and pretend
230224
that we have our data in memory, but this quickly leads to performance issues
231225
when the ORM generates hundreds of select statements in response. Then they get
@@ -310,7 +304,6 @@ <h3>Application Controlled Identifiers</h3>
310304
<span class="k">return</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="mi">201</span><span class="p">,</span> <span class="p">{</span> <span class="s1">&#39;Location&#39;</span><span class="p">:</span> <span class="s1">&#39;/issues/&#39;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">issue_id</span><span class="p">)</span> <span class="p">}</span>
311305
</code></pre></div>
312306

313-
314307
<p>There&rsquo;s a few ways to do this, the most common is just to use a UUID, but you
315308
can also implement something like
316309
<a href="https://pypi.python.org/pypi/sqlalchemy-hilo/0.1.2">hi-lo</a>.

blog/2017-09-19-why-use-domain-events.html

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ <h2>Mapping our requirements to our domain</h2>
145145
<span class="n">expect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">state</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">equal</span><span class="p">(</span><span class="n">IssueState</span><span class="o">.</span><span class="n">AwaitingTriage</span><span class="p">))</span>
146146
</code></pre></div>
147147

148-
149148
<p>We&rsquo;re introducing a new concept - Issues now have a state, and a newly reported
150149
issue begins in the AwaitingTriage state. We can quickly add a command and
151150
handler that allows us to triage an issue.</p>
@@ -161,7 +160,6 @@ <h2>Mapping our requirements to our domain</h2>
161160
<span class="n">uow</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
162161
</code></pre></div>
163162

164-
165163
<p>Triaging an issue, for now, is a matter of selecting a category and priority.
166164
We&rsquo;ll use a free string for category, and an enumeration for Priority. Once an
167165
issue is triaged, it enters the AwaitingAssignment state. At some point we&rsquo;ll
@@ -180,7 +178,6 @@ <h2>Mapping our requirements to our domain</h2>
180178
<span class="n">uow</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
181179
</code></pre></div>
182180

183-
184181
<p>At this point, the handlers are becoming a little boring. As I said way back in
185182
the first part [https://io.made.com/blog/introducing-command-handler/], commands
186183
handlers are supposed to be boring glue-code, and every command handler has the
@@ -225,7 +222,6 @@ <h2>Mapping our requirements to our domain</h2>
225222
<span class="bp">self</span><span class="o">.</span><span class="n">email_sender</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">email</span><span class="p">)</span>
226223
</code></pre></div>
227224

228-
229225
<p>Something here feels wrong, right? Our command-handler now has two very distinct
230226
responsibilities. Back at the beginning of this series we said we would stick
231227
with three principles:</p>
@@ -290,7 +286,6 @@ <h2>Mapping our requirements to our domain</h2>
290286
<span class="bp">self</span><span class="o">.</span><span class="n">email_sender</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">email</span><span class="p">)</span>
291287
</code></pre></div>
292288

293-
294289
<p>We don&rsquo;t really need a unit of work here, because we&rsquo;re not making any
295290
persistent changes to the Issue state, so what if we use a view builder instead?</p>
296291
<div class="codehilite"><pre><span></span><code><span class="k">class</span> <span class="nc">SendAssignmentEmailHandler</span>
@@ -312,7 +307,6 @@ <h2>Mapping our requirements to our domain</h2>
312307
<span class="bp">self</span><span class="o">.</span><span class="n">email_sender</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">email</span><span class="p">)</span>
313308
</code></pre></div>
314309

315-
316310
<p>That seems better, but how should we invoke our new handler? Building a new
317311
command and handler from inside our AssignIssueHandler also sounds like a
318312
violation of SRP. Worse still, if we start calling handlers from handlers, we&rsquo;ll
@@ -386,7 +380,6 @@ <h2>Mapping our requirements to our domain</h2>
386380
<span class="n">bus</span><span class="o">.</span><span class="n">handle</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
387381
</code></pre></div>
388382

389-
390383
<p>Here we have a bare-bones implementation of a message bus. It doesn&rsquo;t do
391384
anything fancy, but it will do the job for now. In a production system, the
392385
message bus is an excellent place to put cross-cutting concerns; for example, we
@@ -404,7 +397,6 @@ <h2>Mapping our requirements to our domain</h2>
404397
<span class="k">return</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="mi">201</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;Location&quot;</span><span class="p">:</span> <span class="s2">&quot;/issues/&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">issue_id</span><span class="p">)</span> <span class="p">}</span>
405398
</code></pre></div>
406399

407-
408400
<p>Not much has changed here - we&rsquo;re still building our command in the Flask
409401
adapter, but now we&rsquo;re passing it into a bus instead of directly constructing a
410402
handler for ourselves. What about when we need to raise an event? We&rsquo;ve got
@@ -425,7 +417,6 @@ <h2>Mapping our requirements to our domain</h2>
425417
<span class="n">cmd</span><span class="o">.</span><span class="n">assigned_by</span><span class="p">))</span>
426418
</code></pre></div>
427419

428-
429420
<p>I usually think of this event-raising as a kind of glue - it&rsquo;s orchestration
430421
code. Raising events from your handlers this way makes the flow of messages
431422
explicit - you don&rsquo;t have to look anywhere else in the system to understand
@@ -445,7 +436,6 @@ <h2>Mapping our requirements to our domain</h2>
445436
<span class="bp">self</span><span class="o">.</span><span class="n">events</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">IssueAssignedToEngineer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">assigned_to</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">assigned_by</span><span class="p">))</span>
446437
</code></pre></div>
447438

448-
449439
<p>There&rsquo;s a couple of benefits of doing this: firstly, it keeps our command
450440
handler simpler, but secondly it pushes the logic for deciding when to send an
451441
event into the model. For example, maybe we don&rsquo;t always need to raise the
@@ -461,7 +451,6 @@ <h2>Mapping our requirements to our domain</h2>
461451
<span class="bp">self</span><span class="o">.</span><span class="n">events</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">IssueAssignedToEngineer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">assigned_to</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">assigned_by</span><span class="p">))</span>
462452
</code></pre></div>
463453

464-
465454
<p>Now we&rsquo;ll only raise our event if the issue was assigned by another engineer.
466455
Cases like this are more like business logic than glue code, so today I&rsquo;m
467456
choosing to put them in my domain model. Updating our unit tests is trivial,
@@ -485,7 +474,6 @@ <h2>Mapping our requirements to our domain</h2>
485474
<span class="bp">self</span><span class="o">.</span><span class="n">assigned_by</span><span class="p">)))</span>
486475
</code></pre></div>
487476

488-
489477
<p>The have_raised function is a custom matcher I wrote that checks the events
490478
attribute of our object to see if we raised the correct event. It&rsquo;s easy to test
491479
for the presence of events, because they&rsquo;re namedtuples, and have value
@@ -540,7 +528,6 @@ <h2>Mapping our requirements to our domain</h2>
540528
<span class="bp">self</span><span class="o">.</span><span class="n">publish_events</span><span class="p">()</span>
541529
</code></pre></div>
542530

543-
544531
<p>Okay, we&rsquo;ve covered a lot of ground here. We&rsquo;ve discussed why you might want to
545532
use domain events, how a message bus actually works in practice, and how we can
546533
get events out of our domain and into our subscribers. The newest code sample

blog/2019-04-15-inversion-of-control.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,10 @@ <h1>Conclusion: complex is better than complicated</h1>
140140
<div class="codehilite"><pre><span></span><code>Simple is better than complex.
141141
</code></pre></div>
142142

143-
144143
<p>But also that</p>
145144
<div class="codehilite"><pre><span></span><code>Complex is better than complicated.
146145
</code></pre></div>
147146

148-
149147
<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
150148
it&rsquo;s needed, our efforts to create a simple system will tangle into complications. Inverting dependencies allows us,
151149
at the cost of a small amount of complexity, to make our systems less complicated.</p>

0 commit comments

Comments
 (0)