Skip to content

Commit e143f32

Browse files
committed
tweaks to post
1 parent 8927dc5 commit e143f32

File tree

3 files changed

+110
-89
lines changed

3 files changed

+110
-89
lines changed

blog/2020-08-13-so-many-layers.html

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -52,70 +52,75 @@ <h1> So Many Layers! A Note of Caution.</h1>
5252
<div class="content">
5353
<p>In the book we are at pains to point out that each pattern is a trade-off, and
5454
comes with costs. But just on the offchance that anyone was still missing the
55-
message, and thinking we were saying that all apps should be built like this,
55+
message and thinking we were saying that <em>all</em> apps should be built like this,
5656
I thought I&rsquo;d write a small blog post just to reinforce the message about
57-
costs. Each time you add a layer, you buy yourself some decoupling, but it
57+
costs.</p>
58+
<p>Each time you add a layer, you buy yourself some decoupling, but it
5859
comes at the cost of an extra moving part. In the simplest terms, there&rsquo;s an
5960
extra file you have to maintain.</p>
60-
<p><a href="https://www.cosmicpython.com/book/appendix_ds1_table.html">
61+
<p><a href="/book/appendix_ds1_table.html">
6162
<figure>
6263
<img src="/book/images/apwp_aa01.png" alt="a recap of all the layers + parts of our architecture" max-height="60%">
6364
<figcaption>Here&rsquo;s a recap of all the layers + parts of our architecture</figcaption>
6465
</figure>
6566
</a></p>
66-
<p>I remember having to make a simple change to an app that the buying team at
67-
MADE uses. We needed to record an extra piece of information for each shipment,
68-
an optional &ldquo;delay&rdquo; field to be used in some ETA calculations. This is a nice
69-
illustration of a trip all the way through the stack, because things have to
70-
change all the way from the frontend/UI, all the way down to the database.</p>
67+
<p>So. Once upon a time, early in my time at MADE, I remember having to make a
68+
simple change to an app that the buying team uses. We needed to record an extra
69+
piece of information for each shipment, an optional &ldquo;delay&rdquo; field to be used in
70+
some ETA calculations. This is a nice illustration of a trip all the way
71+
through the stack, because things have to change all the way from the
72+
frontend/UI, all the way down to the database.</p>
7173
<p>If you&rsquo;re using a framework like Django, you might be used to thinking of a
7274
change like this, in a perfect world, as a change you can make to just <strong>one</strong> file.
73-
We change <code>models.py</code>, and then our <code>ModelForm</code> will be updated automatically,
74-
and maybe even the frontend, if we&rsquo;re using the form&rsquo;s autogenerated HTML, will
75-
&ldquo;just work&rdquo; too. That&rsquo;s one of the reasons that Django is so good as a rapid
76-
application development framework; by closely coupling its various parts, it
77-
saves you a lot of messing about with database tables, html forms, validation,
78-
and so on. And if those are the main things you spend your time on, then Django
79-
is going to save you a lot of time.</p>
75+
You would change <code>models.py</code>, and then your <code>ModelForm</code> will be updated automatically,
76+
and maybe even the frontend will &ldquo;just work&rdquo; too, if you&rsquo;re using the form&rsquo;s
77+
autogenerated HTML. That&rsquo;s one of the reasons that Django is so good as a
78+
rapid application development framework: by closely coupling its various parts,
79+
it saves you a lot of messing about with database tables, html forms,
80+
validation, and so on. And if those are the main things you spend your time on,
81+
then Django is going to save you a lot of time.</p>
8082
<p>But in our world (at least in theory <a href="#in_theory">*</a>),
81-
database tables and html forms are not where we spend our time. Instead, we
82-
optimise for making it as easy as possible to capture and understand business
83-
logic, and as a result we want to <em>decouple</em> things.</p>
84-
<p>What does it cost? Well, let&rsquo;s take a trip through each file I had to change,
83+
database tables and html forms are <em>not</em> where we spend our time. Instead, we
84+
want to optimise for capturing and understand business logic, and as a
85+
result we want to <em>decouple</em> things.</p>
86+
<p>What does it cost? Well, let&rsquo;s take a trip through each file I had to touch,
8587
when I was making my <em>very minor</em> change to the data model in our app.</p>
86-
<ul>
87-
<li>I started off with editing a selenium test of the frontend, plus a javascript
88+
<ol start="0"><li>
89+
I started off with editing a selenium test of the frontend, plus a javascript
8890
frontend test, plus the frontend javascript itself, plus an html template.
89-
That&rsquo;s four files already, but they&rsquo;re not strictly relevant to the patterns
90-
and layers whose cost I want to account for, so I&rsquo;m going to say they don&rsquo;t
91-
count. Don&rsquo;t worry; there&rsquo;s plenty more to come.</li>
92-
</ul>
91+
That's four files already, but they're not strictly relevant to the patterns
92+
and layers whose cost I want to account for, so I'm going to say they don't
93+
count. If you think I'm cheating, don't worry; there's plenty more to come.
94+
</li></ol>
95+
9396
<p>So:</p>
9497
<ol>
95-
<li>An <strong>end-to-end / API test</strong> for the create and edit commands for the objects in question.</li>
96-
<li>The <strong>Command classes</strong> that capture various <a href="https://www.cosmicpython.com/book/chapter_10_commands.html">write interactions</a> a user can have
98+
<li>An <strong>end-to-end / API test</strong> for the create and edit use cases for the objects in question.</li>
99+
<li>The <strong>Command classes</strong> that capture those <a href="/book/chapter_10_commands.html">write interactions</a> a user can have
97100
with this model.</li>
98-
<li>The <strong>command schema</strong> which we use to <a href="https://www.cosmicpython.com/book/appendix_validation.html">validate incoming requests</a>.</li>
99-
<li>The <strong>service-layer tests</strong> which instantiate those commands to test their
101+
<li>The <strong>Command schema</strong> which we use to <a href="/book/appendix_validation.html">validate incoming requests</a>.</li>
102+
<li>The <strong>Service-Layer tests</strong> which instantiates those commands to test their
100103
handlers</li>
101-
<li>The <strong>handlers at the service-layer</strong> that orchestrate these use cases.</li>
102-
<li>The <strong>domain model tests</strong> that were affected. Although <a href="https://www.cosmicpython.com/book/chapter_05_high_gear_low_gear.html">not every domain model
103-
needs low-level unit tests as well as service-layer tests</a>, so if I was being indulgent I might
104-
not count this.</li>
105-
<li>The <strong>Domain Model</strong> itself.</li>
104+
<li>The <strong>Handlers at the Service Layer</strong> that orchestrate these use cases.</li>
105+
<li>The <strong>Domain Model tests</strong> that were affected. Although
106+
<a href="/book/chapter_05_high_gear_low_gear.html">not every domain model needs low-level unit tests as well as service-layer
107+
tests</a>,
108+
so if I was being indulgent I might not count this. But we did happen to
109+
have a few low-level tests in this case.</li>
110+
<li>The <strong>Domain Model</strong> <a href="/book/chapter_01_domain_model.html">itself</a>.</li>
106111
<li>The <strong>Repository integration test</strong>
107-
https://www.cosmicpython.com/book/chapter_02_repository.html</li>
108-
<li>The <strong>Repository and ORM config</strong> https://www.cosmicpython.com/book/chapter_02_repository.html</li>
112+
(repo and DB stuff is in <a href="/book/chapter_02_repository.html">chapter 3</a>)</li>
113+
<li>The <strong>Repository and ORM config</strong> </li>
109114
<li>The <strong>database schema</strong></li>
110115
<li>A <strong>migration file</strong> (admittedly autogenerated by Alembic, but we like to just give them a bit of a tidy-up before committing).</li>
111-
<li>The <strong>Event classes</strong> that capture ongoing internal/external consequences
116+
<li>The <strong>Event classes</strong> that capture ongoing <a href="/book/chapter_08_events_and_message_bus.html">internal</a> / <a href="/book/chapter_11_external_events.html">external</a> consequences
112117
of the various affected use cases</li>
113-
<li>The <strong>Event schema</strong> files we use for (outbound) validation.</li>
114-
<li>And that&rsquo;s not all! Because this app uses CQRS, the read-side is separate from the
118+
<li>The <strong>Event schema</strong> files we use for (outbound) <a href="/book/appendix_validation.html">validation</a>.</li>
119+
<li>And that&rsquo;s not all! Because this app uses <a href="/book/chapter_12_cqrs.html">CQRS</a>, the read-side is separate from the
115120
write side, so I also had to change some <strong>API JSON view tests</strong></li>
116121
<li>And the <strong>CQRS JSON views code</strong></li>
117122
</ol>
118-
<p>So that&rsquo;s fifteen files. Fifteen!</p>
123+
<p>So that&rsquo;s fifteen files. Fifteen! To add one field!</p>
119124
<p>Now I should add that each change was very simple. Most were a matter of
120125
copy-pasting a line and some find+replace. The whole job might have taken an hour
121126
or so. But if you&rsquo;re used to this sort of thing taking five minutes and happening
@@ -125,15 +130,14 @@ <h1> So Many Layers! A Note of Caution.</h1>
125130
<p>We think the cost we impose on ourselves here is worth it, because we believe
126131
that the main thing we want to make easy is not adding database fields and html
127132
forms. We want to make it easy to capture complex and evolving business
128-
requirements in a <a href="https://www.cosmicpython.com/book/chapter_01_domain_model.html">domain model</a>. But, as we try to say in each chapter,
133+
requirements in a <a href="/book/chapter_01_domain_model.html">domain model</a>. But, as we try to say in each chapter,
129134
your mileage may vary!</p>
130135
<div id="#in_theory"><small><i>
131-
OK, in theory. In practice I think this particular app was a _little_
136+
OK, in theory. In practice, I think this particular app was a _little_
132137
overengineered. It was one of the first ones that the team had complete
133-
freedom to try new patterns on, and they may have gone to town a little...
134-
But on the other hand, there is talk of converting that app to eventsourcing,
135-
and if we _had_ used Django, I don't think that would even be on the table,
136-
so...
138+
freedom to try new patterns on, and they may have gone to town a bit...
139+
But on the other hand, there is now talk of converting that app to eventsourcing,
140+
and thanks to all the layers, that would be relatively easy. Relatively.
137141
</i></small></div>
138142
</div>
139143

