Skip to content

Commit 71f2c4d

Browse files
committed
feat(posts): add solid post
1 parent bd472f2 commit 71f2c4d

4 files changed

Lines changed: 249 additions & 9 deletions

File tree

config.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,15 @@ params:
104104
threshold: 0.4
105105
minMatchCharLength: 0
106106
keys: ["title", "permalink", "summary", "content"]
107-
# menu:
108-
# main:
109-
# - identifier: categories
110-
# name: categories
111-
# url: /categories/
112-
# weight: 10
113-
# - identifier: tags
114-
# name: tags
115-
# url: /tags/
107+
menu:
108+
main:
109+
- identifier: posts
110+
name: posts
111+
url: /posts/
112+
weight: 10
113+
# - identifier: about
114+
# name: about
115+
# url: /about/
116116
# weight: 20
117117
# - identifier: example
118118
# name: example.org

content/posts/solid.md

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
---
2+
title: "SOLID is a broken acronym. Here's how we fix it."
3+
date: 2023-08-13T19:54:20Z
4+
draft: false
5+
---
6+
7+
[SOLID](https://en.wikipedia.org/wiki/SOLID) is not a useful mnemonic acronym.
8+
9+
Even if you can remember what all the letters mean, it often just leads to more
10+
questions. Let's take the "L", for instance: the Liskov Substitution Principle.
11+
There's a [post on
12+
StackOverflow](https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle)
13+
simply titled "What is an example of the Liskov Substitution Principle?" with
14+
over half a million views. Unless you're a math major or a computer science
15+
historian, that name isn't going to ring any bells.
16+
17+
Let's stop beating ourselves up for Googling "examples of solid" every year and
18+
collectively accept the problem: SOLID is a broken acronym.
19+
20+
So how do we fix it?
21+
22+
In my experience, the most effective way to remember and recall design
23+
principles like SOLID is through examples and analogies.
24+
25+
In this blog post, I rename the letters in SOLID to remind us of a real-world
26+
analogy of each principle. In this version of SOLID, each word evokes some
27+
mental imagery that captures the underlying design principle without technical
28+
jargon or math formulas. I tried to pick concepts that are familiar in our
29+
everyday life.
30+
31+
What do you think?
32+
33+
## Surgeon
34+
35+
Your classes should be specialized like a surgeon.
36+
37+
Surgeons specialize in one specific task and do it well. Brain surgeons only do
38+
brain surgery. Heart surgeons only do heart surgery. Their job is specific and
39+
focused. This freedom from distractions allows them to get exceptionally good at
40+
what they do.
41+
42+
If your class has too much responsibility, it won't be able to specialize in any
43+
one task.
44+
45+
If your class is starting to seem scattered, consider breaking the class into
46+
multiple more specialized classes.
47+
48+
(Note: if it's easier for you, you can remember this one as just "Specialist" to the same effect)
49+
50+
## Orchestra
51+
52+
Your class should extend its behavior through a common interface. An orchestra
53+
shouldn't have to replace its conductor whenever it adds or removes a member.
54+
55+
To understand this principle, let's contrast orchestras with jazz bands.
56+
57+
Orchestras are extensible systems. Members can come and go without stopping the
58+
show. Want to hold auditions to add new members? You don't need the whole
59+
orchestra for a try-out; just give them some sheet music and see how they do.
60+
Perhaps on a given night a few violin players are added. No problem. Maybe Tommy
61+
the Trumpet Player calls in sick due to chapped lips. No one cares. The show can
62+
still go on. This flexibility allows orchestras to scale to hundreds of members
63+
without issue.
64+
65+
The same isn't true for jazz bands. While orchestras can scale to hundreds of
66+
members, jazz bands can't scale past a handful without descending into chaos.
67+
68+
Why are orchestras extensible whereas jazz bands are static? Orchestras
69+
have a conductor.
70+
71+
In an orchestra, the conductor provides a common interface. The
72+
conductor stands on a podium in clear sight of all the members to send them
73+
visual cues. Each member uses these cues, along with their sheet music, to play
74+
their part. This creates an auditory illusion of coordination among the members
75+
of the orchestra. I call it an illusion because the members aren't even
76+
listening to each other, let alone doing any coordination; they're just focusing
77+
on their own part while watching the conductor for cues.
78+
79+
```mermaid
80+
flowchart LR
81+
Conductor --> Violin
82+
Conductor --> Trumpet
83+
Conductor --> Percussion
84+
```
85+
86+
Jazz bands, on the other hand, don't rely on a central interface. Instead, they
87+
coordinate through their chemistry as a band. For a jazz band to work, the
88+
members need to know each other well. Adding a new member to the band requires
89+
hours of try-outs to see if they're a good "fit". It's a complicated process.
90+
You can't just swap out, add, or remove members of a jazz band like you can with
91+
an orchestra.
92+
93+
```mermaid
94+
flowchart LR
95+
Drums --> Guitar
96+
Drums --> Bass
97+
Drums --> Saxophone
98+
Guitar --> Bass
99+
Guitar --> Saxophone
100+
Bass --> Drums
101+
Saxophone --> Guitar
102+
```
103+
104+
Take a look at how your classes extend functionality. What would it take to add
105+
new functionality to your class? If it requires modifying the class itself, its
106+
a violation of this principle. Remember, an orchestra shouldn't need to replace its
107+
conductor every time it adds a new member.
108+
109+
## LEGOs
110+
111+
In your LEGO kit, any block can be replaced by another block with a compatible
112+
connector.
113+
114+
This doesn't mean both blocks must have the _same_ connectors. They just need to
115+
be _compatible_ connectors.
116+
117+
If some blocks have V1 connectors and others have V2, they will still connect if
118+
V2 is backwards compatible with V1. But if V3 connectors implement a new,
119+
non-comforming standard, you should not try to replace a V2 block with a V3
120+
block.
121+
122+
If you have multiple classes implementing the same interface, lookout for cases
123+
where a class appears categorically different from others. When you notice this,
124+
move those classes into a new interface.
125+
126+
## Insurance Policy
127+
128+
Like an insurance policy, your interfaces should be minimal.
129+
130+
Imagine if an insurance company only offered one policy. You either get full
131+
coverage or nothing. This means someone who only wants liability
132+
coverage will have to also pay for medical and collision coverage as well.
133+
134+
In reality, insurance companies tend to create flexible plans to stay
135+
competitive. This enables their customers to only pay for the coverage they want
136+
and nothing more.
137+
138+
When implementing your interfaces, do you often find yourself leaving many
139+
methods unimplemented? Or perhaps you find yourself forced to implement methods
140+
you won't actually use? If so, break your interfaces into smaller ones and join
141+
them together through inheritance as needed.
142+
143+
## Designer
144+
145+
Like a designer, your high-level classes should focus on the big picture,
146+
not implementation details.
147+
148+
Imagine an architect that goes to the construction site and micromanages the
149+
builders. The architect tells them what nails to use, where every pipe should
150+
go, and where every wire of electricity should run. As the project goes on, the
151+
architect becomes overwhelmed and the building quality declines. It's difficult
152+
to keep high-level design in mind while dealing with the low-level details.
153+
154+
Instead, the architect can create a blueprint. The blueprint is a document which
155+
contains the architect's high-level design of the home. The builders know how to
156+
translate the blueprint into the concrete details (no pun intended). The
157+
blueprint allows the architect to focus on design while allowing the builders to
158+
focus on the specifics of the building process.
159+
160+
In this example, If you have a class that's doing both high-level and low-level
161+
tasks, consider breaking them into multiple classes. As a bonus, you can get
162+
added benefits if the classes communicate through an interface (see "Orchestra"
163+
above).
164+
165+
# Summary
166+
167+
SOLID is a broken mnemonic device. Instead of helping us recall abstract design
168+
principles, it tends to lead to more questions. By replacing each letter of
169+
SOLID with a familiar analogy, it helps us recall more useful information.
170+
171+
What do you think? Feel free to let me know!
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<pre class="mermaid">
2+
{{- .Inner | safeHTML }}
3+
</pre>
4+
{{ .Page.Store.Set "hasMermaid" true }}

layouts/_default/single.html

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{{- define "main" }}
2+
<article class="post-single">
3+
<header class="post-header">
4+
{{ partial "breadcrumbs.html" . }}
5+
<h1 class="post-title">
6+
{{ .Title }}
7+
{{- if .Draft }}<sup><span class="entry-isdraft">&nbsp;&nbsp;[draft]</span></sup>{{- end }}
8+
</h1>
9+
{{- if .Description }}
10+
<div class="post-description">
11+
{{ .Description }}
12+
</div>
13+
{{- end }}
14+
{{- if not (.Param "hideMeta") }}
15+
<div class="post-meta">
16+
{{- partial "post_meta.html" . -}}
17+
{{- partial "translation_list.html" . -}}
18+
{{- partial "edit_post.html" . -}}
19+
{{- partial "post_canonical.html" . -}}
20+
</div>
21+
{{- end }}
22+
</header>
23+
{{- $isHidden := .Params.cover.hidden | default site.Params.cover.hiddenInSingle | default site.Params.cover.hidden }}
24+
{{- partial "cover.html" (dict "cxt" . "IsHome" false "isHidden" $isHidden) }}
25+
{{- if (.Param "ShowToc") }}
26+
{{- partial "toc.html" . }}
27+
{{- end }}
28+
29+
{{- if .Content }}
30+
<div class="post-content">
31+
{{- if not (.Param "disableAnchoredHeadings") }}
32+
{{- partial "anchored_headings.html" .Content -}}
33+
{{- else }}{{ .Content }}{{ end }}
34+
</div>
35+
{{- end }}
36+
37+
{{ if .Page.Store.Get "hasMermaid" }}
38+
<script type="module">
39+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
40+
mermaid.initialize({ startOnLoad: true });
41+
</script>
42+
{{ end }}
43+
44+
<footer class="post-footer">
45+
{{- $tags := .Language.Params.Taxonomies.tag | default "tags" }}
46+
<ul class="post-tags">
47+
{{- range ($.GetTerms $tags) }}
48+
<li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
49+
{{- end }}
50+
</ul>
51+
{{- if (.Param "ShowPostNavLinks") }}
52+
{{- partial "post_nav_links.html" . }}
53+
{{- end }}
54+
{{- if (and site.Params.ShowShareButtons (ne .Params.disableShare true)) }}
55+
{{- partial "share_icons.html" . -}}
56+
{{- end }}
57+
</footer>
58+
59+
{{- if (.Param "comments") }}
60+
{{- partial "comments.html" . }}
61+
{{- end }}
62+
</article>
63+
64+
{{- end }}{{/* end main */}}
65+

0 commit comments

Comments
 (0)