posts/2020-08-13-so-many-layers.md

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,76 +5,83 @@ image_credit: https://www.nasa.gov/image-feature/goddard/2017/hubbles-slice-of-s
55

66
In the book we are at pains to point out that each pattern is a trade-off, and
77
comes with costs. But just on the offchance that anyone was still missing the
8-
message, and thinking we were saying that all apps should be built like this,
8+
message and thinking we were saying that _all_ apps should be built like this,
99
I thought I'd write a small blog post just to reinforce the message about
10-
costs. Each time you add a layer, you buy yourself some decoupling, but it
10+
costs.
11+
12+
Each time you add a layer, you buy yourself some decoupling, but it
1113
comes at the cost of an extra moving part. In the simplest terms, there's an
1214
extra file you have to maintain.
1315

1416

15-
<a href="https://www.cosmicpython.com/book/appendix_ds1_table.html">
17+
<a href="/book/appendix_ds1_table.html">
1618
<figure>
1719
<img src="/book/images/apwp_aa01.png" alt="a recap of all the layers + parts of our architecture" max-height="60%">
1820
<figcaption>Here's a recap of all the layers + parts of our architecture</figcaption>
1921
</figure>
2022
</a>
2123

22-
I remember having to make a simple change to an app that the buying team at
23-
MADE uses. We needed to record an extra piece of information for each shipment,
24-
an optional "delay" field to be used in some ETA calculations. This is a nice
25-
illustration of a trip all the way through the stack, because things have to
26-
change all the way from the frontend/UI, all the way down to the database.
24+
So. Once upon a time, early in my time at MADE, I remember having to make a
25+
simple change to an app that the buying team uses. We needed to record an extra
26+
piece of information for each shipment, an optional "delay" field to be used in
27+
some ETA calculations. This is a nice illustration of a trip all the way
28+
through the stack, because things have to change all the way from the
29+
frontend/UI, all the way down to the database.
2730

2831
If you're using a framework like Django, you might be used to thinking of a
2932
change like this, in a perfect world, as a change you can make to just **one** file.
30-
We change `models.py`, and then our `ModelForm` will be updated automatically,
31-
and maybe even the frontend, if we're using the form's autogenerated HTML, will
32-
"just work" too. That's one of the reasons that Django is so good as a rapid
33-
application development framework; by closely coupling its various parts, it
34-
saves you a lot of messing about with database tables, html forms, validation,
35-
and so on. And if those are the main things you spend your time on, then Django
36-
is going to save you a lot of time.
33+
You would change `models.py`, and then your `ModelForm` will be updated automatically,
34+
and maybe even the frontend will "just work" too, if you're using the form's
35+
autogenerated HTML. That's one of the reasons that Django is so good as a
36+
rapid application development framework: by closely coupling its various parts,
37+
it saves you a lot of messing about with database tables, html forms,
38+
validation, and so on. And if those are the main things you spend your time on,
39+
then Django is going to save you a lot of time.
3740

3841
But in our world (at least in theory [*](#in_theory)),
39-
database tables and html forms are not where we spend our time. Instead, we
40-
optimise for making it as easy as possible to capture and understand business
41-
logic, and as a result we want to _decouple_ things.
42+
database tables and html forms are _not_ where we spend our time. Instead, we
43+
want to optimise for capturing and understand business logic, and as a
44+
result we want to _decouple_ things.
4245

43-
What does it cost? Well, let's take a trip through each file I had to change,
46+
What does it cost? Well, let's take a trip through each file I had to touch,
4447
when I was making my _very minor_ change to the data model in our app.
4548

46-
* I started off with editing a selenium test of the frontend, plus a javascript
49+
<ol start="0"><li>
50+
I started off with editing a selenium test of the frontend, plus a javascript
4751
frontend test, plus the frontend javascript itself, plus an html template.
4852
That's four files already, but they're not strictly relevant to the patterns
4953
and layers whose cost I want to account for, so I'm going to say they don't
50-
count. Don't worry; there's plenty more to come.
54+
count. If you think I'm cheating, don't worry; there's plenty more to come.
55+
</li></ol>
5156

5257
So:
5358

54-
1. An **end-to-end / API test** for the create and edit commands for the objects in question.
55-
2. The **Command classes** that capture various [write interactions](https://www.cosmicpython.com/book/chapter_10_commands.html) a user can have
59+
1. An **end-to-end / API test** for the create and edit use cases for the objects in question.
60+
2. The **Command classes** that capture those [write interactions](/book/chapter_10_commands.html) a user can have
5661
with this model.
57-
3. The **command schema** which we use to [validate incoming requests](https://www.cosmicpython.com/book/appendix_validation.html).
58-
4. The **service-layer tests** which instantiate those commands to test their
62+
3. The **Command schema** which we use to [validate incoming requests](/book/appendix_validation.html).
63+
4. The **Service-Layer tests** which instantiates those commands to test their
5964
handlers
60-
5. The **handlers at the service-layer** that orchestrate these use cases.
61-
6. The **domain model tests** that were affected. Although [not every domain model
62-
needs low-level unit tests as well as service-layer tests](https://www.cosmicpython.com/book/chapter_05_high_gear_low_gear.html), so if I was being indulgent I might
63-
not count this.
64-
7. The **Domain Model** itself.
65+
5. The **Handlers at the Service Layer** that orchestrate these use cases.
66+
6. The **Domain Model tests** that were affected. Although
67+
[not every domain model needs low-level unit tests as well as service-layer
68+
tests](/book/chapter_05_high_gear_low_gear.html),
69+
so if I was being indulgent I might not count this. But we did happen to
70+
have a few low-level tests in this case.
71+
7. The **Domain Model** [itself](/book/chapter_01_domain_model.html).
6572
8. The **Repository integration test**
66-
https://www.cosmicpython.com/book/chapter_02_repository.html
67-
9. The **Repository and ORM config** https://www.cosmicpython.com/book/chapter_02_repository.html
73+
(repo and DB stuff is in [chapter 3](/book/chapter_02_repository.html))
74+
9. The **Repository and ORM config**
6875
10. The **database schema**
6976
11. A **migration file** (admittedly autogenerated by Alembic, but we like to just give them a bit of a tidy-up before committing).
70-
12. The **Event classes** that capture ongoing internal/external consequences
77+
12. The **Event classes** that capture ongoing [internal](/book/chapter_08_events_and_message_bus.html) / [external](/book/chapter_11_external_events.html) consequences
7178
of the various affected use cases
72-
13. The **Event schema** files we use for (outbound) validation.
73-
14. And that's not all! Because this app uses CQRS, the read-side is separate from the
79+
13. The **Event schema** files we use for (outbound) [validation](/book/appendix_validation.html).
80+
14. And that's not all! Because this app uses [CQRS](/book/chapter_12_cqrs.html), the read-side is separate from the
7481
write side, so I also had to change some **API JSON view tests**
7582
15. And the **CQRS JSON views code**
7683

77-
So that's fifteen files. Fifteen!
84+
So that's fifteen files. Fifteen! To add one field!
7885

7986
Now I should add that each change was very simple. Most were a matter of
8087
copy-pasting a line and some find+replace. The whole job might have taken an hour
@@ -86,14 +93,13 @@ endeavour. I know I certainly did.
8693
We think the cost we impose on ourselves here is worth it, because we believe
8794
that the main thing we want to make easy is not adding database fields and html
8895
forms. We want to make it easy to capture complex and evolving business
89-
requirements in a [domain model](https://www.cosmicpython.com/book/chapter_01_domain_model.html). But, as we try to say in each chapter,
96+
requirements in a [domain model](/book/chapter_01_domain_model.html). But, as we try to say in each chapter,
9097
your mileage may vary!
9198

9299
<div id="#in_theory"><small><i>
93-
OK, in theory. In practice I think this particular app was a _little_
100+
OK, in theory. In practice, I think this particular app was a _little_
94101
overengineered. It was one of the first ones that the team had complete
95-
freedom to try new patterns on, and they may have gone to town a little...
96-
But on the other hand, there is talk of converting that app to eventsourcing,
97-
and if we _had_ used Django, I don't think that would even be on the table,
98-
so...
102+
freedom to try new patterns on, and they may have gone to town a bit...
103+
But on the other hand, there is now talk of converting that app to eventsourcing,
104+
and thanks to all the layers, that would be relatively easy. Relatively.
99105
</i></small></div>

rss.xml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,21 @@
77
Simple patterns for building complex apps
88
</description>
99
<link>https://www.cosmicpython.com</link>
10-
<lastBuildDate>Thu, 30 Jul 2020 13:57:16 -0000</lastBuildDate>
10+
<lastBuildDate>Mon, 17 Aug 2020 05:49:43 -0000</lastBuildDate>
1111
<pubDate>Sat, 4 Jan 2020 19:15:54 -0500</pubDate>
1212
<atom:link href="https://cosmicpython.com/rss.xml" rel="self" type="application/rss+xml" />
1313

14+
<item>
15+
<title>So Many Layers! A Note of Caution.</title>
16+
<description>
17+
18+
</description>
19+
<link>https://www.cosmicpython.com/blog/2020-08-13-so-many-layers.html</link>
20+
<pubDate>Thu, 13 Aug 2020 12:00:00 -0000</pubDate>
21+
<dc:creator>Harry</dc:creator>
22+
<guid></guid>
23+
</item>
24+
1425
<item>
1526
<title>Book review: Designing Data-Intensive Applications, by Martin Kleppmann</title>
1627
<description>

0 commit comments

Comments
 (0)