ploeh blog2024-10-03T17:42:07+00:00Mark Seemanndanish software designhttps://blog.ploeh.dkDas verflixte Hunde-Spielhttps://blog.ploeh.dk/2024/10/03/das-verflixte-hunde-spiel2024-10-03T17:41:00+00:00Mark Seemann
<div id="post">
<p>
<em>A puzzle kata, and a possible solution.</em>
</p>
<p>
When I was a boy I had a nine-piece puzzle that I'd been gifted by the Swizz branch of my family. It's called <em>Das verflixte Hunde-Spiel</em>, which means something like <em>the confounded dog game</em> in English. And while a puzzle with nine pieces doesn't sound like much, it is, in fact, incredibly difficult.
</p>
<p>
It's just a specific incarnation of a kind of game that you've almost certainly encountered, too.
</p>
<p>
<img src="/content/binary/hunde-spiel.jpg" alt="A picture of the box of the puzzle, together with the tiles spread out in unordered fashion.">
</p>
<p>
There are nine tiles, each with two dog heads and two dog ends. A dog may be coloured in one of four different patterns. The object of the game is to lay out the nine tiles in a 3x3 square so that all dog halves line up.
</p>
<h3 id="ddf5aa390eed4147a55a35e95803b6ad">
Game details <a href="#ddf5aa390eed4147a55a35e95803b6ad">#</a>
</h3>
<p>
The game is from 1979. Two of the tiles are identical, and, according to the information on the back of the box, two possible solutions exist. Described from top clockwise, the tiles are the following:
</p>
<ul>
<li>Brown head, grey head, umber tail, spotted tail</li>
<li>Brown head, spotted head, brown tail, umber tail</li>
<li>Brown head, spotted head, grey tail, umber tail</li>
<li>Brown head, spotted head, grey tail, umber tail</li>
<li>Brown head, umber head, spotted tail, grey tail</li>
<li>Grey head, brown head, spotted tail, umber tail</li>
<li>Grey head, spotted head, brown tail, umber tail</li>
<li>Grey head, umber head, brown tail, spotted tail</li>
<li>Grey head, umber head, grey tail, spotted tail</li>
</ul>
<p>
I've taken the liberty of using a shorthand for the patterns. The grey dogs are actually also spotted, but since there's only one grey pattern, the <em>grey</em> label is unambiguous. The dogs I've named <em>umber</em> are actually rather <em>burnt umber</em>, but that's too verbose for my tastes, so I just named them <em>umber</em>. Finally, the label <em>spotted</em> indicates dogs that are actually burnt umber with brown blotches.
</p>
<p>
Notice that there are two tiles with a brown head, a spotted head, a grey tail, and an umber tail.
</p>
<p>
The object of the game is to lay down the tiles in a 3x3 square so that all dogs fit. For further reference, I've numbered each position from one to nine like this:
</p>
<p>
<img src="/content/binary/numbered-3x3-tiles.png" alt="Nine tiles arranged in a three-by-three square, numbered from 1 to 9 from top left to bottom right.">
</p>
<p>
What makes the game hard? There are nine cards, so if you start with the upper left corner, you have nine choices. If you just randomly put down the tiles, you now have eight left for the top middle position, and so on. Standard combinatorics indicate that there are at least 9! = 362,880 permutations.
</p>
<p>
That's not the whole story, however, since you can rotate each tile in four different ways. You can rotate the first tile four ways, the second tile four ways, etc. for a total of 4<sup>9</sup> = 262,144 ways. Multiply these two numbers together, and you get 4<sup>9</sup>9! = 95,126,814,720 combinations. No wonder this puzzle is hard if there's only two solutions.
</p>
<p>
When analysed this way, however, there are actually 16 solutions, but that still makes it incredibly unlikely to arrive at a solution by chance. I'll get back to why there are 16 solutions later. For now, you should have enough information to try your hand with this game, if you'd like.
</p>
<p>
I found that the game made for an interesting <a href="/2020/01/13/on-doing-katas">kata</a>: Write a program that finds all possible solutions to the puzzle.
</p>
<p>
If you'd like to try your hand at this exercise, I suggest that you pause reading here.
</p>
<p>
In the rest of the article, I'll outline my first attempt. Spoiler alert: I'll also show one of the solutions.
</p>
<h3 id="113acd886fde4791b10c4a2b6f394216">
Types <a href="#113acd886fde4791b10c4a2b6f394216">#</a>
</h3>
<p>
When you program in <a href="https://www.haskell.org/">Haskell</a>, it's natural to start by defining some types.
</p>
<p>
<pre><span style="color:blue;">data</span> Half = Head | Tail <span style="color:blue;">deriving</span> (<span style="color:#2b91af;">Show</span>, <span style="color:#2b91af;">Eq</span>)
<span style="color:blue;">data</span> Pattern = Brown | Grey | Spotted | Umber <span style="color:blue;">deriving</span> (<span style="color:#2b91af;">Show</span>, <span style="color:#2b91af;">Eq</span>)
<span style="color:blue;">data</span> Tile = Tile {
<span style="color:#2b91af;">top</span> <span style="color:blue;">::</span> (<span style="color:blue;">Pattern</span>, <span style="color:blue;">Half</span>),
<span style="color:#2b91af;">right</span> <span style="color:blue;">::</span> (<span style="color:blue;">Pattern</span>, <span style="color:blue;">Half</span>),
<span style="color:#2b91af;">bottom</span> <span style="color:blue;">::</span> (<span style="color:blue;">Pattern</span>, <span style="color:blue;">Half</span>),
<span style="color:#2b91af;">left</span> <span style="color:blue;">::</span> (<span style="color:blue;">Pattern</span>, <span style="color:blue;">Half</span>) }
<span style="color:blue;">deriving</span> (<span style="color:#2b91af;">Show</span>, <span style="color:#2b91af;">Eq</span>)</pre>
</p>
<p>
Each tile describes what you find on its <code>top</code>, <code>right</code> side, <code>bottom</code>, and <code>left</code> side.
</p>
<p>
We're also going to need a function to evaluate whether two halves match:
</p>
<p>
<pre><span style="color:#2b91af;">matches</span> <span style="color:blue;">::</span> (<span style="color:blue;">Pattern</span>, <span style="color:blue;">Half</span>) <span style="color:blue;">-></span> (<span style="color:blue;">Pattern</span>, <span style="color:blue;">Half</span>) <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
matches (p1, h1) (p2, h2) = p1 == p2 && h1 /= h2</pre>
</p>
<p>
This function demands that the patterns match, but that the halves are opposites.
</p>
<p>
You can use the <code>Tile</code> type and its constituents to define the nine tiles of the game:
</p>
<p>
<pre><span style="color:#2b91af;">tiles</span> <span style="color:blue;">::</span> [<span style="color:blue;">Tile</span>]
tiles =
[
Tile (Brown, Head) (Grey, Head) (Umber, Tail) (Spotted, Tail),
Tile (Brown, Head) (Spotted, Head) (Brown, Tail) (Umber, Tail),
Tile (Brown, Head) (Spotted, Head) (Grey, Tail) (Umber, Tail),
Tile (Brown, Head) (Spotted, Head) (Grey, Tail) (Umber, Tail),
Tile (Brown, Head) (Umber, Head) (Spotted, Tail) (Grey, Tail),
Tile (Grey, Head) (Brown, Head) (Spotted, Tail) (Umber, Tail),
Tile (Grey, Head) (Spotted, Head) (Brown, Tail) (Umber, Tail),
Tile (Grey, Head) (Umber, Head) (Brown, Tail) (Spotted, Tail),
Tile (Grey, Head) (Umber, Head) (Grey, Tail) (Spotted, Tail)
]</pre>
</p>
<p>
Because I'm the neatnik that I am, I've sorted the tiles in lexicographic order, but the solution below doesn't rely on that.
</p>
<h3 id="1568796e41484e21bae6bb5734f996eb">
Brute force doesn't work <a href="#1568796e41484e21bae6bb5734f996eb">#</a>
</h3>
<p>
Before I started, I cast around the internet to see if there was an appropriate algorithm for the problem. While I found a few answers on <a href="https://stackoverflow.com/">Stack Overflow</a>, none of them gave me indication that any sophisticated algorithm was available. (Even so, there may be, and I just didn't find it.)
</p>
<p>
It seems clear, however, that you can implement some kind of recursive search-tree algorithm that cuts a branch off as soon as it realizes that it doesn't work. I'll get back to that later, so let's leave that for now.
</p>
<p>
Since I'd planned on writing the code in Haskell, I decided to first try something that might look like brute force. Because Haskell is lazily evaluated, you can sometimes get away with techniques that look wasteful when you're used to strict/eager evaluation. In this case, it turned out to not work, but it's often quicker to just make the attempt than trying to analyze the problem.
</p>
<p>
As already outlined, I first attempted a purely brute-force solution, betting that Haskell's lazy evaluation would be enough to skip over the unnecessary calculations:
</p>
<p>
<pre>allRotationsOf9 = replicateM 9 [0..3]
<span style="color:#2b91af;">allRotations</span> <span style="color:blue;">::</span> [<span style="color:blue;">Tile</span>] <span style="color:blue;">-></span> [[<span style="color:blue;">Tile</span>]]
allRotations ts = <span style="color:blue;">fmap</span> (\rs -> (\(r, t) -> rotations t !! r) <$> <span style="color:blue;">zip</span> rs ts) allRotationsOf9
<span style="color:#2b91af;">allConfigurations</span> <span style="color:blue;">::</span> [[<span style="color:blue;">Tile</span>]]
allConfigurations = permutations tiles >>= allRotations
solutions = <span style="color:blue;">filter</span> isSolution allConfigurations</pre>
</p>
<p>
My idea with the <code>allConfigurations</code> value was that it's supposed to enumerate all 95 billion combinations. Whether it actually does that, I was never able to verify, because if I try to run that code, my poor laptop runs for a couple of hours before it eventually runs out of memory. In other words, the GHCi process crashes.
</p>
<p>
I haven't shown <code>isSolution</code> or <code>rotations</code>, because I consider the implementations irrelevant. This attempt doesn't work anyway.
</p>
<p>
Now that I look at it, it's quite clear why this isn't a good strategy. There's little to be gained from lazy evaluation when the final attempt just attempts to <code>filter</code> a list. Even with lazy evaluation, the code still has to run through all 95 billion combinations.
</p>
<p>
Things might have been different if I just had to find one solution. With a little luck, it might be that the first solution appears after, say, a hundred million iterations, and lazy evaluation would then had meant that the remaining combinations would never run. Not so here, but hindsight is 20-20.
</p>
<h3 id="93754ac1a84e4a42b87253f1ffded97b">
Search tree <a href="#93754ac1a84e4a42b87253f1ffded97b">#</a>
</h3>
<p>
Back to the search tree idea. It goes like this: Start from the top left position and pick a random tile and rotation. Now pick an arbitrary tile <em>that fits</em> and place it to the right of it, and so on. As far as I can tell, you can always place the first four cards, but from there, you can easily encounter a combination that allows no further tiles. Here's an example:
</p>
<p>
<img src="/content/binary/hunde-spiel-no-fifth-tile.jpg" alt="Four matching tiles put down, with the remaining five tiles arranged to show that none of them fit the fifth position.">
</p>
<p>
None of the remaining five tiles fit in the fifth position. This means that we don't have to do <em>any</em> permutations that involve these four tiles in that combination. While the algorithm has to search through all five remaining tiles and rotations to discover that none fit in position 5, once it knows that, it doesn't have to go through the remaining four positions. That's 4<sup>4</sup>4! = 6,144 combinations that it can skip every time it discovers an impossible beginning. That doesn't sound like that much, but if we assume that this happens more often than not, it's still an improvement by orders of magnitude.
</p>
<p>
We may think of this algorithm as constructing a search tree, but immediately pruning all branches that aren't viable, as close to the root as possible.
</p>
<h3 id="76d4e7e1898a4da89de0d7afabbdc4e8">
Matches <a href="#76d4e7e1898a4da89de0d7afabbdc4e8">#</a>
</h3>
<p>
Before we get to the algorithm proper we need a few simple helper functions. One kind of function is a predicate that determines if a particular tile can occupy a given position. Since we may place any tile in any rotation in the first position, we don't need to write a predicate for that, but if we wanted to generalize, <code>const True</code> would do.
</p>
<p>
Whether or not we can place a given tile in the second position depends exclusively on the tile in the first position:
</p>
<p>
<pre><span style="color:#2b91af;">tile2Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile2Matches t1 t2 = right t1 `matches` left t2</pre>
</p>
<p>
If the <code>right</code> dog part of the first tile <code>matches</code> the <code>left</code> part of the second tile, the return value is <code>True</code>; otherwise, it's <code>False</code>. Note that I'm using infix notation for <code>matches</code>. I could also have written the function as
</p>
<p>
<pre><span style="color:#2b91af;">tile2Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile2Matches t1 t2 = matches (right t1) (left t2)</pre>
</p>
<p>
but it doesn't read as well.
</p>
<p>
In any case, the corresponding matching functions for the third and forth tile look similar:
</p>
<p>
<pre><span style="color:#2b91af;">tile3Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile3Matches t2 t3 = right t2 `matches` left t3
<span style="color:#2b91af;">tile4Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile4Matches t1 t4 = bottom t1 `matches` top t4</pre>
</p>
<p>
Notice that <code>tile4Matches</code> compares the fourth tile with the first tile rather than the third tile, because position 4 is directly beneath position 1, rather than to the right of position 3 (cf. the grid above). For that reason it also compares the <code>bottom</code> of tile 1 to the <code>top</code> of the fourth tile.
</p>
<p>
The matcher for the fifth tile is different:
</p>
<p>
<pre><span style="color:#2b91af;">tile5Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile5Matches t2 t4 t5 = bottom t2 `matches` top t5 && right t4 `matches` left t5</pre>
</p>
<p>
This is the first predicate that depends on two, rather than one, previous tiles. In position 5 we need to examine both the tile in position 2 and the one in position 4.
</p>
<p>
The same is true for position 6:
</p>
<p>
<pre><span style="color:#2b91af;">tile6Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile6Matches t3 t5 t6 = bottom t3 `matches` top t6 && right t5 `matches` left t6</pre>
</p>
<p>
but then the matcher for position 7 looks like the predicate for position 4:
</p>
<p>
<pre><span style="color:#2b91af;">tile7Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile7Matches t4 t7 = bottom t4 `matches` top t7</pre>
</p>
<p>
This is, of course, because the tile in position 7 only has to consider the tile in position 4. Finally, not surprising, the two remaining predicates look like something we've already seen:
</p>
<p>
<pre><span style="color:#2b91af;">tile8Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile8Matches t5 t7 t8 = bottom t5 `matches` top t8 && right t7 `matches` left t8
<span style="color:#2b91af;">tile9Matches</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
tile9Matches t6 t8 t9 = bottom t6 `matches` top t9 && right t8 `matches` left t9</pre>
</p>
<p>
You may suggest that it'd be possible to reduce the number of predicates. After all, there's effectively only three different predicates: One that only looks at the tile to the left, one that only looks at the tile above, and one that looks both to the left and above.
</p>
<p>
Indeed, I could have boiled it down to just three functions:
</p>
<p>
<pre><span style="color:#2b91af;">matchesHorizontally</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
matchesHorizontally x y = right x `matches` left y
<span style="color:#2b91af;">matchesVertically</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
matchesVertically x y = bottom x `matches` top y
<span style="color:#2b91af;">matchesBoth</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">Bool</span>
matchesBoth x y z = matchesVertically x z && matchesHorizontally y z</pre>
</p>
<p>
but I now run the risk of calling the wrong predicate from my implementation of the algorithm. As you'll see, I'll call each predicate by name at each appropriate step, but if I had only these three functions, there's a risk that I might mistakenly use <code>matchesHorizontally</code> when I should have used <code>matchesVertically</code>, or vice versa. Reducing eight one-liners to three one-liners doesn't really seem to warrant the risk.
</p>
<h3 id="01bf66f9df1947d296a004e93638450d">
Rotations <a href="#01bf66f9df1947d296a004e93638450d">#</a>
</h3>
<p>
In addition to examining whether a given tile fits in a given position, we also need to be able to rotate any tile:
</p>
<p>
<pre><span style="color:#2b91af;">rotateClockwise</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span>
rotateClockwise (Tile t r b l) = Tile l t r b
<span style="color:#2b91af;">rotateCounterClockwise</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span>
rotateCounterClockwise (Tile t r b l) = Tile r b l t
<span style="color:#2b91af;">upend</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> <span style="color:blue;">Tile</span>
upend (Tile t r b l) = Tile b l t r</pre>
</p>
<p>
What is really needed, it turns out, is to enumerate all four rotations of a tile:
</p>
<p>
<pre><span style="color:#2b91af;">rotations</span> <span style="color:blue;">::</span> <span style="color:blue;">Tile</span> <span style="color:blue;">-></span> [<span style="color:blue;">Tile</span>]
rotations t = [t, rotateClockwise t, upend t, rotateCounterClockwise t]</pre>
</p>
<p>
Since this, like everything else here, is a pure function, I experimented with defining a 'memoized tile' type that embedded all four rotations upon creation, so that the algorithm doesn't need to call the <code>rotations</code> function millions of times, but I couldn't measure any discernable performance improvement from it. There's no reason to make things more complicated than they need to be, so I didn't keep that change. (Since I do, however, <a href="https://stackoverflow.blog/2022/12/19/use-git-tactically/">use Git tactically</a> i did, of course, <a href="https://git-scm.com/docs/git-stash">stash</a> the experiment.)
</p>
<h3 id="8e7ce1c1bb9c4403abd72d5d3d87bf02">
Permutations <a href="#8e7ce1c1bb9c4403abd72d5d3d87bf02">#</a>
</h3>
<p>
While I couldn't make things work by enumerating all 95 billion combinations, enumerating all 362,880 permutations of non-rotated tiles is well within the realm of the possible:
</p>
<p>
<pre><span style="color:#2b91af;">allPermutations</span> <span style="color:blue;">::</span> [(<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
allPermutations =
(\[t1, t2, t3, t4, t5, t6, t7, t8, t9] -> (t1, t2, t3, t4, t5, t6, t7, t8, t9))
<$> permutations tiles</pre>
</p>
<p>
Doing this in GHCi on my old laptop takes 300 milliseconds, which is good enough compared to what comes next.
</p>
<p>
This list value uses <a href="https://hackage.haskell.org/package/base/docs/Data-List.html#v:permutations">permutations</a> to enumerate all the permutations. You may already have noticed that it converts the result into a nine-tuple. The reason for that is that this enables the algorithm to pattern-match into specific positions without having to resort to the <a href="https://hackage.haskell.org/package/base/docs/Data-List.html#v:-33--33-">index operator</a>, which is both partial and requires iteration of the list to reach the indexed element. Granted, the list is only nine elements long, and often the algorithm will only need to index to the fourth or fifth element. On the other hand, it's going to do it <em>a lot</em>. Perhaps it's a premature optimization, but if it is, it's at least one that makes the code more, rather than less, readable.
</p>
<h3 id="3f0af3d6c91a4cd68b026a0ccf93a0e2">
Algorithm <a href="#3f0af3d6c91a4cd68b026a0ccf93a0e2">#</a>
</h3>
<p>
I found it easiest to begin at the 'bottom' of what is effectively a recursive algorithm, even though I didn't implement it that way. At the 'bottom', I imagine that I'm almost done: That I've found eight tiles that match, and now I only need to examine if I can rotate the final tile so that it matches:
</p>
<p>
<pre><span style="color:#2b91af;">solve9th</span> <span style="color:blue;">::</span> (a, b, c, d, e, <span style="color:blue;">Tile</span>, g, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(a, b, c, d, e, <span style="color:blue;">Tile</span>, g, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve9th (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- <span style="color:blue;">filter</span> (tile9Matches t6 t8) $ rotations t9
<span style="color:blue;">return</span> (t1, t2, t3, t4, t5, t6, t7, t8, match)</pre>
</p>
<p>
Recalling that Haskell functions compose from right to left, the function starts by enumerating the four <code>rotations</code> of the ninth and final tile <code>t9</code>. It then filters those four rotations by the <code>tile9Matches</code> predicate.
</p>
<p>
The <code>match</code> value is a rotation of <code>t9</code> that matches <code>t6</code> and <code>t8</code>. Whenever <code>solve9th</code> finds such a match, it returns the entire nine-tuple, because the assumption is that the eight first tiles are already valid.
</p>
<p>
Notice that the function uses <code>do</code> notation in the list monad, so it's quite possible that the first <code>filter</code> expression produces no <code>match</code>. In that case, the second line of code never runs, and instead, the function returns the empty list.
</p>
<p>
How do we find a tuple where the first eight elements are valid? Well, if we have seven valid tiles, we may consider the eighth and subsequently call <code>solve9th</code>:
</p>
<p>
<pre><span style="color:#2b91af;">solve8th</span> <span style="color:blue;">::</span> (a, b, c, d, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(a, b, c, d, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve8th (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- <span style="color:blue;">filter</span> (tile8Matches t5 t7) $ rotations t8
solve9th (t1, t2, t3, t4, t5, t6, t7, match, t9)</pre>
</p>
<p>
This function looks a lot like <code>solve9th</code>, but it instead enumerates the four <code>rotations</code> of the eighth tile <code>t8</code> and filters with the <code>tile8Matches</code> predicate. Due to the <code>do</code> notation, it'll only call <code>solve9th</code> if it finds a <code>match</code>.
</p>
<p>
Once more, this function assumes that the first seven tiles are already in a legal constellation. How do we find seven valid tiles? The same way we find eight: By assuming that we have six valid tiles, and then finding the seventh, and so on:
</p>
<p>
<pre><span style="color:#2b91af;">solve7th</span> <span style="color:blue;">::</span> (a, b, c, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(a, b, c, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve7th (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- <span style="color:blue;">filter</span> (tile7Matches t4) $ rotations t7
solve8th (t1, t2, t3, t4, t5, t6, match, t8, t9)
<span style="color:#2b91af;">solve6th</span> <span style="color:blue;">::</span> (a, b, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(a, b, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve6th (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- <span style="color:blue;">filter</span> (tile6Matches t3 t5) $ rotations t6
solve7th (t1, t2, t3, t4, t5, match, t7, t8, t9)
<span style="color:#2b91af;">solve5th</span> <span style="color:blue;">::</span> (a, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(a, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve5th (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- <span style="color:blue;">filter</span> (tile5Matches t2 t4) $ rotations t5
solve6th (t1, t2, t3, t4, match, t6, t7, t8, t9)
<span style="color:#2b91af;">solve4th</span> <span style="color:blue;">::</span> (<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve4th (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- <span style="color:blue;">filter</span> (tile4Matches t1) $ rotations t4
solve5th (t1, t2, t3, match, t5, t6, t7, t8, t9)
<span style="color:#2b91af;">solve3rd</span> <span style="color:blue;">::</span> (<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve3rd (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- <span style="color:blue;">filter</span> (tile3Matches t2) $ rotations t3
solve4th (t1, t2, match, t4, t5, t6, t7, t8, t9)
<span style="color:#2b91af;">solve2nd</span> <span style="color:blue;">::</span> (<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve2nd (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- <span style="color:blue;">filter</span> (tile2Matches t1) $ rotations t2
solve3rd (t1, match, t3, t4, t5, t6, t7, t8, t9)</pre>
</p>
<p>
You'll observe that <code>solve7th</code> down to <code>solve2nd</code> are very similar. The only things that really vary are the predicates, and the positions of the tile being examined, as well as its neighbours. Clearly I can generalize this code, but I'm not sure it's worth it. I wrote a few of these in the order I've presented them here, because it helped me think the problem through, and to be honest, once I had two or three of them, <a href="https://github.com/features/copilot">GitHub Copilot</a> picked up on the pattern and wrote the remaining functions for me.
</p>
<p>
Granted, <a href="/2018/09/17/typing-is-not-a-programming-bottleneck">typing isn't a programming bottleneck</a>, so we should rather ask if this kind of duplication looks like a maintenance problem. Given that this is a one-time exercise, I'll just leave it be and move on.
</p>
<p>
Particularly, if you're struggling to understand how this implements the 'truncated search tree', keep in mind that e..g <code>solve5th</code> is likely to produce no valid <code>match</code>, in which case it'll never call <code>solve6th</code>. The same may happen in <code>solve6th</code>, etc.
</p>
<p>
The 'top' function is a bit different because it doesn't need to <code>filter</code> anything:
</p>
<p>
<pre><span style="color:#2b91af;">solve1st</span> <span style="color:blue;">::</span> (<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)
<span style="color:blue;">-></span> [(<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solve1st (t1, t2, t3, t4, t5, t6, t7, t8, t9) = <span style="color:blue;">do</span>
match <- rotations t1
solve2nd (match, t2, t3, t4, t5, t6, t7, t8, t9)</pre>
</p>
<p>
In the first position, any tile in any rotation is legal, so <code>solve1st</code> only enumerates all four <code>rotations</code> of <code>t1</code> and calls <code>solve2nd</code> for each.
</p>
<p>
The final step is to compose <code>allPermutations</code> with <code>solve1st</code>:
</p>
<p>
<pre><span style="color:#2b91af;">solutions</span> <span style="color:blue;">::</span> [(<span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>, <span style="color:blue;">Tile</span>)]
solutions = allPermutations >>= solve1st</pre>
</p>
<p>
Running this in GHCi on my 4½-year old laptop produces all 16 solutions in approximately 22 seconds.
</p>
<h3 id="d3d8c77398334534b5a200a240d7bddc">
Evaluation <a href="#d3d8c77398334534b5a200a240d7bddc">#</a>
</h3>
<p>
Is that good performance? Well, it turns out that it's possible to substantially improve on the situation. As I've mentioned a couple of times, so far I've been running the program from GHCi, the Haskell <a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a>. Most of the 22 seconds are spent interpreting or compiling the code.
</p>
<p>
If I compile the code with some optimizations turned on, the executable runs in approximately 300 ms. That seems quite decent, if I may say so.
</p>
<p>
I can think of a few tweaks to the code that might conceivably improve things even more, but when I test, there's no discernable difference. Thus, I'll keep the code as shown here.
</p>
<p>
Here's one of the solutions:
</p>
<p>
<img src="/content/binary/hunde-spiel-solution.jpg" alt="One of the game solutions.">
</p>
<p>
The information on the box claims that there's two solutions. Why does the code shown here produce 16 solutions?
</p>
<p>
There's a good explanation for that. Recall that two of the tiles are identical. In the above solution picture, it's tile 1 and 3, although they're rotated 90° in relation to each other. This implies that you could take tile 1, rotate it counter-clockwise and put it in position 3, while simultaneously taking tile 3, rotating it clockwise, and putting it in position 1. Visually, you can't tell the difference, so they don't count as two distinct solutions. The algorithm, however, doesn't make that distinction, so it enumerates what is effectively the same solution twice.
</p>
<p>
Not surprising, it turns out that all 16 solutions are doublets in that way. We can confirm that by evaluating <code>length $ <a href="https://hackage.haskell.org/package/base/docs/Data-List.html#v:nub">nub</a> solutions</code>, which returns <code>8</code>.
</p>
<p>
Eight solutions are, however, still four times more than two. Can you figure out what's going on?
</p>
<p>
The algorithm also enumerates four rotations of each solution. Once we take this into account, there's only two visually distinct solutions left. One of them is shown above. I also have a picture of the other one, but I'm not going to totally spoil things for you.
</p>
<h3 id="f97500846a6e481ebe1706278f324979">
Conclusion <a href="#f97500846a6e481ebe1706278f324979">#</a>
</h3>
<p>
When I was eight, I might have had the time and the patience to actually lay the puzzle. Despite the incredibly bad odds, I vaguely remember finally solving it. There must be some more holistic processing going on in the brain, if even a kid can solve the puzzle, because it seems inconceivable that it should be done as described here.
</p>
<p>
Today, I don't care for that kind of puzzle in analog form, but I did, on the other hand, find it an interesting programming exercise.
</p>
<p>
The code could be smaller, but I like it as it is. While a bit on the verbose side, I think that it communicates well what's going on.
</p>
<p>
I was pleasantly surprised that I managed to get execution time down to 300 ms. I'd honestly not expected that when I started.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.FSZipper in C#https://blog.ploeh.dk/2024/09/23/fszipper-in-c2024-09-23T06:13:00+00:00Mark Seemann
<div id="post">
<p>
<em>Another functional model of a file system, with code examples in C#.</em>
</p>
<p>
This article is part of <a href="/2024/08/19/zippers">a series about Zippers</a>. In this one, I port the <code>FSZipper</code> data structure from the <a href="https://learnyouahaskell.com/">Learn You a Haskell for Great Good!</a> article <a href="https://learnyouahaskell.com/zippers">Zippers</a>.
</p>
<p>
A word of warning: I'm assuming that you're familiar with the contents of that article, so I'll skip the pedagogical explanations; I can hardly do it better that it's done there. Additionally, I'll make heavy use of certain standard constructs to port <a href="https://www.haskell.org/">Haskell</a> code, most notably <a href="/2018/05/22/church-encoding">Church encoding</a> to model <a href="https://en.wikipedia.org/wiki/Tagged_union">sum types</a> in languages that don't natively have them. Such as C#. In some cases, I'll implement the Church encoding using the data structure's <a href="/2019/04/29/catamorphisms">catamorphism</a>. Since the <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> of the resulting code is quite low, you may be able to follow what's going on even if you don't know what Church encoding or catamorphisms are, but if you want to understand the background and motivation for that style of programming, you can consult the cited resources.
</p>
<p>
The code shown in this article is <a href="https://github.com/ploeh/CSharpZippers">available on GitHub</a>.
</p>
<h3 id="dd4cbc996cfa4347afa4b9279c95f6e1">
File system item initialization and structure <a href="#dd4cbc996cfa4347afa4b9279c95f6e1">#</a>
</h3>
<p>
If you haven't already noticed, Haskell (and other statically typed functional programming languages like <a href="https://fsharp.org/">F#</a>) makes heavy use of <a href="https://en.wikipedia.org/wiki/Tagged_union">sum types</a>, and the <code>FSZipper</code> example is no exception. It starts with a one-liner to define a file system item, which may be either a file or a folder. In C# we must instead use a class:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">FSItem</span></pre>
</p>
<p>
Contrary to the two previous examples, the <code>FSItem</code> class has no generic type parameter. This is because I'm following the Haskell example code as closely as possible, but as I've previously shown, you can <a href="/2019/08/26/functional-file-system">model a file hierarchy with a general-purpose rose tree</a>.
</p>
<p>
Staying consistent with the two previous articles, I'll use Church encoding to model a sum type, and as discussed in <a href="/2024/09/09/a-binary-tree-zipper-in-c">the previous article</a> I use a <code>private</code> implementation for that.
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">IFSItem</span> imp;
<span style="color:blue;">private</span> <span style="color:#2b91af;">FSItem</span>(<span style="color:#2b91af;">IFSItem</span> <span style="font-weight:bold;color:#1f377f;">imp</span>)
{
<span style="color:blue;">this</span>.imp = <span style="font-weight:bold;color:#1f377f;">imp</span>;
}
<span style="color:blue;">public</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">FSItem</span> <span style="color:#74531f;">CreateFile</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">name</span>, <span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">data</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">File</span>(<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">data</span>));
}
<span style="color:blue;">public</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">FSItem</span> <span style="color:#74531f;">CreateFolder</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">name</span>, <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSItem</span>> <span style="font-weight:bold;color:#1f377f;">items</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">Folder</span>(<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">items</span>));
}</pre>
</p>
<p>
Two <code>static</code> creation methods enable client developers to create a single <code>FSItem</code> object, or an entire tree, like the example from the Haskell code, here ported to C#:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">static</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">FSItem</span> myDisk =
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"root"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"goat_yelling_like_man.wmv"</span>, <span style="color:#a31515;">"baaaaaa"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"pope_time.avi"</span>, <span style="color:#a31515;">"god bless"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"pics"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"ape_throwing_up.jpg"</span>, <span style="color:#a31515;">"bleargh"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"watermelon_smash.gif"</span>, <span style="color:#a31515;">"smash!!"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"skull_man(scary).bmp"</span>, <span style="color:#a31515;">"Yikes!"</span>)
]),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"dijon_poupon.doc"</span>, <span style="color:#a31515;">"best mustard"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"programs"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"fartwizard.exe"</span>, <span style="color:#a31515;">"10gotofart"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"owl_bandit.dmg"</span>, <span style="color:#a31515;">"mov eax, h00t"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"not_a_virus.exe"</span>, <span style="color:#a31515;">"really not a virus"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"source code"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"best_hs_prog.hs"</span>, <span style="color:#a31515;">"main = print (fix error)"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"random.hs"</span>, <span style="color:#a31515;">"main = print 4"</span>)
])
])
]);</pre>
</p>
<p>
Since the <code>imp</code> class field is just a <code>private</code> implementation detail, a client developer needs a way to query an <code>FSItem</code> object about its contents.
</p>
<h3 id="246063d761a94eb880a079f1d31b817d">
File system item catamorphism <a href="#246063d761a94eb880a079f1d31b817d">#</a>
</h3>
<p>
Just like the previous article, I'll start with the catamorphism. This is essentially the <a href="/2019/08/05/rose-tree-catamorphism">rose tree catamorphism</a>, just less generic, since <code>FSItem</code> doesn't have a generic type parameter.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFile</span>,
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">TResult</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFolder</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> imp.<span style="font-weight:bold;color:#74531f;">Aggregate</span>(<span style="font-weight:bold;color:#1f377f;">whenFile</span>, <span style="font-weight:bold;color:#1f377f;">whenFolder</span>);
}</pre>
</p>
<p>
The <code>Aggregate</code> method delegates to its internal implementation class field, which is defined as the <code>private</code> nested interface <code>IFSItem</code>:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">interface</span> <span style="color:#2b91af;">IFSItem</span>
{
<span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFile</span>,
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">TResult</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFolder</span>);
}</pre>
</p>
<p>
As discussed in the previous article, the interface is hidden away because it's only a vehicle for polymorphism. It's not intended for client developers to be used (although that would be benign) or implemented (which could break <a href="/encapsulation-and-solid">encapsulation</a>). There are only, and should ever only be, two implementations. The one that represents a file is the simplest:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">record</span> <span style="color:#2b91af;">File</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">Name</span>, <span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">Data</span>) : <span style="color:#2b91af;">IFSItem</span>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFile</span>,
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">TResult</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFolder</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">whenFile</span>(Name, Data);
}
}</pre>
</p>
<p>
The <code>File</code> record's <code>Aggregate</code> method unconditionally calls the supplied <code>whenFile</code> function argument with the <code>Name</code> and <code>Data</code> that was originally supplied via its constructor.
</p>
<p>
The <code>Folder</code> implementation is a bit trickier, mostly due to its recursive nature, but also because I wanted it to have structural equality.
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">Folder</span> : <span style="color:#2b91af;">IFSItem</span>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:blue;">string</span> name;
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSItem</span>> items;
<span style="color:blue;">public</span> <span style="color:#2b91af;">Folder</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">Name</span>, <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSItem</span>> <span style="font-weight:bold;color:#1f377f;">Items</span>)
{
name = <span style="font-weight:bold;color:#1f377f;">Name</span>;
items = <span style="font-weight:bold;color:#1f377f;">Items</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFile</span>,
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">TResult</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFolder</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">whenFolder</span>(
name,
items.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">i</span> => <span style="font-weight:bold;color:#1f377f;">i</span>.<span style="font-weight:bold;color:#74531f;">Aggregate</span>(<span style="font-weight:bold;color:#1f377f;">whenFile</span>, <span style="font-weight:bold;color:#1f377f;">whenFolder</span>)).<span style="font-weight:bold;color:#74531f;">ToList</span>());
}
<span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">Equals</span>(<span style="color:blue;">object</span>? <span style="font-weight:bold;color:#1f377f;">obj</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">obj</span> <span style="color:blue;">is</span> <span style="color:#2b91af;">Folder</span> <span style="font-weight:bold;color:#1f377f;">folder</span> &&
name == <span style="font-weight:bold;color:#1f377f;">folder</span>.name &&
items.<span style="font-weight:bold;color:#74531f;">SequenceEqual</span>(<span style="font-weight:bold;color:#1f377f;">folder</span>.items);
}
<span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:blue;">int</span> <span style="font-weight:bold;color:#74531f;">GetHashCode</span>()
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">HashCode</span>.<span style="color:#74531f;">Combine</span>(name, items);
}
}</pre>
</p>
<p>
It, too, unconditionally calls one of the two functions passed to its <code>Aggregate</code> method, but this time <code>whenFolder</code>. It does that, however, by first <em>recursively</em> calling <code>Aggregate</code> within a <code>Select</code> expression. It needs to do that because the <code>whenFolder</code> function expects the subtree to have been already converted to values of the <code>TResult</code> return type. This is a common pattern with catamorphisms, and takes a bit of time getting used to. You can see similar examples in the articles <a href="/2019/06/10/tree-catamorphism">Tree catamorphism</a>, <a href="/2019/08/05/rose-tree-catamorphism">Rose tree catamorphism</a>, <a href="/2019/06/24/full-binary-tree-catamorphism">Full binary tree catamorphism</a>, as well as the previous one in this series.
</p>
<p>
I also had to make <code>Folder</code> a <code>class</code> rather than a <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/record">record</a>, because I wanted the type to have structural equality, and you can't override <a href="https://learn.microsoft.com/dotnet/api/system.object.equals">Equals</a> on records (and if the base class library has any collection type with structural equality, I'm not aware of it).
</p>
<h3 id="761c6a5ede2b4df68985e61f6664822f">
File system item Church encoding <a href="#761c6a5ede2b4df68985e61f6664822f">#</a>
</h3>
<p>
True to the structure of the previous article, the catamorphism doesn't look quite like a Church encoding, but it's possible to define the latter from the former.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Match</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:blue;">string</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFile</span>,
<span style="color:#2b91af;">Func</span><<span style="color:blue;">string</span>, <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSItem</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenFolder</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span>(
<span style="font-weight:bold;color:#1f377f;">whenFile</span>: (<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">data</span>) =>
(item: <span style="color:#74531f;">CreateFile</span>(<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">data</span>), result: <span style="font-weight:bold;color:#1f377f;">whenFile</span>(<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">data</span>)),
<span style="font-weight:bold;color:#1f377f;">whenFolder</span>: (<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">pairs</span>) =>
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">items</span> = <span style="font-weight:bold;color:#1f377f;">pairs</span>.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">i</span> => <span style="font-weight:bold;color:#1f377f;">i</span>.item).<span style="font-weight:bold;color:#74531f;">ToList</span>();
<span style="font-weight:bold;color:#8f08c4;">return</span> (<span style="color:#74531f;">CreateFolder</span>(<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">items</span>), <span style="font-weight:bold;color:#1f377f;">whenFolder</span>(<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">items</span>));
}).result;
}</pre>
</p>
<p>
The trick is the same as in the previous article: Build up an intermediate tuple that contains both the current <code>item</code> as well as the <code>result</code> being accumulated. Once the <code>Aggregate</code> method returns, the <code>Match</code> method returns only the <code>result</code> part of the resulting tuple.
</p>
<p>
I implemented the <code>whenFolder</code> expression as a code block, because both tuple elements needed the <code>items</code> collection. You can inline the <code>Select</code> expression, but that would cause it to run twice. That's probably a premature optimization, but it also made the code a bit shorter, and, one may hope, a bit more readable.
</p>
<h3 id="c2ffdb1994bc400d99f359ecf4edb312">
Fily system breadcrumb <a href="#c2ffdb1994bc400d99f359ecf4edb312">#</a>
</h3>
<p>
Finally, things seem to be becoming a little easier. The port of <code>FSCrumb</code> is straightforward.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">FSCrumb</span>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">FSCrumb</span>(
<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">name</span>,
<span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSItem</span>> <span style="font-weight:bold;color:#1f377f;">left</span>,
<span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSItem</span>> <span style="font-weight:bold;color:#1f377f;">right</span>)
{
Name = <span style="font-weight:bold;color:#1f377f;">name</span>;
Left = <span style="font-weight:bold;color:#1f377f;">left</span>;
Right = <span style="font-weight:bold;color:#1f377f;">right</span>;
}
<span style="color:blue;">public</span> <span style="color:blue;">string</span> Name { <span style="color:blue;">get</span>; }
<span style="color:blue;">public</span> <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSItem</span>> Left { <span style="color:blue;">get</span>; }
<span style="color:blue;">public</span> <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSItem</span>> Right { <span style="color:blue;">get</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">Equals</span>(<span style="color:blue;">object</span>? <span style="font-weight:bold;color:#1f377f;">obj</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">obj</span> <span style="color:blue;">is</span> <span style="color:#2b91af;">FSCrumb</span> <span style="font-weight:bold;color:#1f377f;">crumb</span> &&
Name == <span style="font-weight:bold;color:#1f377f;">crumb</span>.Name &&
Left.<span style="font-weight:bold;color:#74531f;">SequenceEqual</span>(<span style="font-weight:bold;color:#1f377f;">crumb</span>.Left) &&
Right.<span style="font-weight:bold;color:#74531f;">SequenceEqual</span>(<span style="font-weight:bold;color:#1f377f;">crumb</span>.Right);
}
<span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:blue;">int</span> <span style="font-weight:bold;color:#74531f;">GetHashCode</span>()
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">HashCode</span>.<span style="color:#74531f;">Combine</span>(Name, Left, Right);
}
}</pre>
</p>
<p>
The only reason this isn't a <code>record</code> is, once again, that I want to override <code>Equals</code> so that the type can have structural equality. <a href="https://visualstudio.microsoft.com/">Visual Studio</a> wants me to convert to a <a href="https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors">primary constructor</a>. That would simplify the code a bit, but actually not that much.
</p>
<p>
(I'm still somewhat conservative in my choice of new C# language features. Not that I have anything against primary constructors which, after all, F# has had forever. The reason I'm holding back is for didactic reasons. Not every reader is on the latest language version, and some readers may be using another programming language entirely. On the other hand, primary constructors seem natural and intuitive, so I may start using them here on the blog as well. I don't think that they're going to be much of a barrier to understanding.)
</p>
<p>
Now that we have both the data type we want to zip, as well as the breadcrumb type we need, we can proceed to add the Zipper.
</p>
<h3 id="bb452627a3c3420a95a412dd33ad0efa">
File system Zipper <a href="#bb452627a3c3420a95a412dd33ad0efa">#</a>
</h3>
<p>
The <code>FSZipper</code> C# class fills the position of the eponymous Haskell type alias. Data structure and initialization is straightforward.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">FSZipper</span>
{
<span style="color:blue;">private</span> <span style="color:#2b91af;">FSZipper</span>(<span style="color:#2b91af;">FSItem</span> <span style="font-weight:bold;color:#1f377f;">fSItem</span>, <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSCrumb</span>> <span style="font-weight:bold;color:#1f377f;">breadcrumbs</span>)
{
FSItem = <span style="font-weight:bold;color:#1f377f;">fSItem</span>;
Breadcrumbs = <span style="font-weight:bold;color:#1f377f;">breadcrumbs</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">FSZipper</span>(<span style="color:#2b91af;">FSItem</span> <span style="font-weight:bold;color:#1f377f;">fSItem</span>) : <span style="color:blue;">this</span>(<span style="font-weight:bold;color:#1f377f;">fSItem</span>, [])
{
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">FSItem</span> FSItem { <span style="color:blue;">get</span>; }
<span style="color:blue;">public</span> <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">FSCrumb</span>> Breadcrumbs { <span style="color:blue;">get</span>; }
<span style="color:green;">// Methods follow here...</span></pre>
</p>
<p>
True to the style I've already established, I've made the master constructor <code>private</code> in order to highlight that the <code>Breadcrumbs</code> are the responsibility of the <code>FSZipper</code> class itself. It's not something client code need worry about.
</p>
<h3 id="5dd35bee62764a3fb455c406f1a63754">
Going down <a href="#5dd35bee62764a3fb455c406f1a63754">#</a>
</h3>
<p>
The Haskell Zippers article introduces <code>fsUp</code> before <code>fsTo</code>, but if we want to see some example code, we need to navigate <em>to</em> somewhere before we can navigate up. Thus, I'll instead start with the function that navigates to a child node.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">FSZipper</span>? <span style="font-weight:bold;color:#74531f;">GoTo</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">name</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> FSItem.<span style="font-weight:bold;color:#74531f;">Match</span>(
(<span style="font-weight:bold;color:#1f377f;">_</span>, <span style="font-weight:bold;color:#1f377f;">_</span>) => <span style="color:blue;">null</span>,
(<span style="font-weight:bold;color:#1f377f;">folderName</span>, <span style="font-weight:bold;color:#1f377f;">items</span>) =>
{
<span style="color:#2b91af;">FSItem</span>? <span style="font-weight:bold;color:#1f377f;">item</span> = <span style="color:blue;">null</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">ls</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">List</span><<span style="color:#2b91af;">FSItem</span>>();
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">rs</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">List</span><<span style="color:#2b91af;">FSItem</span>>();
<span style="font-weight:bold;color:#8f08c4;">foreach</span> (<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">i</span> <span style="font-weight:bold;color:#8f08c4;">in</span> <span style="font-weight:bold;color:#1f377f;">items</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">item</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span> && <span style="font-weight:bold;color:#1f377f;">i</span>.<span style="font-weight:bold;color:#74531f;">IsNamed</span>(<span style="font-weight:bold;color:#1f377f;">name</span>))
<span style="font-weight:bold;color:#1f377f;">item</span> = <span style="font-weight:bold;color:#1f377f;">i</span>;
<span style="font-weight:bold;color:#8f08c4;">else</span> <span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">item</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#1f377f;">ls</span>.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="font-weight:bold;color:#1f377f;">i</span>);
<span style="font-weight:bold;color:#8f08c4;">else</span>
<span style="font-weight:bold;color:#1f377f;">rs</span>.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="font-weight:bold;color:#1f377f;">i</span>);
}
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">item</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">FSZipper</span>(
<span style="font-weight:bold;color:#1f377f;">item</span>,
Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Prepend</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">FSCrumb</span>(<span style="font-weight:bold;color:#1f377f;">folderName</span>, <span style="font-weight:bold;color:#1f377f;">ls</span>, <span style="font-weight:bold;color:#1f377f;">rs</span>)).<span style="font-weight:bold;color:#74531f;">ToList</span>());
});
}</pre>
</p>
<p>
This is by far the most complicated navigation we've seen so far, and I've even taken the liberty of writing an imperative implementation. It's not that I don't know how I could implement it in a purely functional fashion, but I've chosen this implementation for a couple of reasons. The first of which is that, frankly, it was easier this way.
</p>
<p>
This stems from the second reason: That the .NET base class library, as far as I know, offers no functionality like Haskell's <a href="https://hackage.haskell.org/package/base/docs/Data-List.html#v:break">break</a> function. I could have written such a function myself, but felt that it was too much of a digression, even for me. Maybe I'll do that another day. It might make for <a href="/2020/01/13/on-doing-katas">a nice little exercise</a>.
</p>
<p>
The third reason is that <a href="/2011/10/11/CheckingforexactlyoneiteminasequenceusingCandF">C# doesn't afford pattern matching on sequences</a>, in the shape of destructuring the head and the tail of a list. (Not that I know of, anyway, but that language changes rapidly at the moment, and it does have <em>some</em> pattern-matching features now.) This means that I have to check <code>item</code> for <code>null</code> anyway.
</p>
<p>
In any case, while the implementation is imperative, an external caller can't tell. The <code>GoTo</code> method is still <a href="https://en.wikipedia.org/wiki/Referential_transparency">referentially transparent</a>. Which means that <a href="/2021/07/28/referential-transparency-fits-in-your-head">it fits in your head</a>.
</p>
<p>
You may have noticed that the implementation calls <code>IsNamed</code>, which is also new.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">IsNamed</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">name</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#74531f;">Match</span>((<span style="font-weight:bold;color:#1f377f;">n</span>, <span style="font-weight:bold;color:#1f377f;">_</span>) => <span style="font-weight:bold;color:#1f377f;">n</span> == <span style="font-weight:bold;color:#1f377f;">name</span>, (<span style="font-weight:bold;color:#1f377f;">n</span>, <span style="font-weight:bold;color:#1f377f;">_</span>) => <span style="font-weight:bold;color:#1f377f;">n</span> == <span style="font-weight:bold;color:#1f377f;">name</span>);
}</pre>
</p>
<p>
This is an instance method I added to <code>FSItem</code>.
</p>
<p>
In summary, the <code>GoTo</code> method enables client code to navigate down in the file hierarchy, as this unit test demonstrates:
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">GoToSkullMan</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">FSZipper</span>(myDisk);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GoTo</span>(<span style="color:#a31515;">"pics"</span>)?.<span style="font-weight:bold;color:#74531f;">GoTo</span>(<span style="color:#a31515;">"skull_man(scary).bmp"</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">NotNull</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"skull_man(scary).bmp"</span>, <span style="color:#a31515;">"Yikes!"</span>),
<span style="font-weight:bold;color:#1f377f;">actual</span>.FSItem);
}</pre>
</p>
<p>
The example is elementary. First go to the <code>pics</code> folder, and from there to the <code>skull_man(scary).bmp</code>.
</p>
<h3 id="be9c842baa2c4cbb8afc50fdb9ea13c7">
Going up <a href="#be9c842baa2c4cbb8afc50fdb9ea13c7">#</a>
</h3>
<p>
Going back up the hierarchy isn't as complicated.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">FSZipper</span>? <span style="font-weight:bold;color:#74531f;">GoUp</span>()
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (Breadcrumbs.Count == 0)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">head</span> = Breadcrumbs.<span style="font-weight:bold;color:#74531f;">First</span>();
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">tail</span> = Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Skip</span>(1);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">FSZipper</span>(
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="font-weight:bold;color:#1f377f;">head</span>.Name, [.. <span style="font-weight:bold;color:#1f377f;">head</span>.Left, FSItem, .. <span style="font-weight:bold;color:#1f377f;">head</span>.Right]),
<span style="font-weight:bold;color:#1f377f;">tail</span>.<span style="font-weight:bold;color:#74531f;">ToList</span>());
}</pre>
</p>
<p>
If the <code>Breadcrumbs</code> collection is empty, we're already at the root, in which case we can't go further up. In that case, the <code>GoUp</code> method returns <code>null</code>, as does the <code>GoTo</code> method if it can't find an item with the desired name. This possibility is explicitly indicated by the <code><span style="color:#2b91af;">FSZipper</span>?</code> return type; notice the question mark, <a href="https://learn.microsoft.com/dotnet/csharp/nullable-references">which indicates that the value may be null</a>. If you're working in a context or language where that feature isn't available, you may instead consider taking advantage of the <a href="/2022/04/25/the-maybe-monad">Maybe monad</a> (which is also what you'd <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatically</a> do in Haskell).
</p>
<p>
If <code>Breadcrumbs</code> is <em>not</em> empty, it means that there's a place to go up to. It also implies that the previous operation navigated down, and the only way that's possible is if the previous node was a folder. Thus, the <code>GoUp</code> method knows that it needs to reconstitute a folder, and from the <code>head</code> breadcrumb, it knows that folder's name, and what was originally to the <code>Left</code> and <code>Right</code> of the Zipper's <code>FSItem</code> property.
</p>
<p>
This unit test demonstrates how client code may use the <code>GoUp</code> method:
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">GoUpFromSkullMan</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">FSZipper</span>(myDisk);
<span style="color:green;">// This is the same as the GoToSkullMan test</span>
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">newFocus</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GoTo</span>(<span style="color:#a31515;">"pics"</span>)?.<span style="font-weight:bold;color:#74531f;">GoTo</span>(<span style="color:#a31515;">"skull_man(scary).bmp"</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">newFocus</span>?.<span style="font-weight:bold;color:#74531f;">GoUp</span>()?.<span style="font-weight:bold;color:#74531f;">GoTo</span>(<span style="color:#a31515;">"watermelon_smash.gif"</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">NotNull</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"watermelon_smash.gif"</span>, <span style="color:#a31515;">"smash!!"</span>),
<span style="font-weight:bold;color:#1f377f;">actual</span>.FSItem);
}</pre>
</p>
<p>
This test first repeats the navigation also performed by the other test, then uses <code>GoUp</code> to go one level up, which finally enables it to navigate to the <code>watermelon_smash.gif</code> file.
</p>
<h3 id="7c96d9a847f04adfb660973e66246d13">
Renaming a file or folder <a href="#7c96d9a847f04adfb660973e66246d13">#</a>
</h3>
<p>
A Zipper enables you to navigate a data structure, but you can also use it to modify the element in focus. One option is to rename a file or folder.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">FSZipper</span> <span style="font-weight:bold;color:#74531f;">Rename</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">newName</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">FSZipper</span>(
FSItem.<span style="font-weight:bold;color:#74531f;">Match</span>(
(<span style="font-weight:bold;color:#1f377f;">_</span>, <span style="font-weight:bold;color:#1f377f;">dat</span>) => <span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="font-weight:bold;color:#1f377f;">newName</span>, <span style="font-weight:bold;color:#1f377f;">dat</span>),
(<span style="font-weight:bold;color:#1f377f;">_</span>, <span style="font-weight:bold;color:#1f377f;">items</span>) => <span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="font-weight:bold;color:#1f377f;">newName</span>, <span style="font-weight:bold;color:#1f377f;">items</span>)),
Breadcrumbs);
}</pre>
</p>
<p>
The <code>Rename</code> method 'pattern-matches' on the 'current' <code>FSItem</code> and in both cases creates a new file or folder with the new name. Since it doesn't need the old name for anything, it uses the wildcard pattern to ignore that value. This operation is always possible, so the return type is <code>FSZipper</code>, without a question mark, indicating that the method never returns <code>null</code>.
</p>
<p>
The following unit test replicates the Haskell article's example by renaming the <code>pics</code> folder to <code>cspi</code>.
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">RenamePics</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">FSZipper</span>(myDisk);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GoTo</span>(<span style="color:#a31515;">"pics"</span>)?.<span style="font-weight:bold;color:#74531f;">Rename</span>(<span style="color:#a31515;">"cspi"</span>).<span style="font-weight:bold;color:#74531f;">GoUp</span>();
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">NotNull</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Empty</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>.Breadcrumbs);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"root"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"goat_yelling_like_man.wmv"</span>, <span style="color:#a31515;">"baaaaaa"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"pope_time.avi"</span>, <span style="color:#a31515;">"god bless"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"cspi"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"ape_throwing_up.jpg"</span>, <span style="color:#a31515;">"bleargh"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"watermelon_smash.gif"</span>, <span style="color:#a31515;">"smash!!"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"skull_man(scary).bmp"</span>, <span style="color:#a31515;">"Yikes!"</span>)
]),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"dijon_poupon.doc"</span>, <span style="color:#a31515;">"best mustard"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"programs"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"fartwizard.exe"</span>, <span style="color:#a31515;">"10gotofart"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"owl_bandit.dmg"</span>, <span style="color:#a31515;">"mov eax, h00t"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"not_a_virus.exe"</span>, <span style="color:#a31515;">"really not a virus"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"source code"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"best_hs_prog.hs"</span>, <span style="color:#a31515;">"main = print (fix error)"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"random.hs"</span>, <span style="color:#a31515;">"main = print 4"</span>)
])
])
]),
<span style="font-weight:bold;color:#1f377f;">actual</span>.FSItem);
}</pre>
</p>
<p>
Since the test uses <code>GoUp</code> after <code>Rename</code>, the <code>actual</code> value contains the entire tree, while the <code>Breadcrumbs</code> collection is empty.
</p>
<h3 id="827bcbd5632844fa97b2a92e8beb17cf">
Adding a new file <a href="#827bcbd5632844fa97b2a92e8beb17cf">#</a>
</h3>
<p>
Finally, we can add a new file to a folder.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">FSZipper</span>? <span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:#2b91af;">FSItem</span> <span style="font-weight:bold;color:#1f377f;">item</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> FSItem.<span style="font-weight:bold;color:#74531f;">Match</span><<span style="color:#2b91af;">FSZipper</span>?>(
<span style="font-weight:bold;color:#1f377f;">whenFile</span>: (<span style="font-weight:bold;color:#1f377f;">_</span>, <span style="font-weight:bold;color:#1f377f;">_</span>) => <span style="color:blue;">null</span>,
<span style="font-weight:bold;color:#1f377f;">whenFolder</span>: (<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">items</span>) => <span style="color:blue;">new</span> <span style="color:#2b91af;">FSZipper</span>(
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="font-weight:bold;color:#1f377f;">name</span>, <span style="font-weight:bold;color:#1f377f;">items</span>.<span style="font-weight:bold;color:#74531f;">Prepend</span>(<span style="font-weight:bold;color:#1f377f;">item</span>).<span style="font-weight:bold;color:#74531f;">ToList</span>()),
Breadcrumbs));
}</pre>
</p>
<p>
This operation may fail, since we can't add a file to a file. This is, again, clearly indicated by the return type, which allows <code>null</code>.
</p>
<p>
This implementation adds the file to the start of the folder, but it would also be possible to add it at the end. I would consider that slightly more idiomatic in C#, but here I've followed the Haskell example code, which conses the new <code>item</code> to the beginning of the list. As is idiomatic in Haskell.
</p>
<p>
The following unit test reproduces the Haskell article's example.
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">AddPic</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">FSZipper</span>(myDisk);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GoTo</span>(<span style="color:#a31515;">"pics"</span>)?.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"heh.jpg"</span>, <span style="color:#a31515;">"lol"</span>))?.<span style="font-weight:bold;color:#74531f;">GoUp</span>();
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">NotNull</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"root"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"goat_yelling_like_man.wmv"</span>, <span style="color:#a31515;">"baaaaaa"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"pope_time.avi"</span>, <span style="color:#a31515;">"god bless"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"pics"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"heh.jpg"</span>, <span style="color:#a31515;">"lol"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"ape_throwing_up.jpg"</span>, <span style="color:#a31515;">"bleargh"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"watermelon_smash.gif"</span>, <span style="color:#a31515;">"smash!!"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"skull_man(scary).bmp"</span>, <span style="color:#a31515;">"Yikes!"</span>)
]),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"dijon_poupon.doc"</span>, <span style="color:#a31515;">"best mustard"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"programs"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"fartwizard.exe"</span>, <span style="color:#a31515;">"10gotofart"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"owl_bandit.dmg"</span>, <span style="color:#a31515;">"mov eax, h00t"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"not_a_virus.exe"</span>, <span style="color:#a31515;">"really not a virus"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFolder</span>(<span style="color:#a31515;">"source code"</span>,
[
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"best_hs_prog.hs"</span>, <span style="color:#a31515;">"main = print (fix error)"</span>),
<span style="color:#2b91af;">FSItem</span>.<span style="color:#74531f;">CreateFile</span>(<span style="color:#a31515;">"random.hs"</span>, <span style="color:#a31515;">"main = print 4"</span>)
])
])
]),
<span style="font-weight:bold;color:#1f377f;">actual</span>.FSItem);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Empty</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>.Breadcrumbs);
}</pre>
</p>
<p>
This example also follows the edit with a <code>GoUp</code> call, with the effect that the Zipper is once more focused on the entire tree. The assertion verifies that the new <code>heh.jpg</code> file is the first file in the <code>pics</code> folder.
</p>
<h3 id="18720e9e88d94384921a2b664b4e0a7a">
Conclusion <a href="#18720e9e88d94384921a2b664b4e0a7a">#</a>
</h3>
<p>
The code for <code>FSZipper</code> is actually a bit simpler than for the binary tree. This, I think, is mostly attributable to the <code>FSZipper</code> having fewer constituent sum types. While sum types are trivial, and extraordinarily useful in languages that natively support them, they require a lot of boilerplate in a language like C#.
</p>
<p>
Do you need something like <code>FSZipper</code> in C#? Probably not. As I've already discussed, this article series mostly exists as a programming exercise.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Functor productshttps://blog.ploeh.dk/2024/09/16/functor-products2024-09-16T06:08:00+00:00Mark Seemann
<div id="post">
<p>
<em>A tuple or class of functors is also a functor. An article for object-oriented developers.</em>
</p>
<p>
This article is part of <a href="/2022/07/11/functor-relationships">a series of articles about functor relationships</a>. In this one you'll learn about a universal composition of <a href="/2018/03/22/functors">functors</a>. In short, if you have a <a href="https://en.wikipedia.org/wiki/Product_type">product type</a> of functors, that data structure itself gives rise to a functor.
</p>
<p>
Together with other articles in this series, this result can help you answer questions such as: <em>Does this data structure form a functor?</em>
</p>
<p>
Since functors tend to be quite common, and since they're useful enough that many programming languages have special support or syntax for them, the ability to recognize a potential functor can be useful. Given a type like <code>Foo<T></code> (C# syntax) or <code>Bar<T1, T2></code>, being able to recognize it as a functor can come in handy. One scenario is if you yourself have just defined such a data type. Recognizing that it's a functor strongly suggests that you should give it a <code>Select</code> method in C#, a <code>map</code> function in <a href="https://fsharp.org/">F#</a>, and so on.
</p>
<p>
Not all generic types give rise to a (covariant) functor. Some are rather <a href="/2021/09/02/contravariant-functors">contravariant functors</a>, and some are <a href="/2022/08/01/invariant-functors">invariant</a>.
</p>
<p>
If, on the other hand, you have a data type which is a product of two or more (covariant) functors <em>with the same type parameter</em>, then the data type itself gives rise to a functor. You'll see some examples in this article.
</p>
<h3 id="9fc25288b4504ff3b4fabe932ecf2ea2">
Abstract shape <a href="#9fc25288b4504ff3b4fabe932ecf2ea2">#</a>
</h3>
<p>
Before we look at some examples found in other code, it helps if we know what we're looking for. Most (if not all?) languages support product types. In canonical form, they're just tuples of values, but in an object-oriented language like C#, such types are typically classes.
</p>
<p>
Imagine that you have two functors <code>F</code> and <code>G</code>, and you're now considering a data structure that contains a value of both types.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">FAndG</span><<span style="color:#2b91af;">T</span>>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">FAndG</span>(<span style="color:#2b91af;">F</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">f</span>, <span style="color:#2b91af;">G</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">g</span>)
{
F = <span style="font-weight:bold;color:#1f377f;">f</span>;
G = <span style="font-weight:bold;color:#1f377f;">g</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">F</span><<span style="color:#2b91af;">T</span>> F { <span style="color:blue;">get</span>; }
<span style="color:blue;">public</span> <span style="color:#2b91af;">G</span><<span style="color:#2b91af;">T</span>> G { <span style="color:blue;">get</span>; }
<span style="color:green;">// Methods go here...</span></pre>
</p>
<p>
The name of the type is <code><span style="color:#2b91af;">FAndG</span><<span style="color:#2b91af;">T</span>></code> because it contains both an <code><span style="color:#2b91af;">F</span><<span style="color:#2b91af;">T</span>></code> object and a <code><span style="color:#2b91af;">G</span><<span style="color:#2b91af;">T</span>></code> object.
</p>
<p>
Notice that it's an essential requirement that the individual functors (here <code>F</code> and <code>G</code>) are parametrized by the same type parameter (here <code>T</code>). If your data structure contains <code><span style="color:#2b91af;">F</span><<span style="color:#2b91af;">T1</span>></code> and <code><span style="color:#2b91af;">G</span><<span style="color:#2b91af;">T2</span>></code>, the following 'theorem' doesn't apply.
</p>
<p>
The point of this article is that such an <code><span style="color:#2b91af;">FAndG</span><<span style="color:#2b91af;">T</span>></code> data structure forms a functor. The <code>Select</code> implementation is quite unsurprising:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">FAndG</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#74531f;">Select</span><<span style="color:#2b91af;">TResult</span>>(<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">selector</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">FAndG</span><<span style="color:#2b91af;">TResult</span>>(F.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">selector</span>), G.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">selector</span>));
}</pre>
</p>
<p>
Since we've assumed that both <code>F</code> and <code>G</code> already are functors, they must come with some projection function. In C# it's <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatically</a> called <code>Select</code>, while in F# it'd typically be called <code>map</code>:
</p>
<p>
<pre><span style="color:green;">// ('a -> 'b) -> FAndG<'a> -> FAndG<'b></span>
<span style="color:blue;">let</span> <span style="color:#74531f;">map</span> <span style="color:#74531f;">f</span> <span style="font-weight:bold;color:#1f377f;">fandg</span> = { F = <span style="color:#2b91af;">F</span>.<span style="color:#74531f;">map</span> <span style="color:#74531f;">f</span> <span style="font-weight:bold;color:#1f377f;">fandg</span>.F; G = <span style="color:#2b91af;">G</span>.<span style="color:#74531f;">map</span> <span style="color:#74531f;">f</span> <span style="font-weight:bold;color:#1f377f;">fandg</span>.G }</pre>
</p>
<p>
assuming a record type like
</p>
<p>
<pre><span style="color:blue;">type</span> <span style="color:#2b91af;">FAndG</span><<span style="color:#2b91af;">'a</span>> = { F : <span style="color:#2b91af;">F</span><<span style="color:#2b91af;">'a</span>>; G : <span style="color:#2b91af;">G</span><<span style="color:#2b91af;">'a</span>> }</pre>
</p>
<p>
In both the C# <code>Select</code> example and the F# <code>map</code> function, the composed functor passes the function argument (<code>selector</code> or <code>f</code>) to both <code>F</code> and <code>G</code> and uses it to map both constituents. It then composes a new product from these individual results.
</p>
<p>
I'll have more to say about how this generalizes to a product of more than two functors, but first, let's consider some examples.
</p>
<h3 id="e3b18df7ac4440d7aada000ce27044f3">
List Zipper <a href="#e3b18df7ac4440d7aada000ce27044f3">#</a>
</h3>
<p>
One of the simplest example I can think of is a List Zipper, which <a href="https://learnyouahaskell.com/zippers">in Haskell</a> is nothing but a type alias of a tuple of lists:
</p>
<p>
<pre><span style="color:blue;">type</span> ListZipper a = ([a],[a])</pre>
</p>
<p>
In the article <a href="/2024/08/26/a-list-zipper-in-c">A List Zipper in C#</a> you saw how the <code><span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>></code> class composes two <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>></code> objects.
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> values;
<span style="color:blue;">public</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> Breadcrumbs { <span style="color:blue;">get</span>; }
<span style="color:blue;">private</span> <span style="color:#2b91af;">ListZipper</span>(<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">values</span>, <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">breadcrumbs</span>)
{
<span style="color:blue;">this</span>.values = <span style="font-weight:bold;color:#1f377f;">values</span>;
Breadcrumbs = <span style="font-weight:bold;color:#1f377f;">breadcrumbs</span>;
}</pre>
</p>
<p>
Since we already know that sequences like <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>></code> form functors, we now know that so must <code><span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>></code>. And indeed, the <code>Select</code> implementation looks similar to the above 'shape outline'.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#74531f;">Select</span><<span style="color:#2b91af;">TResult</span>>(<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">selector</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">TResult</span>>(values.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">selector</span>), Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">selector</span>));
}</pre>
</p>
<p>
It passes the <code>selector</code> function to the <code>Select</code> method of both <code>values</code> and <code>Breadcrumbs</code>, and composes the results into a <code><span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">TResult</span>></code>.
</p>
<p>
While this example is straightforward, it may not be the most compelling, because <code><span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>></code> composes two identical functors: <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>></code>. The knowledge that functors compose is more general than that.
</p>
<h3 id="051a4cc14ad74c2ca2f62fd12051f97c">
Non-empty collection <a href="#051a4cc14ad74c2ca2f62fd12051f97c">#</a>
</h3>
<p>
Next after the above List Zipper, the simplest example I can think of is a non-empty list. On this blog I originally introduced it in the article <a href="/2017/12/11/semigroups-accumulate">Semigroups accumulate</a>, but here I'll use the variant from <a href="/2023/08/07/nonempty-catamorphism">NonEmpty catamorphism</a>. It composes a single value of the type <code>T</code> with an <code><span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">T</span>></code>.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">NonEmptyCollection</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">head</span>, <span style="color:blue;">params</span> <span style="color:#2b91af;">T</span>[] <span style="font-weight:bold;color:#1f377f;">tail</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">head</span> == <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ArgumentNullException</span>(<span style="color:blue;">nameof</span>(<span style="font-weight:bold;color:#1f377f;">head</span>));
<span style="color:blue;">this</span>.Head = <span style="font-weight:bold;color:#1f377f;">head</span>;
<span style="color:blue;">this</span>.Tail = <span style="font-weight:bold;color:#1f377f;">tail</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">T</span> Head { <span style="color:blue;">get</span>; }
<span style="color:blue;">public</span> <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">T</span>> Tail { <span style="color:blue;">get</span>; }</pre>
</p>
<p>
The <code>Tail</code>, being an <code><span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">T</span>></code>, easily forms a functor, since it's a kind of list. But what about <code>Head</code>, which is a 'naked' <code>T</code> value? Does that form a functor? If so, which one?
</p>
<p>
Indeed, a 'naked' <code>T</code> value is isomorphic to <a href="/2018/09/03/the-identity-functor">the Identity functor</a>. This situation is an example of how knowing about the Identity functor is useful, even if you never actually write code that uses it. Once you realize that <code>T</code> is equivalent with a functor, you've now established that <code><span style="color:#2b91af;">NonEmptyCollection</span><<span style="color:#2b91af;">T</span>></code> composes two functors. Therefore, it must itself form a functor, and you realize that you can give it a <code>Select</code> method.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">NonEmptyCollection</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#74531f;">Select</span><<span style="color:#2b91af;">TResult</span>>(<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">selector</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">NonEmptyCollection</span><<span style="color:#2b91af;">TResult</span>>(<span style="font-weight:bold;color:#1f377f;">selector</span>(Head), Tail.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">selector</span>).<span style="font-weight:bold;color:#74531f;">ToArray</span>());
}</pre>
</p>
<p>
Notice that even though we understand that <code>T</code> is equivalent to the Identity functor, there's no reason to actually wrap <code>Head</code> in an <code><span style="color:#2b91af;">Identity</span><<span style="color:#2b91af;">T</span>></code> <a href="https://bartoszmilewski.com/2014/01/14/functors-are-containers/">container</a> just to call <code>Select</code> on it and unwrap the result. Rather, the above <code>Select</code> implementation directly invokes <code>selector</code> with <code>Head</code>. It is, after all, a function that takes a <code>T</code> value as input and returns a <code>TResult</code> object as output.
</p>
<h3 id="d721c5ba6eda4016be1417ea01105bea">
Ranges <a href="#d721c5ba6eda4016be1417ea01105bea">#</a>
</h3>
<p>
It's hard to come up with an example that's both somewhat compelling and realistic, and at the same time prototypically pure. Stripped of all 'noise' functor products are just tuples, but that hardly makes for a compelling example. On the other hand, most other examples I can think of combine results about functors where they compose in more than one way. Not only as products, but also as sums of functors, as well as nested compositions. You'll be able to read about these in future articles, but for the next examples, you'll have to accept some claims about functors at face value.
</p>
<p>
In <a href="/2024/02/12/range-as-a-functor">Range as a functor</a> you saw how both <code><span style="color:#2b91af;">Endpoint</span><<span style="color:#2b91af;">T</span>></code> and <code><span style="color:#2b91af;">Range</span><<span style="color:#2b91af;">T</span>></code> are functors. The article shows functor implementations for each, in both C#, F#, and <a href="https://www.haskell.org/">Haskell</a>. For now we'll ignore the deeper underlying reason why <code><span style="color:#2b91af;">Endpoint</span><<span style="color:#2b91af;">T</span>></code> forms a functor, and instead focus on <code><span style="color:#2b91af;">Range</span><<span style="color:#2b91af;">T</span>></code>.
</p>
<p>
In Haskell I never defined an explicit <code>Range</code> type, but rather just treated ranges as tuples. As stated repeatedly already, tuples are the essential products, so if you accept that <code>Endpoint</code> gives rise to a functor, then a 'range tuple' does, too.
</p>
<p>
In F# <code>Range</code> is defined like this:
</p>
<p>
<pre><span style="color:blue;">type</span> Range<'a> = { LowerBound : Endpoint<'a>; UpperBound : Endpoint<'a> }</pre>
</p>
<p>
Such a record type is also easily identified as a product type. In a sense, we can think of a record type as a 'tuple with metadata', where the metadata contains <em>names</em> of elements.
</p>
<p>
In C# <code><span style="color:#2b91af;">Range</span><<span style="color:#2b91af;">T</span>></code> is a class with two <code><span style="color:#2b91af;">Endpoint</span><<span style="color:#2b91af;">T</span>></code> fields.
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Endpoint</span><<span style="color:#2b91af;">T</span>> min;
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Endpoint</span><<span style="color:#2b91af;">T</span>> max;
<span style="color:blue;">public</span> <span style="color:#2b91af;">Range</span>(<span style="color:#2b91af;">Endpoint</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">min</span>, <span style="color:#2b91af;">Endpoint</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">max</span>)
{
<span style="color:blue;">this</span>.min = <span style="font-weight:bold;color:#1f377f;">min</span>;
<span style="color:blue;">this</span>.max = <span style="font-weight:bold;color:#1f377f;">max</span>;
}</pre>
</p>
<p>
In a sense, you can think of such an immutable class as equivalent to a record type, only requiring substantial <a href="/2019/12/16/zone-of-ceremony">ceremony</a>. The point is that because a range is a product of two functors, it itself gives rise to a functor. You can see all the implementations in <a href="/2024/02/12/range-as-a-functor">Range as a functor</a>.
</p>
<h3 id="25e4dea36f644217ba1e28f2a509f3ab">
Binary tree Zipper <a href="#25e4dea36f644217ba1e28f2a509f3ab">#</a>
</h3>
<p>
In <a href="/2024/09/09/a-binary-tree-zipper-in-c">A Binary Tree Zipper in C#</a> you saw that the <code><span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>></code> class has two class fields:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> Tree { <span style="color:blue;">get</span>; }
<span style="color:blue;">public</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">Crumb</span><<span style="color:#2b91af;">T</span>>> Breadcrumbs { <span style="color:blue;">get</span>; }</pre>
</p>
<p>
Both have the same generic type parameter <code>T</code>, so the question is whether <code><span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>></code> may form a functor? We now know that the answer is affirmative if <code><span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></code> and <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">Crumb</span><<span style="color:#2b91af;">T</span>>></code> are both functors.
</p>
<p>
For now, believe me when I claim that this is the case. This means that you can add a <code>Select</code> method to the class:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#74531f;">Select</span><<span style="color:#2b91af;">TResult</span>>(<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">selector</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">TResult</span>>(
Tree.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">selector</span>),
Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">c</span> => <span style="font-weight:bold;color:#1f377f;">c</span>.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">selector</span>)));
}</pre>
</p>
<p>
By now, this should hardly be surprising: Call <code>Select</code> on each constituent functor and create a proper return value from the results.
</p>
<h3 id="1179fc33850d430780c843583c16adcb">
Higher arities <a href="#1179fc33850d430780c843583c16adcb">#</a>
</h3>
<p>
All examples have involved products of only two functors, but the result generalizes to higher arities. To gain an understanding of why, consider that it's always possible to rewrite tuples of higher arities as nested pairs. As an example, a triple like <code>(42, <span style="color:#a31515;">"foo"</span>, True)</code> can be rewritten as <code>(42, (<span style="color:#a31515;">"foo"</span>, True))</code> without loss of information. The latter representation is a pair (a two-tuple) where the first element is <code>42</code>, but the second element is another pair. These two representations are isomorphic, meaning that we can go back and forth without losing data.
</p>
<p>
By induction you can generalize this result to any arity. The point is that the only data type you need to describe a product is a pair.
</p>
<p>
Haskell's <a href="https://hackage.haskell.org/package/base">base</a> library defines a specialized container called <a href="https://hackage.haskell.org/package/base/docs/Data-Functor-Product.html">Product</a> for this very purpose: If you have two <code>Functor</code> instances, you can <code>Pair</code> them up, and they become a single <code>Functor</code>.
</p>
<p>
Let's start with a <code>Pair</code> of <code>Maybe</code> and a list:
</p>
<p>
<pre>ghci> Pair (Just "foo") ["bar", "baz", "qux"]
Pair (Just "foo") ["bar","baz","qux"]</pre>
</p>
<p>
This is a single 'object', if you will, that composes those two <code>Functor</code> instances. This means that you can map over it:
</p>
<p>
<pre>ghci> elem 'b' <$> Pair (Just "foo") ["bar", "baz", "qux"]
Pair (Just False) [True,True,False]</pre>
</p>
<p>
Here I've used the infix <code><$></code> operator as an alternative to <code>fmap</code>. By composing with <code>elem 'b'</code>, I'm asking every value inside the container whether or not it contains the character <code>b</code>. The <code>Maybe</code> value doesn't, while the first two list elements do.
</p>
<p>
If you want to compose three, rather than two, <code>Functor</code> instances, you just nest the <code>Pairs</code>, just like you can nest tuples:
</p>
<p>
<pre>ghci> elem 'b' <$> Pair (Identity "quux") (Pair (Just "foo") ["bar", "baz", "qux"])
Pair (Identity False) (Pair (Just False) [True,True,False])</pre>
</p>
<p>
This example now introduces the <code>Identity</code> container as a third <code>Functor</code> instance. I could have used any other <code>Functor</code> instance instead of <code>Identity</code>, but some of them are more awkward to create or display. For example, the <a href="/2021/08/30/the-reader-functor">Reader</a> or <a href="/2021/07/19/the-state-functor">State</a> functors have no <code>Show</code> instances in Haskell, meaning that GHCi doesn't know how to print them as values. Other <code>Functor</code> instances didn't work as well for the example, since they tend to be more awkward to create. As an example, any non-trivial <a href="https://hackage.haskell.org/package/containers/docs/Data-Tree.html#t:Tree">Tree</a> requires substantial editor space to express.
</p>
<h3 id="329c3274f8f54171905d747867fc293b">
Conclusion <a href="#329c3274f8f54171905d747867fc293b">#</a>
</h3>
<p>
A product of functors may itself be made a functor. The examples shown in this article are all constrained to two functors, but if you have a product of three, four, or more functors, that product still gives rise to a functor.
</p>
<p>
This is useful to know, particularly if you're working in a language with only partial support for functors. Mainstream languages aren't going to automatically turn such products into functors, in the way that Haskell's <code>Product</code> container almost does. Thus, knowing when you can safely give your generic types a <code>Select</code> method or <code>map</code> function may come in handy.
</p>
<p>
There are more rules like this one. The next article examines another.
</p>
<p>
<strong>Next:</strong> Functor sums.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.A Binary Tree Zipper in C#https://blog.ploeh.dk/2024/09/09/a-binary-tree-zipper-in-c2024-09-09T06:09:00+00:00Mark Seemann
<div id="post">
<p>
<em>A port of another Haskell example, still just because.</em>
</p>
<p>
This article is part of <a href="/2024/08/19/zippers">a series about Zippers</a>. In this one, I port the <code>Zipper</code> data structure from the <a href="https://learnyouahaskell.com/">Learn You a Haskell for Great Good!</a> article also called <a href="https://learnyouahaskell.com/zippers">Zippers</a>.
</p>
<p>
A word of warning: I'm assuming that you're familiar with the contents of that article, so I'll skip the pedagogical explanations; I can hardly do it better that it's done there. Additionally, I'll make heavy use of certain standard constructs to port <a href="https://www.haskell.org/">Haskell</a> code, most notably <a href="/2018/05/22/church-encoding">Church encoding</a> to model <a href="https://en.wikipedia.org/wiki/Tagged_union">sum types</a> in languages that don't natively have them. Such as C#. In some cases, I'll implement the Church encoding using the data structure's <a href="/2019/04/29/catamorphisms">catamorphism</a>. Since the <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> of the resulting code is quite low, you may be able to follow what's going on even if you don't know what Church encoding or catamorphisms are, but if you want to understand the background and motivation for that style of programming, you can consult the cited resources.
</p>
<p>
The code shown in this article is <a href="https://github.com/ploeh/CSharpZippers">available on GitHub</a>.
</p>
<h3 id="e612adde6ff2487ebd026c858f36233f">
Binary tree initialization and structure <a href="#e612adde6ff2487ebd026c858f36233f">#</a>
</h3>
<p>
In the Haskell code, the binary <code>Tree</code> type is a recursive <a href="https://en.wikipedia.org/wiki/Tagged_union">sum type</a>, defined on a single line of code. C#, on the other hand, has no built-in language construct that supports sum types, so a more elaborate solution is required. At least two options are available to us. One is to <a href="/2018/06/25/visitor-as-a-sum-type">model a sum type as a Visitor</a>. Another is to use <a href="/2018/05/22/church-encoding">Church encoding</a>. In this article, I'll do the latter.
</p>
<p>
I find the type name (<code>Tree</code>) used in the Zippers article a bit too vague, and since I consider <a href="https://peps.python.org/pep-0020/">explicit better than implicit</a>, I'll use a more precise class name:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></pre>
</p>
<p>
Even so, there are different kinds of binary trees. In <a href="/2019/06/24/full-binary-tree-catamorphism">a previous article</a> I've shown a catamorphism for a <em>full <a href="https://en.wikipedia.org/wiki/Binary_tree">binary tree</a></em>. This variation is not as strict, since it allows a node to have zero, one, or two children. Or, strictly speaking, a node always has exactly two children, but both, or one of them, may be empty. <code><span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></code> uses Church encoding to distinguish between the two, but we'll return to that in a moment.
</p>
<p>
First, we'll examine how the class allows initialization:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">IBinaryTree</span> root;
<span style="color:blue;">private</span> <span style="color:#2b91af;">BinaryTree</span>(<span style="color:#2b91af;">IBinaryTree</span> <span style="font-weight:bold;color:#1f377f;">root</span>)
{
<span style="color:blue;">this</span>.root = <span style="font-weight:bold;color:#1f377f;">root</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTree</span>() : <span style="color:blue;">this</span>(<span style="color:#2b91af;">Empty</span>.Instance)
{
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTree</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">value</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">left</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">right</span>)
: <span style="color:blue;">this</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">Node</span>(<span style="font-weight:bold;color:#1f377f;">value</span>, <span style="font-weight:bold;color:#1f377f;">left</span>.root, <span style="font-weight:bold;color:#1f377f;">right</span>.root))
{
}</pre>
</p>
<p>
The class uses a <code>private</code> <code>root</code> object to implement behaviour, and constructor chaining for initialization. The master constructor is <code>private</code>, since the <code>IBinaryTree</code> interface is <code>private</code>. The parameterless constructor implicitly indicates an empty node, whereas the other <code>public</code> constructor indicates a node with a value and two children. Yes, I know that I just wrote that explicit is better than implicit, but it turns out that with the <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/operators/new-operator">target-typed <code>new</code></a> operator feature in C#, constructing trees in code becomes easier with this design choice:
</p>
<p>
<pre><span style="color:#2b91af;">BinaryTree</span><<span style="color:blue;">int</span>> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span>(
42,
<span style="color:blue;">new</span>(),
<span style="color:blue;">new</span>(2, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>()));</pre>
</p>
<p>
As <a href="/2020/11/30/name-by-role">the variable name suggests</a>, I've taken this code example from a unit test.
</p>
<h3 id="57fddbbeebc44489b3ebc0c4fd7c0d9f">
Private interface <a href="#57fddbbeebc44489b3ebc0c4fd7c0d9f">#</a>
</h3>
<p>
The class delegates method calls to the <code>root</code> field, which is an instance of the <code>private</code>, nested <code>IBinaryTree</code> interface:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">interface</span> <span style="color:#2b91af;">IBinaryTree</span>
{
<span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenEmpty</span>,
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">TResult</span>, <span style="color:#2b91af;">TResult</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenNode</span>);
}</pre>
</p>
<p>
Why is <code>IBinaryTree</code> a <code>private</code> interface? Why does that interface even exist?
</p>
<p>
To be frank, I could have chosen another implementation strategy. Since there's only two mutually exclusive alternatives (<em>node</em> or <em>empty</em>), I could also have indicated which is which with a Boolean flag. You can see an example of that implementation tactic in the <code>Table</code> class in the sample code that accompanies <a href="/2021/06/14/new-book-code-that-fits-in-your-head">Code That Fits in Your Head</a>.
</p>
<p>
Using a Boolean flag, however, only works when there are exactly two choices. If you have three or more, things because more complicated. You could try to use an <a href="https://en.wikipedia.org/wiki/Enumerated_type">enum</a>, but in most languages, these tend to be nothing but glorified integers, and are typically not type-safe. If you define a three-way enum, there's no guarantee that a value of that type takes only one of these three values, and a good compiler will typically insist that you check for any other value as well. The C# compiler certainly does.
</p>
<p>
Church encoding offers a better alternative, but since it makes use of polymorphism, the most <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatic</a> choice in C# is either an interface or a base class. Since I favour interfaces over base classes, that's what I've chosen here, but for the purposes of this little digression, it makes no difference: The following argument applies to base classes as well.
</p>
<p>
An interface (or base class) suggests to users of an API that they can implement it in order to extend behaviour. That's an impression I don't wish to give client developers. The purpose of the interface is exclusively to enable <a href="https://en.wikipedia.org/wiki/Double_dispatch">double dispatch</a> to work. There's only two implementations of the <code>IBinaryTree</code> interface, and under no circumstances should there be more.
</p>
<p>
The interface is an implementation detail, which is why both it, and its implementations, are <code>private</code>.
</p>
<h3 id="72ecf86f028f482ebcdb02e914e4cd06">
Binary tree catamorphism <a href="#72ecf86f028f482ebcdb02e914e4cd06">#</a>
</h3>
<p>
The <code>IBinaryTree</code> interface defines a catamorphism for the <code><span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></code> class. Since we may often view a catamorphism as a sort of 'generalized fold', and since these kinds of operations in C# are typically called <code>Aggregate</code>, that's what I've called the method.
</p>
<p>
An aggregate function affords a way to traverse a data structure and collect information into a single value, here of type <code>TResult</code>. The return type may, however, be a complex type, including another <code><span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></code>. You'll see examples of complex return values later in this article.
</p>
<p>
As already discussed, there are exactly two implementations of <code>IBinaryTree</code>. The one representing an empty node is the simplest:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">Empty</span> : <span style="color:#2b91af;">IBinaryTree</span>
{
<span style="color:blue;">public</span> <span style="color:blue;">readonly</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">Empty</span> Instance = <span style="color:blue;">new</span>();
<span style="color:blue;">private</span> <span style="color:#2b91af;">Empty</span>()
{
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenEmpty</span>,
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">TResult</span>, <span style="color:#2b91af;">TResult</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenNode</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">whenEmpty</span>();
}
}</pre>
</p>
<p>
The <code>Aggregate</code> implementation unconditionally calls the supplied <code>whenEmpty</code> function, which returns some <code>TResult</code> value unknown to the <code>Empty</code> class.
</p>
<p>
Although not strictly necessary, I've made the class a <a href="https://en.wikipedia.org/wiki/Singleton_pattern">Singleton</a>. Since I like to <a href="/2021/05/03/structural-equality-for-better-tests">take advantage of structural equality to write better tests</a>, it was either that, or overriding <code>Equals</code> and <code>GetHashCode</code>.
</p>
<p>
The other implementation gets around that problem by being a <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/record">record</a>:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">record</span> <span style="color:#2b91af;">Node</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">Value</span>, <span style="color:#2b91af;">IBinaryTree</span> <span style="font-weight:bold;color:#1f377f;">Left</span>, <span style="color:#2b91af;">IBinaryTree</span> <span style="font-weight:bold;color:#1f377f;">Right</span>) : <span style="color:#2b91af;">IBinaryTree</span>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenEmpty</span>,
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">TResult</span>, <span style="color:#2b91af;">TResult</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenNode</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">whenNode</span>(
Value,
Left.<span style="font-weight:bold;color:#74531f;">Aggregate</span>(<span style="font-weight:bold;color:#1f377f;">whenEmpty</span>, <span style="font-weight:bold;color:#1f377f;">whenNode</span>),
Right.<span style="font-weight:bold;color:#74531f;">Aggregate</span>(<span style="font-weight:bold;color:#1f377f;">whenEmpty</span>, <span style="font-weight:bold;color:#1f377f;">whenNode</span>));
}
}</pre>
</p>
<p>
It, too, unconditionally calls one of the two functions passed to its <code>Aggregate</code> method, but this time <code>whenNode</code>. It does that, however, by first <em>recursively</em> calling <code>Aggregate</code> on both <code>Left</code> and <code>Right</code>. It needs to do that because the <code>whenNode</code> function expects the subtrees to have been already converted to values of the <code>TResult</code> return type. This is a common pattern with catamorphisms, and takes a bit of time getting used to. You can see similar examples in the articles <a href="/2019/06/10/tree-catamorphism">Tree catamorphism</a>, <a href="/2019/08/05/rose-tree-catamorphism">Rose tree catamorphism</a>, and <a href="/2019/06/24/full-binary-tree-catamorphism">Full binary tree catamorphism</a>.
</p>
<p>
The <code><span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></code> class defines a <code>public</code> <code>Aggregate</code> method that delegates to its <code>root</code> field:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Aggregate</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenEmpty</span>,
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">TResult</span>, <span style="color:#2b91af;">TResult</span>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenNode</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> root.<span style="font-weight:bold;color:#74531f;">Aggregate</span>(<span style="font-weight:bold;color:#1f377f;">whenEmpty</span>, <span style="font-weight:bold;color:#1f377f;">whenNode</span>);
}</pre>
</p>
<p>
The astute reader may now remark that the <code>Aggregate</code> method doesn't look like a Church encoding.
</p>
<h3 id="e99e9074e04e416c82a7345574d4944b">
Binary tree Church encoding <a href="#e99e9074e04e416c82a7345574d4944b">#</a>
</h3>
<p>
A Church encoding will typically have a <code>Match</code> method that enables client code to match on all the alternative cases in the sum type, without those confusing already-converted <code>TResult</code> values. It turns out that you can implement the desired <code>Match</code> method with the <code>Aggregate</code> method.
</p>
<p>
One of the advantages of doing meaningless coding exercises like this one is that you can pursue various ideas that interest you. One idea that interests me is the potential universality of catamorphisms. I conjecture that a catamorphism is an <a href="https://en.wikipedia.org/wiki/Algebraic_data_type">algebraic data type</a>'s universal API, and that you can implement all other methods or functions with it. I admit that I haven't done much research in the form of perusing existing literature, but at least it seems to be the case conspicuously often.
</p>
<p>
As it is here.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Match</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenEmpty</span>,
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenNode</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> root
.<span style="font-weight:bold;color:#74531f;">Aggregate</span>(
() => (tree: <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>(), result: <span style="font-weight:bold;color:#1f377f;">whenEmpty</span>()),
(<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">l</span>, <span style="font-weight:bold;color:#1f377f;">r</span>) => (
<span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">l</span>.tree, <span style="font-weight:bold;color:#1f377f;">r</span>.tree),
<span style="font-weight:bold;color:#1f377f;">whenNode</span>(<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">l</span>.tree, <span style="font-weight:bold;color:#1f377f;">r</span>.tree)))
.result;
}</pre>
</p>
<p>
Now, I readily admit that it took me a couple of hours tossing and turning in my bed before this solution came to me. I don't find it intuitive at all, but it works.
</p>
<p>
The <code>Aggregate</code> method requires that the <code>whenNode</code> function's <em>left</em> and <em>right</em> values are of <em>the same</em> <code>TResult</code> type as the return type. How do we consolidate that requirement with the <code>Match</code> method's variation, where <em>its</em> <code>whenNode</code> function requires the <em>left</em> and <em>right</em> values to be <code><span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></code> values, but the return type still <code>TResult</code>?
</p>
<p>
The way out of this conundrum, it turns out, is to combine both in a tuple. Thus, when <code>Match</code> calls <code>Aggregate</code>, the implied <code>TResult</code> type is <em>not</em> the <code>TResult</code> visible in the <code>Match</code> method declaration. Rather, it's inferred to be of the type <code>(<span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>)</code>. That is, a tuple where the first element is a <code><span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></code> value, and the second element is a <code><span style="color:#2b91af;">TResult</span></code> value. The C# compiler's type inference engine then figures out that <code>(<span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>)</code> must also be the return type of the <code>Aggregate</code> method call.
</p>
<p>
That's not what <code>Match</code> should return, but the second tuple element contains a value of the correct type, so it returns that. Since I've given the tuple elements names, the <code>Match</code> implementation accomplishes that by returning the <code>result</code> tuple field.
</p>
<h3 id="816773c095624bfcb5cced827ba76455">
Breadcrumbs <a href="#816773c095624bfcb5cced827ba76455">#</a>
</h3>
<p>
That's just the tree that we want to zip. So far, we can only move from root to branches, but not the other way. Before we can define a Zipper for the tree, we need a data structure to store breadcrumbs (the navigation log, if you will).
</p>
<p>
In Haskell it's just another one-liner, but in C# this requires another full-fledged class:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">Crumb</span><<span style="color:#2b91af;">T</span>></pre>
</p>
<p>
It's another sum type, so once more, I make the constructor private and use a <code>private</code> class field for the implementation:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">ICrumb</span> imp;
<span style="color:blue;">private</span> <span style="color:#2b91af;">Crumb</span>(<span style="color:#2b91af;">ICrumb</span> <span style="font-weight:bold;color:#1f377f;">imp</span>)
{
<span style="color:blue;">this</span>.imp = <span style="font-weight:bold;color:#1f377f;">imp</span>;
}
<span style="color:blue;">internal</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">Crumb</span><<span style="color:#2b91af;">T</span>> <span style="color:#74531f;">Left</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">value</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">right</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">LeftCrumb</span>(<span style="font-weight:bold;color:#1f377f;">value</span>, <span style="font-weight:bold;color:#1f377f;">right</span>));
}
<span style="color:blue;">internal</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">Crumb</span><<span style="color:#2b91af;">T</span>> <span style="color:#74531f;">Right</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">value</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">left</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">RightCrumb</span>(<span style="font-weight:bold;color:#1f377f;">value</span>, <span style="font-weight:bold;color:#1f377f;">left</span>));
}</pre>
</p>
<p>
To stay consistent throughout the code base, I also use Church encoding to distinguish between a <code>Left</code> and <code>Right</code> breadcrumb, and the technique is similar. First, define a <code>private</code> interface:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">interface</span> <span style="color:#2b91af;">ICrumb</span>
{
<span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Match</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenLeft</span>,
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenRight</span>);
}</pre>
</p>
<p>
Then, use <code>private</code> nested types to implement the interface.
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">record</span> <span style="color:#2b91af;">LeftCrumb</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">Value</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">Right</span>) : <span style="color:#2b91af;">ICrumb</span>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Match</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenLeft</span>,
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenRight</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">whenLeft</span>(Value, Right);
}
}</pre>
</p>
<p>
The <code>RightCrumb</code> record is essentially just the 'mirror image' of the <code>LeftCrumb</code> record, and just as was the case with <code><span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>></code>, the <code><span style="color:#2b91af;">Crumb</span><<span style="color:#2b91af;">T</span>></code> class exposes an externally accessible <code>Match</code> method that just delegates to the <code>private</code> class field:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">TResult</span> <span style="font-weight:bold;color:#74531f;">Match</span><<span style="color:#2b91af;">TResult</span>>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenLeft</span>,
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>, <span style="color:#2b91af;">TResult</span>> <span style="font-weight:bold;color:#1f377f;">whenRight</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> imp.<span style="font-weight:bold;color:#74531f;">Match</span>(<span style="font-weight:bold;color:#1f377f;">whenLeft</span>, <span style="font-weight:bold;color:#1f377f;">whenRight</span>);
}</pre>
</p>
<p>
Finally, all the building blocks are ready for the actual Zipper.
</p>
<h3 id="f345665355144ccfbbc5767d75f48ece">
Zipper data structure and initialization <a href="#f345665355144ccfbbc5767d75f48ece">#</a>
</h3>
<p>
In the Haskell code, the Zipper is another one-liner, and really just a type alias. In C#, once more, we're going to need a full class.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>></pre>
</p>
<p>
The Haskell article simply calls this type alias <code>Zipper</code>, but I find that name too general, since there's more than one kind of Zipper. I think I understand that the article chooses that name for didactic reasons, but here I've chosen a more consistent disambiguation scheme, so I've named the class <code><span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>></code>.
</p>
<p>
The Haskell example is just a type alias for a tuple, and the C# class is similar, although with significantly more <a href="/2019/12/16/zone-of-ceremony">ceremony</a>:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> Tree { <span style="color:blue;">get</span>; }
<span style="color:blue;">public</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">Crumb</span><<span style="color:#2b91af;">T</span>>> Breadcrumbs { <span style="color:blue;">get</span>; }
<span style="color:blue;">private</span> <span style="color:#2b91af;">BinaryTreeZipper</span>(
<span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">tree</span>,
<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">Crumb</span><<span style="color:#2b91af;">T</span>>> <span style="font-weight:bold;color:#1f377f;">breadcrumbs</span>)
{
Tree = <span style="font-weight:bold;color:#1f377f;">tree</span>;
Breadcrumbs = <span style="font-weight:bold;color:#1f377f;">breadcrumbs</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTreeZipper</span>(<span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">tree</span>) : <span style="color:blue;">this</span>(<span style="font-weight:bold;color:#1f377f;">tree</span>, [])
{
}</pre>
</p>
<p>
I've here chosen to add an extra bit of <a href="/2022/10/24/encapsulation-in-functional-programming">encapsulation</a> by making the master constructor <code>private</code>. This prevents client code from creating an arbitrary object with breadcrumbs without having navigated through the tree. To be honest, I don't think it violates any contract even if we allow this, but it at least highlights that the <code>Breadcrumbs</code> role is to keep a log of what previously happened to the object.
</p>
<h3 id="9cafe5fe05cd4d619b8d50cd3a86f549">
Navigation <a href="#9cafe5fe05cd4d619b8d50cd3a86f549">#</a>
</h3>
<p>
We can now reproduce the navigation functions from the Haskell article.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>? <span style="font-weight:bold;color:#74531f;">GoLeft</span>()
{
<span style="font-weight:bold;color:#8f08c4;">return</span> Tree.<span style="font-weight:bold;color:#74531f;">Match</span><<span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>?>(
<span style="font-weight:bold;color:#1f377f;">whenEmpty</span>: () => <span style="color:blue;">null</span>,
<span style="font-weight:bold;color:#1f377f;">whenNode</span>: (<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">l</span>, <span style="font-weight:bold;color:#1f377f;">r</span>) => <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>(
<span style="font-weight:bold;color:#1f377f;">l</span>,
Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Prepend</span>(<span style="color:#2b91af;">Crumb</span>.<span style="color:#74531f;">Left</span>(<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">r</span>))));
}</pre>
</p>
<p>
Going left 'pattern-matches' on the <code>Tree</code> and, if not empty, constructs a new <code>BinaryTreeZipper</code> object with the left tree, and a <code>Left</code> breadcrumb that stores the 'current' node value and the right subtree. If the 'current' node is empty, on the other hand, the method returns <code>null</code>. This possibility is explicitly indicated by the <code><span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>?</code> return type; notice the question mark, <a href="https://learn.microsoft.com/dotnet/csharp/nullable-references">which indicates that the value may be null</a>. If you're working in a context or language where that feature isn't available, you may instead consider taking advantage of the <a href="/2022/04/25/the-maybe-monad">Maybe monad</a> (which is also what you'd <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatically</a> do in Haskell).
</p>
<p>
The <code>GoRight</code> method is similar to <code>GoLeft</code>.
</p>
<p>
We may also attempt to navigate up in the tree, undoing our last downward move:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>? <span style="font-weight:bold;color:#74531f;">GoUp</span>()
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Any</span>())
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">head</span> = Breadcrumbs.<span style="font-weight:bold;color:#74531f;">First</span>();
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">tail</span> = Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Skip</span>(1);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">head</span>.<span style="font-weight:bold;color:#74531f;">Match</span>(
<span style="font-weight:bold;color:#1f377f;">whenLeft</span>: (<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">r</span>) => <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>(
<span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">x</span>, Tree, <span style="font-weight:bold;color:#1f377f;">r</span>),
<span style="font-weight:bold;color:#1f377f;">tail</span>),
<span style="font-weight:bold;color:#1f377f;">whenRight</span>: (<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">l</span>) => <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>(
<span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">l</span>, Tree),
<span style="font-weight:bold;color:#1f377f;">tail</span>));
}</pre>
</p>
<p>
This is another operation that may fail. If we're already at the root of the tree, there are no <code>Breadcrumbs</code>, in which case the only option is to return a value indicating that the operation failed; here, <code>null</code>, but in other languages perhaps <code>None</code> or <code>Nothing</code>.
</p>
<p>
If, on the other hand, there's at least one breadcrumb, the <code>GoUp</code> method uses the most recent one (<code>head</code>) to construct a new <code><span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>></code> object that reconstitutes the opposite (sibling) subtree and the parent node. It does that by 'pattern-matching' on the <code>head</code> breadcrumb, which enables it to distinguish a left breadcrumb from a right breadcrumb.
</p>
<p>
Finally, we may keep trying to <code>GoUp</code> until we reach the root:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#74531f;">TopMost</span>()
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#74531f;">GoUp</span>()?.<span style="font-weight:bold;color:#74531f;">TopMost</span>() ?? <span style="color:blue;">this</span>;
}</pre>
</p>
<p>
You'll see an example of that a little later.
</p>
<h3 id="56a16be50dc4405d8931e9210895b5a0">
Modifications <a href="#56a16be50dc4405d8931e9210895b5a0">#</a>
</h3>
<p>
Continuing the port of the Haskell code, we can <code>Modify</code> the current node with a function:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#74531f;">Modify</span>(<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">T</span>, <span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">f</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>(
Tree.<span style="font-weight:bold;color:#74531f;">Match</span>(
<span style="font-weight:bold;color:#1f377f;">whenEmpty</span>: () => <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>(),
<span style="font-weight:bold;color:#1f377f;">whenNode</span>: (<span style="font-weight:bold;color:#1f377f;">x</span>, <span style="font-weight:bold;color:#1f377f;">l</span>, <span style="font-weight:bold;color:#1f377f;">r</span>) => <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">f</span>(<span style="font-weight:bold;color:#1f377f;">x</span>), <span style="font-weight:bold;color:#1f377f;">l</span>, <span style="font-weight:bold;color:#1f377f;">r</span>)),
Breadcrumbs);
}</pre>
</p>
<p>
This operation always succeeds, since it chooses to ignore the change if the tree is empty. Thus, there's no question mark on the return type, indicating that the method never returns <code>null</code>.
</p>
<p>
Finally, we may replace a node with a new subtree:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#74531f;">Attach</span>(<span style="color:#2b91af;">BinaryTree</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">tree</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">tree</span>, Breadcrumbs);
}</pre>
</p>
<p>
The following unit test demonstrates a combination of several of the methods shown above:
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">AttachAndGoTopMost</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">BinaryTreeZipper</span><<span style="color:blue;">char</span>>(freeTree);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">farLeft</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GoLeft</span>()?.<span style="font-weight:bold;color:#74531f;">GoLeft</span>()?.<span style="font-weight:bold;color:#74531f;">GoLeft</span>()?.<span style="font-weight:bold;color:#74531f;">GoLeft</span>();
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">farLeft</span>?.<span style="font-weight:bold;color:#74531f;">Attach</span>(<span style="color:blue;">new</span>(<span style="color:#a31515;">'Z'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>())).<span style="font-weight:bold;color:#74531f;">TopMost</span>();
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">NotNull</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(
<span style="color:blue;">new</span>(<span style="color:#a31515;">'P'</span>,
<span style="color:blue;">new</span>(<span style="color:#a31515;">'O'</span>,
<span style="color:blue;">new</span>(<span style="color:#a31515;">'L'</span>,
<span style="color:blue;">new</span>(<span style="color:#a31515;">'N'</span>,
<span style="color:blue;">new</span>(<span style="color:#a31515;">'Z'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>()),
<span style="color:blue;">new</span>()),
<span style="color:blue;">new</span>(<span style="color:#a31515;">'T'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>())),
<span style="color:blue;">new</span>(<span style="color:#a31515;">'Y'</span>,
<span style="color:blue;">new</span>(<span style="color:#a31515;">'S'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>()),
<span style="color:blue;">new</span>(<span style="color:#a31515;">'A'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>()))),
<span style="color:blue;">new</span>(<span style="color:#a31515;">'L'</span>,
<span style="color:blue;">new</span>(<span style="color:#a31515;">'W'</span>,
<span style="color:blue;">new</span>(<span style="color:#a31515;">'C'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>()),
<span style="color:blue;">new</span>(<span style="color:#a31515;">'R'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>())),
<span style="color:blue;">new</span>(<span style="color:#a31515;">'A'</span>,
<span style="color:blue;">new</span>(<span style="color:#a31515;">'A'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>()),
<span style="color:blue;">new</span>(<span style="color:#a31515;">'C'</span>, <span style="color:blue;">new</span>(), <span style="color:blue;">new</span>())))),
<span style="font-weight:bold;color:#1f377f;">actual</span>.Tree);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Empty</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>.Breadcrumbs);
}</pre>
</p>
<p>
The test starts with <code>freeTree</code> (not shown) and first navigates to the leftmost empty node. Here it uses <code>Attach</code> to add a new 'singleton' subtree with the value <code>'Z'</code>. Finally, it uses <code>TopMost</code> to return to the root node.
</p>
<p>
In <a href="/2013/06/24/a-heuristic-for-formatting-code-according-to-the-aaa-pattern">the Assert phase</a>, the test verifies that the <code>actual</code> object contains the expected values.
</p>
<h3 id="8eaa9438655f4bcbb9447796a7ed7154">
Conclusion <a href="#8eaa9438655f4bcbb9447796a7ed7154">#</a>
</h3>
<p>
The Tree Zipper shown here is a port of the example given in the Haskell <a href="https://learnyouahaskell.com/zippers">Zippers article</a>. As I've already discussed in the <a href="/2024/08/19/zippers">introduction article</a>, this data structure doesn't make much sense in C#, where you can easily implement a navigable tree with two-way links. Even if this requires state mutation, you can package such a data structure in a proper object with good <a href="/encapsulation-and-solid">encapsulation</a>, so that operations don't leave any dangling pointers or the like.
</p>
<p>
As far as I can tell, the code shown in this article isn't useful in production code, but I hope that, at least, you still learned something from it. I always learn a new thing or two from <a href="/2020/01/13/on-doing-katas">doing programming exercises</a> and writing about them, and this was no exception.
</p>
<p>
In the next article, I continue with the final of the Haskell article's three examples.
</p>
<p>
<strong>Next:</strong> <a href="/2024/09/23/fszipper-in-c">FSZipper in C#</a>.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Keeping cross-cutting concerns out of application codehttps://blog.ploeh.dk/2024/09/02/keeping-cross-cutting-concerns-out-of-application-code2024-09-02T06:19:00+00:00Mark Seemann
<div id="post">
<p>
<em>Don't inject third-party dependencies. Use Decorators.</em>
</p>
<p>
I recently came across <a href="https://stackoverflow.com/q/78887199/126014">a Stack Overflow question</a> that reminded me of a topic I've been meaning to write about for a long time: <a href="https://en.wikipedia.org/wiki/Cross-cutting_concern">Cross-cutting concerns</a>.
</p>
<p>
When it comes to <a href="https://en.wikipedia.org/wiki/Casablanca_(film)">the usual suspects</a>, logging, fault tolerance, caching, the best solution is usually to apply the <a href="https://en.wikipedia.org/wiki/Decorator_pattern">Decorator pattern</a>.
</p>
<p>
I often see code that uses Dependency Injection (DI) to inject, say, a logging interface into application code. You can see an example of that in <a href="/2020/03/23/repeatable-execution">Repeatable execution</a>, as well as a suggestion for a better design. Not surprisingly, the better design involves logging Decorators.
</p>
<p>
The Stack Overflow question isn't about logging, but rather about fault tolerance; <a href="https://martinfowler.com/bliki/CircuitBreaker.html">Circuit Breaker</a>, retry policies, timeouts, etc.
</p>
<h3 id="02d07297ea6341c6aef55c0fcb76678c">
Injected concern <a href="#02d07297ea6341c6aef55c0fcb76678c">#</a>
</h3>
<p>
The question does a good job of presenting a minimal, reproducible example. At the outset, the code looks like this:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">MyApi</span>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">ResiliencePipeline</span> pipeline;
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">IOrganizationService</span> service;
<span style="color:blue;">public</span> <span style="color:#2b91af;">MyApi</span>(<span style="color:#2b91af;">ResiliencePipelineProvider</span><<span style="color:blue;">string</span>> <span style="font-weight:bold;color:#1f377f;">provider</span>, <span style="color:#2b91af;">IOrganizationService</span> <span style="font-weight:bold;color:#1f377f;">service</span>)
{
<span style="color:blue;">this</span>.pipeline = <span style="font-weight:bold;color:#1f377f;">provider</span>.<span style="font-weight:bold;color:#74531f;">GetPipeline</span>(<span style="color:#a31515;">"retry-pipeline"</span>);
<span style="color:blue;">this</span>.service = <span style="font-weight:bold;color:#1f377f;">service</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">List</span><<span style="color:blue;">string</span>> <span style="font-weight:bold;color:#74531f;">GetSomething</span>(<span style="color:#2b91af;">QueryByAttribute</span> <span style="font-weight:bold;color:#1f377f;">query</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">result</span> = <span style="color:blue;">this</span>.pipeline.<span style="font-weight:bold;color:#74531f;">Execute</span>(() => service.<span style="font-weight:bold;color:#74531f;">RetrieveMultiple</span>(<span style="font-weight:bold;color:#1f377f;">query</span>));
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">result</span>.Entities.<span style="font-weight:bold;color:#74531f;">Cast</span><<span style="color:blue;">string</span>>().<span style="font-weight:bold;color:#74531f;">ToList</span>();
}
}</pre>
</p>
<p>
The Stack Overflow question asks how to test this implementation, but I'd rather take the example as an opportunity to discuss design alternatives. Not surprisingly, it turns out that with a more decoupled design, testing becomes easier, too.
</p>
<p>
Before we proceed, a few words about this example code. I assume that this isn't <a href="https://stackoverflow.com/users/3805597">Andy Cooke</a>'s actual production code. Rather, I interpret it as a reduced example that highlights the actual question. This is important because you might ask: <em>Why bother testing two lines of code?</em>
</p>
<p>
Indeed, as presented, the <code>GetSomething</code> method is <a href="/2018/11/12/what-to-test-and-not-to-test">so simple that you may consider not testing it</a>. Thus, I interpret the second line of code as a stand-in for more complicated production code. Hold on to that thought, because once I'm done, that's all that's going to be left, and you may then think that it's so simple that it really doesn't warrant all this hoo-ha.
</p>
<h3 id="32211a755e0a4b9bbd04a049ddbba0c8">
Coupling <a href="#32211a755e0a4b9bbd04a049ddbba0c8">#</a>
</h3>
<p>
As shown, the <code>MyApi</code> class is coupled to <a href="https://www.thepollyproject.org/">Polly</a>, because <code>ResiliencePipeline</code> is defined by that library. To be clear, all I've heard is that Polly is a fine library. I've used it for a few projects myself, but I also admit that I haven't that much experience with it. I'd probably use it again the next time I need a Circuit Breaker or similar, so the following discussion isn't a denouncement of Polly. Rather, it applies to all third-party dependencies, or perhaps even dependencies that are part of your language's base library.
</p>
<p>
Coupling is a major cause of <a href="https://en.wikipedia.org/wiki/Spaghetti_code">spaghetti code</a> and code rot in general. To write sustainable code, you should be cognizant of coupling. The most decoupled code is <a href="/2022/11/21/decouple-to-delete">code that you can easily delete</a>.
</p>
<p>
This doesn't mean that you shouldn't use high-quality third-party libraries like Polly. Among myriads of software engineering heuristics, we know that we should be aware of the <a href="https://en.wikipedia.org/wiki/Not_invented_here">not-invented-here syndrome</a>.
</p>
<p>
When it comes to classic cross-cutting concerns, the Decorator pattern is usually a better design than injecting the concern into application code. The above example clearly looks innocuous, but imagine injecting both a <code>ResiliencePipeline</code>, a logger, and perhaps a caching service, and your real application code eventually disappears in 'infrastructure code'.
</p>
<p>
It's not that we don't want to have these third-party dependencies, but rather that we want to move them somewhere else.
</p>
<h3 id="67a215289ba944b984b4d113b10e419c">
Resilient Decorator <a href="#67a215289ba944b984b4d113b10e419c">#</a>
</h3>
<p>
The concern in the above example is the desire to make the <code>IOrganizationService</code> dependency more resilient. The <code>MyApi</code> class only becomes more resilient as a transitive effect. The first refactoring step, then, is to introduce a resilient Decorator.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">ResilientOrganizationService</span>(
<span style="color:#2b91af;">ResiliencePipeline</span> <span style="font-weight:bold;color:#1f377f;">pipeline</span>,
<span style="color:#2b91af;">IOrganizationService</span> <span style="font-weight:bold;color:#1f377f;">inner</span>) : <span style="color:#2b91af;">IOrganizationService</span>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">QueryResult</span> <span style="font-weight:bold;color:#74531f;">RetrieveMultiple</span>(<span style="color:#2b91af;">QueryByAttribute</span> <span style="font-weight:bold;color:#1f377f;">query</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">pipeline</span>.<span style="font-weight:bold;color:#74531f;">Execute</span>(() => <span style="font-weight:bold;color:#1f377f;">inner</span>.<span style="font-weight:bold;color:#74531f;">RetrieveMultiple</span>(<span style="font-weight:bold;color:#1f377f;">query</span>));
}
}</pre>
</p>
<p>
As Decorators must, this class composes another <code>IOrganizationService</code> while also implementing that interface itself. It does so by being an <a href="https://en.wikipedia.org/wiki/Adapter_pattern">Adapter</a> over the Polly API.
</p>
<p>
I've applied <a href="https://vuscode.wordpress.com/2009/10/16/inversion-of-control-single-responsibility-principle-and-nikola-s-laws-of-dependency-injection/">Nikola Malovic's 4th law of DI</a>:
</p>
<blockquote>
<p>
"Every constructor of a class being resolved should not have any implementation other then accepting a set of its own dependencies."
</p>
<footer><cite><a href="https://vuscode.wordpress.com/2009/10/16/inversion-of-control-single-responsibility-principle-and-nikola-s-laws-of-dependency-injection/">Inversion Of Control, Single Responsibility Principle and Nikola’s laws of dependency injection</a></cite>, Nikola Malovic, 2009</footer>
</blockquote>
<p>
Instead of injecting a <code><span style="color:#2b91af;">ResiliencePipelineProvider</span><<span style="color:blue;">string</span>></code> only to call <code>GetPipeline</code> on it, it just receives a <code>ResiliencePipeline</code> and saves the object for use in the <code>RetrieveMultiple</code> method. It does that via a <a href="https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors">primary constructor</a>, which is a recent C# language addition. It's just syntactic sugar for Constructor Injection, and as usual <a href="https://fsharp.org/">F#</a> developers should feel right at home.
</p>
<h3 id="8e967ac0c4ea4323b280e7a665825903">
Simplifying MyApi <a href="#8e967ac0c4ea4323b280e7a665825903">#</a>
</h3>
<p>
Now that you have a resilient version of <code>IOrganizationService</code> you don't need to have any Polly code in <code>MyApi</code>. Remove it and simplify:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">MyApi</span>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">IOrganizationService</span> service;
<span style="color:blue;">public</span> <span style="color:#2b91af;">MyApi</span>(<span style="color:#2b91af;">IOrganizationService</span> <span style="font-weight:bold;color:#1f377f;">service</span>)
{
<span style="color:blue;">this</span>.service = <span style="font-weight:bold;color:#1f377f;">service</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">List</span><<span style="color:blue;">string</span>> <span style="font-weight:bold;color:#74531f;">GetSomething</span>(<span style="color:#2b91af;">QueryByAttribute</span> <span style="font-weight:bold;color:#1f377f;">query</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">result</span> = service.<span style="font-weight:bold;color:#74531f;">RetrieveMultiple</span>(<span style="font-weight:bold;color:#1f377f;">query</span>);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">result</span>.Entities.<span style="font-weight:bold;color:#74531f;">Cast</span><<span style="color:blue;">string</span>>().<span style="font-weight:bold;color:#74531f;">ToList</span>();
}
}</pre>
</p>
<p>
As promised, there's almost nothing left of it now, but I'll remind you that I consider the second line of <code>GetSomething</code> as a stand-in for something more complicated that you might need to test. As it is now, though, testing it is trivial:
</p>
<p>
<pre>[<span style="color:#2b91af;">Theory</span>]
[<span style="color:#2b91af;">InlineData</span>(<span style="color:#a31515;">"foo"</span>, <span style="color:#a31515;">"bar"</span>, <span style="color:#a31515;">"baz"</span>)]
[<span style="color:#2b91af;">InlineData</span>(<span style="color:#a31515;">"qux"</span>, <span style="color:#a31515;">"quux"</span>, <span style="color:#a31515;">"corge"</span>)]
[<span style="color:#2b91af;">InlineData</span>(<span style="color:#a31515;">"grault"</span>, <span style="color:#a31515;">"garply"</span>, <span style="color:#a31515;">"waldo"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">GetSomething</span>(<span style="color:blue;">params</span> <span style="color:blue;">string</span>[] <span style="font-weight:bold;color:#1f377f;">expected</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">service</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">Mock</span><<span style="color:#2b91af;">IOrganizationService</span>>();
<span style="font-weight:bold;color:#1f377f;">service</span>
.<span style="font-weight:bold;color:#74531f;">Setup</span>(<span style="font-weight:bold;color:#1f377f;">s</span> => <span style="font-weight:bold;color:#1f377f;">s</span>.<span style="font-weight:bold;color:#74531f;">RetrieveMultiple</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">QueryByAttribute</span>()))
.<span style="font-weight:bold;color:#74531f;">Returns</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">QueryResult</span>(<span style="font-weight:bold;color:#1f377f;">expected</span>));
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">MyApi</span>(<span style="font-weight:bold;color:#1f377f;">service</span>.Object);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GetSomething</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">QueryByAttribute</span>());
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(<span style="font-weight:bold;color:#1f377f;">expected</span>, <span style="font-weight:bold;color:#1f377f;">actual</span>);
}</pre>
</p>
<p>
The larger point, however, is that not only have you now managed to keep third-party dependencies out of your application code, you've also simplified it and made it easier to test.
</p>
<h3 id="c9dd80b39e234c6595ef31de1fea30c2">
Composition <a href="#c9dd80b39e234c6595ef31de1fea30c2">#</a>
</h3>
<p>
You can still create a resilient <code>MyApi</code> object in your <a href="/2011/07/28/CompositionRoot">Composition Root</a>:
</p>
<p>
<pre><span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">service</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">ResilientOrganizationService</span>(<span style="font-weight:bold;color:#1f377f;">pipeline</span>, <span style="font-weight:bold;color:#1f377f;">inner</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">myApi</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">MyApi</span>(<span style="font-weight:bold;color:#1f377f;">service</span>);</pre>
</p>
<p>
Decomposing the problem in this way, you decouple your application code from third-party dependencies. You can define <code>ResilientOrganizationService</code> in the application's Composition Root, which also keeps the Polly dependency there. Even so, you can implement <code>MyApi</code> as part of your application layer.
</p>
<p>
<img src="/content/binary/polly-in-outer-shell.png" alt="Three circles arranged in layers. In the outer layer, there's a box labelled 'ResilientOrganizationService' and another box labelled 'Polly'. An arrow points from 'ResilientOrganizationService' to 'Polly'. In the second layer in there's a box labelled 'MyApi'. The inner circle is empty." >
</p>
<p>
I usually illustrate <a href="/2013/12/03/layers-onions-ports-adapters-its-all-the-same">Ports and Adapters</a>, or, if you will, <a href="/ref/clean-architecture">Clean Architecture</a> as concentric circles, but in this diagram I've skewed the circles to make space for the boxes. In other words, the diagram is 'not to scale'. Ideally, the outermost layer is much smaller and thinner than any of the the other layers. I've also included an inner green layer which indicates the architecture's Domain Model, but since I assume that <code>MyApi</code> is part of some application layer, I've left the Domain Model empty.
</p>
<h3 id="ba7304112c214dd6be84011aea811dbf">
Reasons to decouple <a href="#ba7304112c214dd6be84011aea811dbf">#</a>
</h3>
<p>
Why is it important to decouple application code from Polly? First, keep in mind that in this discussion Polly is just a stand-in for any third-party dependency. It's up to you as a software architect to decide how you'll structure your code, but third-party dependencies are one of the first things I look for. A third-party component changes with time, and often independently of your base platform. You may have to deal with breaking changes or security patches at inopportune times. The organization that maintains the component may cease to operate. This happens to commercial entities and open-source contributors alike, although for different reasons.
</p>
<p>
Second, even a top-tier library like Polly will undergo changes. If your time horizon is five to ten years, you'll be surprised how much things change. You may protest that no-one designs software systems with such a long view, but I think that if you ask the business people involved with your software, they most certainly expect your system to last a long time.
</p>
<p>
I believe that I heard on a podcast that some Microsoft teams had taken a dependency on Polly. Assuming, for the sake of argument, that this is true, while we may not wish to depend on some random open-source component, depending on Polly is safe, right? In the long run, it isn't. Five years ago, you had the same situation with <a href="https://www.newtonsoft.com/json">Json.NET</a>, but then Microsoft hired James Newton-King and had him make a JSON API as part of the .NET base library. While Json.NET isn't dead by any means, now you have two competing JSON libraries, and Microsoft uses their own in the frameworks and libraries that they release.
</p>
<p>
Deciding to decouple your application code from a third-party component is ultimately a question of risk management. It's up to you to make the bet. Do you pay the up-front cost of decoupling, or do you postpone it, hoping it'll never be necessary?
</p>
<p>
I usually do the former, because the cost is low, and there are other benefits as well. As I've already touched on, unit testing becomes easier.
</p>
<h3 id="f126ff285a014a6d85cff276436321c8">
Configuration <a href="#f126ff285a014a6d85cff276436321c8">#</a>
</h3>
<p>
Since Polly only lives in the Composition Root, you'll also need to define the <code>ResiliencePipeline</code> there. You can write the code that creates that pieline wherever you like, but it might be natural to make it a creation function on the <code>ResilientOrganizationService</code> class:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">ResiliencePipeline</span> <span style="color:#74531f;">CreatePipeline</span>()
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ResiliencePipelineBuilder</span>()
.<span style="font-weight:bold;color:#74531f;">AddRetry</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">RetryStrategyOptions</span>
{
MaxRetryAttempts = 4
})
.<span style="font-weight:bold;color:#74531f;">AddTimeout</span>(<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromSeconds</span>(1))
.<span style="font-weight:bold;color:#74531f;">Build</span>();
}</pre>
</p>
<p>
That's just an example, and perhaps not what you'd like to do. Perhaps you rather want some of these values to be defined in a configuration file. Thus, this isn't what you <em>have</em> to do, but rather what you <em>could</em> do.
</p>
<p>
If you use this option, however, you could take the return value of this method and inject it into the <code>ResilientOrganizationService</code> constructor.
</p>
<h3 id="11bbc9df98474c33a6ce0902b13178d4">
Conclusion <a href="#11bbc9df98474c33a6ce0902b13178d4">#</a>
</h3>
<p>
Cross-cutting concerns, like caching, logging, security, or, in this case, fault tolerance, are usually best addressed with the Decorator pattern. In this article, you saw an example of using the Decorator pattern to decouple the concern of fault tolerance from the consumer of the service that you need to handle in a fault-tolerant manner.
</p>
<p>
The specific example dealt with the Polly library, but the point isn't that Polly is a particularly nasty third-party component that you need to protect yourself against. Rather, it just so happened that I came across a Stack Overflow question that used Polly, and I though it was a a nice example.
</p>
<p>
As far as I can tell, Polly is actually one of the top .NET open-source packages, so this article is not a denouncement of Polly. It's just a sketch of how to move useful dependencies around in your code base to make sure that they impact your application code as little as possible.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.A List Zipper in C#https://blog.ploeh.dk/2024/08/26/a-list-zipper-in-c2024-08-26T13:19:00+00:00Mark Seemann
<div id="post">
<p>
<em>A port of a Haskell example, just because.</em>
</p>
<p>
This article is part of <a href="/2024/08/19/zippers">a series about Zippers</a>. In this one, I port the <code>ListZipper</code> data structure from the <a href="https://learnyouahaskell.com/">Learn You a Haskell for Great Good!</a> article also called <a href="https://learnyouahaskell.com/zippers">Zippers</a>.
</p>
<p>
A word of warning: I'm assuming that you're familiar with the contents of that article, so I'll skip the pedagogical explanations; I can hardly do it better that it's done there.
</p>
<p>
The code shown in this article is <a href="https://github.com/ploeh/CSharpZippers">available on GitHub</a>.
</p>
<h3 id="04e3cad425414735aff6a3a0507a9855">
Initialization and structure <a href="#04e3cad425414735aff6a3a0507a9855">#</a>
</h3>
<p>
In the Haskell code, <code>ListZipper</code> is just a type alias, but C# doesn't have that, so instead, we'll have to introduce a class.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>> : <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>></pre>
</p>
<p>
Since it implements <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>></code>, it may be used like any other sequence, but it also comes with some special operations that enable client code to move forward and backward, as well as inserting and removing values.
</p>
<p>
The class has the following fields, properties, and constructors:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> values;
<span style="color:blue;">public</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> Breadcrumbs { <span style="color:blue;">get</span>; }
<span style="color:blue;">private</span> <span style="color:#2b91af;">ListZipper</span>(<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">values</span>, <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">breadcrumbs</span>)
{
<span style="color:blue;">this</span>.values = <span style="font-weight:bold;color:#1f377f;">values</span>;
Breadcrumbs = <span style="font-weight:bold;color:#1f377f;">breadcrumbs</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">ListZipper</span>(<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">values</span>) : <span style="color:blue;">this</span>(<span style="font-weight:bold;color:#1f377f;">values</span>, [])
{
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">ListZipper</span>(<span style="color:blue;">params</span> <span style="color:#2b91af;">T</span>[] <span style="font-weight:bold;color:#1f377f;">values</span>) : <span style="color:blue;">this</span>(<span style="font-weight:bold;color:#1f377f;">values</span>.<span style="font-weight:bold;color:#74531f;">AsEnumerable</span>())
{
}</pre>
</p>
<p>
It uses constructor chaining to initialize a <code>ListZipper</code> object with proper <a href="/encapsulation-and-solid">encapsulation</a>. Notice that the master constructor is private. This prevents client code from initializing an object with arbitrary <code>Breadcrumbs</code>. Rather, the <code>Breadcrumbs</code> (the log, if you will) is going to be the result of various operations performed by client code, and only the <code>ListZipper</code> class itself can use this constructor.
</p>
<p>
You may consider the constructor that takes a single <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>></code> as the 'main' <code>public</code> constructor, and the other one as a convenience that enables a client developer to write code like <code><span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"foo"</span>, <span style="color:#a31515;">"bar"</span>, <span style="color:#a31515;">"baz"</span>)</code>.
</p>
<p>
The class' <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>></code> implementation only enumerates the <code>values</code>:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">IEnumerator</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#74531f;">GetEnumerator</span>()
{
<span style="font-weight:bold;color:#8f08c4;">return</span> values.<span style="font-weight:bold;color:#74531f;">GetEnumerator</span>();
}</pre>
</p>
<p>
In other words, when enumerating a <code>ListZipper</code>, you only get the 'forward' <code>values</code>. Client code may still examine the <code>Breadcrumbs</code>, since this is a <code>public</code> property, but it should have little need for that.
</p>
<p>
(I admit that making <code>Breadcrumbs</code> public is a concession to testability, since it enabled me to write assertions against this property. It's a form of <a href="/2013/04/04/structural-inspection">structural inspection</a>, which is a technique that I use much less than I did a decade ago. Still, in this case, while you may argue that it violates <a href="https://en.wikipedia.org/wiki/Information_hiding">information hiding</a>, it at least doesn't allow client code to put an object in an invalid state. Had the <code>ListZipper</code> class been a part of a reusable library, I would probably have hidden that data, too, but since this is exercise code, I found this an acceptable compromise. Notice, too, that in the original Haskell code, the breadcrumbs are available to client code.)
</p>
<p>
Regular readers of this blog may be aware that <a href="/2013/07/20/linq-versus-the-lsp">I usually favour IReadOnlyCollection<T> over IEnumerable<T></a>. Here, on the other hand, I've allowed <code>values</code> to be any <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>></code>, which includes infinite sequences. I decided to do that because Haskell lists, too, may be infinite, and as far as I can tell, <code>ListZipper</code> actually does work with infinite sequences. I have, at least, written a few tests with infinite sequences, and they pass. (I may still have missed an edge case or two. I can't rule that out.)
</p>
<h3 id="908d0fe3cf5d453da3541127ae365d00">
Movement <a href="#908d0fe3cf5d453da3541127ae365d00">#</a>
</h3>
<p>
It's not much fun just being able to initialize an object. You also want to be able to do something with it, such as moving forward:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>? <span style="font-weight:bold;color:#74531f;">GoForward</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">head</span> = values.<span style="font-weight:bold;color:#74531f;">Take</span>(1);
<span style="font-weight:bold;color:#8f08c4;">if</span> (!<span style="font-weight:bold;color:#1f377f;">head</span>.<span style="font-weight:bold;color:#74531f;">Any</span>())
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">tail</span> = values.<span style="font-weight:bold;color:#74531f;">Skip</span>(1);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">tail</span>, <span style="font-weight:bold;color:#1f377f;">head</span>.<span style="font-weight:bold;color:#74531f;">Concat</span>(Breadcrumbs));
}</pre>
</p>
<p>
You can move forward through any <code>IEnumerable</code>, so why make things so complicated? The benefit of this <code>GoForward</code> method (<a href="https://en.wikipedia.org/wiki/Pure_function">function</a>, really) is that it records where it came from, which means that moving backwards becomes an option:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>? <span style="font-weight:bold;color:#74531f;">GoBack</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">head</span> = Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Take</span>(1);
<span style="font-weight:bold;color:#8f08c4;">if</span> (!<span style="font-weight:bold;color:#1f377f;">head</span>.<span style="font-weight:bold;color:#74531f;">Any</span>())
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">tail</span> = Breadcrumbs.<span style="font-weight:bold;color:#74531f;">Skip</span>(1);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">head</span>.<span style="font-weight:bold;color:#74531f;">Concat</span>(values), <span style="font-weight:bold;color:#1f377f;">tail</span>);
}</pre>
</p>
<p>
This test may serve as an example of client code that makes use of those two operations:
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">GoBack1</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:blue;">int</span>>(1, 2, 3, 4);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GoForward</span>()?.<span style="font-weight:bold;color:#74531f;">GoForward</span>()?.<span style="font-weight:bold;color:#74531f;">GoForward</span>()?.<span style="font-weight:bold;color:#74531f;">GoBack</span>();
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>([3, 4], <span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>([2, 1], <span style="font-weight:bold;color:#1f377f;">actual</span>?.Breadcrumbs);
}</pre>
</p>
<p>
Going forward takes the first element off <code>values</code> and adds it to the front of <code>Breadcrumbs</code>. Going backwards is nearly symmetrical: It takes the first element off the <code>Breadcrumbs</code> and adds it back to the front of the <code>values</code>. Used in this way, <code>Breadcrumbs</code> works as a <a href="https://en.wikipedia.org/wiki/Stack_(abstract_data_type)">stack</a>.
</p>
<p>
Notice that both <code>GoForward</code> and <code>GoBack</code> admit the possibility of failure. If <code>values</code> is empty, you can't go forward. If <code>Breadcrumbs</code> is empty, you can't go back. In both cases, the functions return <code>null</code>, which are also indicated by the <code><span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>?</code> return types; notice the question mark, <a href="https://learn.microsoft.com/dotnet/csharp/nullable-references">which indicates that the value may be null</a>. If you're working in a context or language where that feature isn't available, you may instead consider taking advantage of the <a href="/2022/04/25/the-maybe-monad">Maybe monad</a> (which is also what you'd <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatically</a> do in Haskell).
</p>
<p>
To be clear, the <a href="https://learnyouahaskell.com/zippers">Zippers article</a> does discuss handling failures using Maybe, but only applies it to its binary tree example. Thus, the error handling shown here is my own addition.
</p>
<h3 id="704f23586ead4b199b171baa50dfd1da">
Modifications <a href="#704f23586ead4b199b171baa50dfd1da">#</a>
</h3>
<p>
In addition to moving back and forth in the list, we can also modify it. The following operations are also not in the Zippers article, but are rather my own contributions. Adding a new element is easy:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#74531f;">Insert</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">value</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>(values.<span style="font-weight:bold;color:#74531f;">Prepend</span>(<span style="font-weight:bold;color:#1f377f;">value</span>), Breadcrumbs);
}</pre>
</p>
<p>
Notice that this operation is always possible. Even if the list is empty, we can <code>Insert</code> a value. In that case, it just becomes the list's first and only element.
</p>
<p>
A simple test demonstrates usage:
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">InsertAtFocus</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"foo"</span>, <span style="color:#a31515;">"bar"</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GoForward</span>()?.<span style="font-weight:bold;color:#74531f;">Insert</span>(<span style="color:#a31515;">"ploeh"</span>).<span style="font-weight:bold;color:#74531f;">GoBack</span>();
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">NotNull</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>([<span style="color:#a31515;">"foo"</span>, <span style="color:#a31515;">"ploeh"</span>, <span style="color:#a31515;">"bar"</span>], <span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Empty</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>.Breadcrumbs);
}</pre>
</p>
<p>
Likewise, we may attempt to remove an element from the list:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>? <span style="font-weight:bold;color:#74531f;">Remove</span>()
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!values.<span style="font-weight:bold;color:#74531f;">Any</span>())
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>(values.<span style="font-weight:bold;color:#74531f;">Skip</span>(1), Breadcrumbs);
}</pre>
</p>
<p>
Contrary to <code>Insert</code>, the <code>Remove</code> operation will fail if <code>values</code> is empty. Notice that this doesn't necessarily imply that the list as such is empty, but only that the focus is at the end of the list (which, of course, never happens if <code>values</code> is infinite):
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">RemoveAtEnd</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"foo"</span>, <span style="color:#a31515;">"bar"</span>).<span style="font-weight:bold;color:#74531f;">GoForward</span>()?.<span style="font-weight:bold;color:#74531f;">GoForward</span>();
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>?.<span style="font-weight:bold;color:#74531f;">Remove</span>();
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Null</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">NotNull</span>(<span style="font-weight:bold;color:#1f377f;">sut</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Empty</span>(<span style="font-weight:bold;color:#1f377f;">sut</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>([<span style="color:#a31515;">"bar"</span>, <span style="color:#a31515;">"foo"</span>], <span style="font-weight:bold;color:#1f377f;">sut</span>.Breadcrumbs);
}</pre>
</p>
<p>
In this example, the focus is at the end of the list, so there's nothing to remove. The list, however, is not empty, but all the data currently reside in the <code>Breadcrumbs</code>.
</p>
<p>
Finally, we can combine insertion and removal to implement a replacement operation:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>>? <span style="font-weight:bold;color:#74531f;">Replace</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">newValue</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#74531f;">Remove</span>()?.<span style="font-weight:bold;color:#74531f;">Insert</span>(<span style="font-weight:bold;color:#1f377f;">newValue</span>);
}</pre>
</p>
<p>
As the name implies, this operation replaces the value currently in focus with a completely different value. Here's an example:
</p>
<p>
<pre>[<span style="color:#2b91af;">Fact</span>]
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">ReplaceAtFocus</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">ListZipper</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"foo"</span>, <span style="color:#a31515;">"bar"</span>, <span style="color:#a31515;">"baz"</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">actual</span> = <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">GoForward</span>()?.<span style="font-weight:bold;color:#74531f;">Replace</span>(<span style="color:#a31515;">"qux"</span>)?.<span style="font-weight:bold;color:#74531f;">GoBack</span>();
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">NotNull</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>([<span style="color:#a31515;">"foo"</span>, <span style="color:#a31515;">"qux"</span>, <span style="color:#a31515;">"baz"</span>], <span style="font-weight:bold;color:#1f377f;">actual</span>);
<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Empty</span>(<span style="font-weight:bold;color:#1f377f;">actual</span>.Breadcrumbs);
}</pre>
</p>
<p>
Once more, this may fail if the current focus is empty, so <code>Replace</code> also returns a nullable value.
</p>
<h3 id="5979ae4ab42543f79df4e572f7f5c2c3">
Conclusion <a href="#5979ae4ab42543f79df4e572f7f5c2c3">#</a>
</h3>
<p>
For a C# developer, the <code><span style="color:#2b91af;">ListZipper</span><<span style="color:#2b91af;">T</span>></code> class looks odd. Why would you ever want to use this data structure? Why not just use <a href="https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1">List<T></a>?
</p>
<p>
As I hope I've made clear in the <a href="/2024/08/19/zippers">introduction article</a>, I can't, indeed, think of a good reason.
</p>
<p>
I've gone through this exercise <a href="/2020/01/13/on-doing-katas">to hone my skills</a>, and to prepare myself for the more intimidating exercise it is to implement a binary tree Zipper.
</p>
<p>
<strong>Next:</strong> <a href="/2024/09/09/a-binary-tree-zipper-in-c">A Binary Tree Zipper in C#</a>.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Zippershttps://blog.ploeh.dk/2024/08/19/zippers2024-08-19T14:13:00+00:00Mark Seemann
<div id="post">
<p>
<em>Some functional programming examples ported to C#, just because.</em>
</p>
<p>
Many algorithms rely on data structures that enable the implementation to move in more than one way. A simple example is a <a href="https://en.wikipedia.org/wiki/Doubly_linked_list">doubly-linked list</a>, where an algorithm can move both forward and backward from a given element. Other examples are various tree-based algorithms, such as <a href="https://en.wikipedia.org/wiki/Red%E2%80%93black_tree">red-black trees</a> where certain operations trigger reorganization of the tree. Yet other data structures, such as <a href="https://en.wikipedia.org/wiki/Fibonacci_heap">Fibonacci heaps</a>, combine doubly-linked lists with trees that allow navigation in more than one direction.
</p>
<p>
In an imperative programming language, you can easily implement such data structures, as long as the language allows data mutation. Here's a simple example:
</p>
<p>
<pre><span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">node1</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">Node</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"foo"</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">node2</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">Node</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"bar"</span>) { Previous = <span style="font-weight:bold;color:#1f377f;">node1</span> };
<span style="font-weight:bold;color:#1f377f;">node1</span>.Next = <span style="font-weight:bold;color:#1f377f;">node2</span>;</pre>
</p>
<p>
It's possible to double-link <code>node1</code> to <code>node2</code> by first creating <code>node1</code>. At that point, <code>node2</code> still doesn't exist, so you can't yet assign <code><span style="font-weight:bold;color:#1f377f;">node1</span>.Next</code>, but once you've initialized <code>node2</code>, you can mutate the state of <code>node1</code> by changing its <code>Next</code> property.
</p>
<p>
When data structures are immutable (as they must be in functional programming) this is no longer possible. How may you get around that limitation?
</p>
<h3 id="3b3c3d4cba1f4ae8bef462b28047860a">
Alternatives <a href="#3b3c3d4cba1f4ae8bef462b28047860a">#</a>
</h3>
<p>
Some languages get around this problem in various ways. <a href="https://www.haskell.org/">Haskell</a>, because of its lazy evaluation, enables a technique called <a href="https://wiki.haskell.org/Tying_the_Knot">tying the knot</a> that, frankly, makes my head hurt.
</p>
<p>
Even though I write a decent amount of Haskell code, that's not something that I make use of. Usually, it turns out, you can solve most problems by thinking about them differently. By choosing another perspective, and another data structure, you can often arrive at a good, functional solution to your problem.
</p>
<p>
One family of general-purpose data structures are called Zippers. The general idea is that the data structure has a natural 'focus' (e.g. the head of a list), but it also keeps a record of 'breadcrumbs', that is, where the caller has previously been. This enables client code to 'go back' or 'go up', if the natural direction is to 'go forward' or 'go down'. It's a bit like <a href="https://martinfowler.com/eaaDev/EventSourcing.html">Event Sourcing</a>, in that every operation leaves a log entry that can later be used to reconstruct what happened. <a href="/2020/03/23/repeatable-execution">Repeatable Execution</a> also comes to mind, although it's not quite the same.
</p>
<p>
For an introduction to Zippers, I recommend the excellent and highly readable article <a href="https://learnyouahaskell.com/zippers">Zippers</a>. In this article series, I'm going to assume that you're familiar with the contents of that article.
</p>
<h3 id="8ec371f87d2f468ea6ebbc3a2e420cbb">
C# ports <a href="#8ec371f87d2f468ea6ebbc3a2e420cbb">#</a>
</h3>
<p>
While I may add more articles to this series in the future, as I'm writing this, I have nothing more planned than writing about how it's possible to implement the article's three Zippers in C#.
</p>
<ul>
<li><a href="/2024/08/26/a-list-zipper-in-c">A List Zipper in C#</a></li>
<li><a href="/2024/09/09/a-binary-tree-zipper-in-c">A Binary Tree Zipper in C#</a></li>
<li><a href="/2024/09/23/fszipper-in-c">FSZipper in C#</a></li>
</ul>
<p>
Why would you want to do this?
</p>
<p>
To be honest, for production code, I can't think of a good reason. I did it for a few reasons, most of them didactic. Additionally, <a href="/2020/01/13/on-doing-katas">writing code for exercise</a> helps you improve. If you know enough Haskell to understand what's going on in the <a href="https://learnyouahaskell.com/zippers">Zippers article</a>, you may consider porting some of it to your favourite language, as an exercise.
</p>
<p>
It may help you <a href="/ref/stranger-in-a-strange-land">grokking</a> functional programming.
</p>
<p>
That's really it, though. There's no reason to use Zippers in a language like C#, which <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatically</a> makes use of mutation. If you want a doubly-linked list, you can just write code as shown in the beginning of this article.
</p>
<p>
If you're interested in an <a href="https://fsharp.org/">F#</a> perspective on Zippers, <a href="https://tomasp.net/">Tomas Petricek</a> has a cool article: <a href="https://tomasp.net/blog/tree-zipper-query.aspx/">Processing trees with F# zipper computation</a>.
</p>
<h3 id="8a124e3b10aa4b0b889efe866f63dc91">
Conclusion <a href="#8a124e3b10aa4b0b889efe866f63dc91">#</a>
</h3>
<p>
Zippers constitute a family of data structures that enables you to move in multiple directions. Left and right in a list. Up or down in a tree. For an imperative programmer, that's literally just another day at the office, but in disciplined functional programming, making cyclic graphs can be surprisingly tricky.
</p>
<p>
Even in functional programming, I rarely reach for a Zipper, since I can often find a library with a higher level of abstraction that does what I need it to do. Still, learning of new ways to solve problems never seems a waste to me.
</p>
<p>
In the next three articles, I'll go through the examples from <a href="https://learnyouahaskell.com/zippers">the Zipper article</a> and show how I ported them to C#. While that article starts with a <a href="https://en.wikipedia.org/wiki/Binary_tree">binary tree</a>, I'll instead begin with the doubly-linked list, since it's the simplest of the three.
</p>
<p>
<strong>Next:</strong> <a href="/2024/08/26/a-list-zipper-in-c">A List Zipper in C#</a>.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Using only a Domain Model to persist restaurant table configurationshttps://blog.ploeh.dk/2024/08/12/using-only-a-domain-model-to-persist-restaurant-table-configurations2024-08-12T12:57:00+00:00Mark Seemann
<div id="post">
<p>
<em>A data architecture example in C# and ASP.NET.</em>
</p>
<p>
This is part of a <a href="/2024/07/25/three-data-architectures-for-the-server">small article series on data architectures</a>. In this, the third instalment, you'll see an alternative way of modelling data in a server-based application. One that doesn't rely on statically typed classes to model data. As the introductory article explains, the example code shows how to create a new restaurant table configuration, or how to display an existing resource. The sample code base is an ASP.NET 8.0 <a href="https://en.wikipedia.org/wiki/REST">REST</a> API.
</p>
<p>
Keep in mind that while the sample code does store data in a relational database, the term <em>table</em> in this article mainly refers to physical tables, rather than database tables.
</p>
<p>
The idea is to use 'raw' serialization APIs to handle communication with external systems. For the presentation layer, the example even moves representation concerns to middleware, so that it's nicely abstracted away from the application layer.
</p>
<p>
An architecture diagram like this attempts to capture the design:
</p>
<p>
<img src="/content/binary/domain-model-only-data-architecture.png" alt="Architecture diagram showing a box labelled Domain Model with bidirectional arrows both above and below, pointing below towards a cylinder, and above towards a document.">
</p>
<p>
Here, the arrows indicate mappings, not dependencies.
</p>
<p>
Like in the <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">DTO-based Ports and Adapters architecture</a>, the goal is to being able to design Domain Models unconstrained by serialization concerns, but also being able to format external data unconstrained by Reflection-based serializers. Thus, while this architecture is centred on a Domain Model, there are no <a href="https://en.wikipedia.org/wiki/Data_transfer_object">Data Transfer Objects</a> (DTOs) to represent <a href="https://json.org/">JSON</a>, <a href="https://en.wikipedia.org/wiki/XML">XML</a>, or database rows.
</p>
<h3 id="799ef3debcb748079610a1ff818360e2">
HTTP interaction <a href="#799ef3debcb748079610a1ff818360e2">#</a>
</h3>
<p>
To establish the context of the application, here's how HTTP interactions may play out. The following is a copy of the identically named section in the article <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">Using Ports and Adapters to persist restaurant table configurations</a>, repeated here for your convenience.
</p>
<p>
A client can create a new table with a <code>POST</code> HTTP request:
</p>
<p>
<pre>POST /tables HTTP/1.1
content-type: application/json
{ <span style="color:#2e75b6;">"communalTable"</span>: { <span style="color:#2e75b6;">"capacity"</span>: 16 } }</pre>
</p>
<p>
Which might elicit a response like this:
</p>
<p>
<pre>HTTP/1.1 201 Created
Location: https://example.com/Tables/844581613e164813aa17243ff8b847af</pre>
</p>
<p>
Clients can later use the address indicated by the <code>Location</code> header to retrieve a representation of the resource:
</p>
<p>
<pre>GET /Tables/844581613e164813aa17243ff8b847af HTTP/1.1
accept: application/json</pre>
</p>
<p>
Which would result in this response:
</p>
<p>
<pre>HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{<span style="color:#2e75b6;">"communalTable"</span>:{<span style="color:#2e75b6;">"capacity"</span>:16}}</pre>
</p>
<p>
By default, ASP.NET handles and returns JSON. Later in this article you'll see how well it deals with other data formats.
</p>
<h3 id="63cacca8023b4adb9534a34aba0c50ff">
Boundary <a href="#63cacca8023b4adb9534a34aba0c50ff">#</a>
</h3>
<p>
ASP.NET supports some variation of the <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">model-view-controller</a> (MVC) pattern, and Controllers handle HTTP requests. At the outset, the <em>action method</em> that handles the <code>POST</code> request looks like this:
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpPost</span>]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Post</span>(<span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">id</span> = <span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">NewGuid</span>();
<span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">repository</span>.<span style="font-weight:bold;color:#74531f;">Create</span>(<span style="font-weight:bold;color:#1f377f;">id</span>, <span style="font-weight:bold;color:#1f377f;">table</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">CreatedAtActionResult</span>(
<span style="color:blue;">nameof</span>(<span style="font-weight:bold;color:#74531f;">Get</span>),
<span style="color:blue;">null</span>,
<span style="color:blue;">new</span> { id = <span style="font-weight:bold;color:#1f377f;">id</span>.<span style="font-weight:bold;color:#74531f;">ToString</span>(<span style="color:#a31515;">"N"</span>) },
<span style="color:blue;">null</span>);
}</pre>
</p>
<p>
While this looks identical to the <code>Post</code> method for <a href="/2024/08/05/using-a-shared-data-model-to-persist-restaurant-table-configurations">the Shared Data Model architecture</a>, it's not, because it's not the same <code>Table</code> class. Not by a long shot. The <code>Table</code> class in use here is the one originally introduced in the article <a href="/2023/12/25/serializing-restaurant-tables-in-c">Serializing restaurant tables in C#</a>, with a few inconsequential differences.
</p>
<p>
How does a Controller <em>action method</em> receive an input parameter directly in the form of a Domain Model, keeping in mind that this particular Domain Model is far from serialization-friendly? The short answer is <em>middleware</em>, which we'll get to in a moment. Before we look at that, however, let's also look at the <code>Get</code> method that supports HTTP <code>GET</code> requests:
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpGet</span>(<span style="color:#a31515;">"</span><span style="color:#0073ff;">{</span>id<span style="color:#0073ff;">}</span><span style="color:#a31515;">"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Get</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!<span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">TryParseExact</span>(<span style="font-weight:bold;color:#1f377f;">id</span>, <span style="color:#a31515;">"N"</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">guid</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">BadRequestResult</span>();
<span style="color:#2b91af;">Table</span>? <span style="font-weight:bold;color:#1f377f;">table</span> = <span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">repository</span>.<span style="font-weight:bold;color:#74531f;">Read</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">table</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">NotFoundResult</span>();
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">OkObjectResult</span>(<span style="font-weight:bold;color:#1f377f;">table</span>);
}</pre>
</p>
<p>
This, too, looks exactly like the Shared Data Model architecture, again with the crucial difference that the <code>Table</code> class is completely different. The <code>Get</code> method just takes the <code>table</code> object and wraps it in an <code>OkObjectResult</code> and returns it.
</p>
<p>
The <code>Table</code> class is, in reality, extraordinarily opaque, and not at all friendly to serialization, so how do the service turn it into JSON?
</p>
<h3 id="38d9d73532fc4912834452fff3d33b3a">
JSON middleware <a href="#38d9d73532fc4912834452fff3d33b3a">#</a>
</h3>
<p>
Most web frameworks come with extensibility points where you can add middleware. A common need is to be able to add custom serializers. In ASP.NET they're called <em>formatters</em>, and can be added at application startup:
</p>
<p>
<pre><span style="font-weight:bold;color:#1f377f;">builder</span>.Services.<span style="font-weight:bold;color:#74531f;">AddControllers</span>(<span style="font-weight:bold;color:#1f377f;">opts</span> =>
{
<span style="font-weight:bold;color:#1f377f;">opts</span>.InputFormatters.<span style="font-weight:bold;color:#74531f;">Insert</span>(0, <span style="color:blue;">new</span> <span style="color:#2b91af;">TableJsonInputFormatter</span>());
<span style="font-weight:bold;color:#1f377f;">opts</span>.OutputFormatters.<span style="font-weight:bold;color:#74531f;">Insert</span>(0, <span style="color:blue;">new</span> <span style="color:#2b91af;">TableJsonOutputFormatter</span>());
});</pre>
</p>
<p>
As the names imply, <code>TableJsonInputFormatter</code> deserializes JSON input, while <code>TableJsonOutputFormatter</code> serializes strongly typed objects to JSON.
</p>
<p>
We'll look at each in turn, starting with <code>TableJsonInputFormatter</code>, which is responsible for deserializing JSON documents into <code>Table</code> objects, as used by, for example, the <code>Post</code> method.
</p>
<h3 id="9ff7ca45e5fd4d19bb9be29769e9a298">
JSON input formatter <a href="#9ff7ca45e5fd4d19bb9be29769e9a298">#</a>
</h3>
<p>
You create an input formatter by implementing the <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.mvc.formatters.iinputformatter">IInputFormatter</a> interface, although in this example code base, inheriting from <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.mvc.formatters.textinputformatter">TextInputFormatter</a> is enough:
</p>
<p>
<pre><span style="color:blue;">internal</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">TableJsonInputFormatter</span> : <span style="color:#2b91af;">TextInputFormatter</span></pre>
</p>
<p>
You can use the constructor to define which media types and encodings the formatter will support:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">TableJsonInputFormatter</span>()
{
SupportedMediaTypes.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:#2b91af;">MediaTypeHeaderValue</span>.<span style="color:#74531f;">Parse</span>(<span style="color:#a31515;">"application/json"</span>));
SupportedEncodings.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:#2b91af;">Encoding</span>.UTF8);
SupportedEncodings.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:#2b91af;">Encoding</span>.Unicode);
}</pre>
</p>
<p>
You'll also need to tell the formatter, which .NET type it supports:
</p>
<p>
<pre><span style="color:blue;">protected</span> <span style="color:blue;">override</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">CanReadType</span>(<span style="color:#2b91af;">Type</span> <span style="font-weight:bold;color:#1f377f;">type</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">type</span> <span style="font-weight:bold;color:#74531f;">==</span> <span style="color:blue;">typeof</span>(<span style="color:#2b91af;">Table</span>);
}</pre>
</p>
<p>
As far as I can tell, the ASP.NET framework will first determine which <em>action method</em> (that is, which Controller, and which method on that Controller) should handle a given HTTP request. For a <code>POST</code> request, as shown above, it'll determine that the appropriate <em>action method</em> is the <code>Post</code> method.
</p>
<p>
Since the <code>Post</code> method takes a <code>Table</code> object as input, the framework then goes through the registered formatters and asks them whether they can read from an HTTP request into that type. In this case, the <code>TableJsonInputFormatter</code> answers <code>true</code> only if the <code>type</code> is <code>Table</code>.
</p>
<p>
When <code>CanReadType</code> answers <code>true</code>, the framework then invokes a method to turn the HTTP request into an object:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">InputFormatterResult</span>> <span style="font-weight:bold;color:#74531f;">ReadRequestBodyAsync</span>(
<span style="color:#2b91af;">InputFormatterContext</span> <span style="font-weight:bold;color:#1f377f;">context</span>,
<span style="color:#2b91af;">Encoding</span> <span style="font-weight:bold;color:#1f377f;">encoding</span>)
{
<span style="color:blue;">using</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">rdr</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">StreamReader</span>(<span style="font-weight:bold;color:#1f377f;">context</span>.HttpContext.Request.Body, <span style="font-weight:bold;color:#1f377f;">encoding</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">json</span> = <span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">rdr</span>.<span style="font-weight:bold;color:#74531f;">ReadToEndAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">table</span> = <span style="color:#2b91af;">TableJson</span>.<span style="color:#74531f;">Deserialize</span>(<span style="font-weight:bold;color:#1f377f;">json</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">table</span> <span style="color:blue;">is</span> { })
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">await</span> <span style="color:#2b91af;">InputFormatterResult</span>.<span style="color:#74531f;">SuccessAsync</span>(<span style="font-weight:bold;color:#1f377f;">table</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">else</span>
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">await</span> <span style="color:#2b91af;">InputFormatterResult</span>.<span style="color:#74531f;">FailureAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
}</pre>
</p>
<p>
The <code>ReadRequestBodyAsync</code> method reads the HTTP request body into a <code>string</code> value called <code>json</code>, and then passes the value to <code>TableJson.Deserialize</code>. You can see the implementation of the <code>Deserialize</code> method in the article <a href="/2023/12/25/serializing-restaurant-tables-in-c">Serializing restaurant tables in C#</a>. In short, it uses the default .NET JSON parser to probe a document object model. If it can turn the JSON document into a <code>Table</code> value, it does that. Otherwise, it returns <code>null</code>.
</p>
<p>
The above <code>ReadRequestBodyAsync</code> method then checks if the return value from <code>TableJson.Deserialize</code> is <code>null</code>. If it's not, it wraps the result in a value that indicates success. If it's <code>null</code>, it uses <code>FailureAsync</code> to indicate a deserialization failure.
</p>
<p>
With this input formatter in place as middleware, any action method that takes a <code>Table</code> parameter will automatically receive a deserialized JSON object, if possible.
</p>
<h3 id="e04e265f6cdd48869aa8510e14092644">
JSON output formatter <a href="#e04e265f6cdd48869aa8510e14092644">#</a>
</h3>
<p>
The <code>TableJsonOutputFormatter</code> class works much in the same way, but instead derives from the <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.mvc.formatters.textoutputformatter">TextOutputFormatter</a> base class:
</p>
<p>
<pre><span style="color:blue;">internal</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">TableJsonOutputFormatter</span> : <span style="color:#2b91af;">TextOutputFormatter</span></pre>
</p>
<p>
The constructor looks just like the <code>TableJsonInputFormatter</code>, and instead of a <code>CanReadType</code> method, it has a <code>CanWriteType</code> method that also looks identical.
</p>
<p>
The <code>WriteResponseBodyAsync</code> serializes a <code>Table</code> object to JSON:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:#2b91af;">Task</span> <span style="font-weight:bold;color:#74531f;">WriteResponseBodyAsync</span>(
<span style="color:#2b91af;">OutputFormatterWriteContext</span> <span style="font-weight:bold;color:#1f377f;">context</span>,
<span style="color:#2b91af;">Encoding</span> <span style="font-weight:bold;color:#1f377f;">selectedEncoding</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">context</span>.Object <span style="color:blue;">is</span> <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">context</span>.HttpContext.Response.<span style="font-weight:bold;color:#74531f;">WriteAsync</span>(<span style="font-weight:bold;color:#1f377f;">table</span>.<span style="font-weight:bold;color:#74531f;">Serialize</span>(), <span style="font-weight:bold;color:#1f377f;">selectedEncoding</span>);
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">InvalidOperationException</span>(<span style="color:#a31515;">"Expected a Table object."</span>);
}</pre>
</p>
<p>
If <code>context.Object</code> is, in fact, a <code>Table</code> object, the method calls <code>table.Serialize()</code>, which you can also see in the article <a href="/2023/12/25/serializing-restaurant-tables-in-c">Serializing restaurant tables in C#</a>. In short, it pattern-matches on the two possible kinds of tables and builds an appropriate <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">abstract syntax tree</a> or document object model that it then serializes to JSON.
</p>
<h3 id="7c935b48e0cf42369b5d0c55c688d5bf">
Data access <a href="#7c935b48e0cf42369b5d0c55c688d5bf">#</a>
</h3>
<p>
While the application stores data in <a href="https://en.wikipedia.org/wiki/Microsoft_SQL_Server">SQL Server</a>, it uses no <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">object-relational mapper</a> (ORM). Instead, it simply uses ADO.NET, as also outlined in the article <a href="/2023/09/18/do-orms-reduce-the-need-for-mapping">Do ORMs reduce the need for mapping?</a>
</p>
<p>
At first glance, the <code>Create</code> method looks simple:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span> <span style="font-weight:bold;color:#74531f;">Create</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>, <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
{
<span style="color:blue;">using</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">conn</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">SqlConnection</span>(<span style="font-weight:bold;color:#1f377f;">connectionString</span>);
<span style="color:blue;">using</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">cmd</span> = <span style="font-weight:bold;color:#1f377f;">table</span>.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">SqlInsertCommandVisitor</span>(<span style="font-weight:bold;color:#1f377f;">id</span>));
<span style="font-weight:bold;color:#1f377f;">cmd</span>.Connection = <span style="font-weight:bold;color:#1f377f;">conn</span>;
<span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">conn</span>.<span style="font-weight:bold;color:#74531f;">OpenAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">cmd</span>.<span style="font-weight:bold;color:#74531f;">ExecuteNonQueryAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
}</pre>
</p>
<p>
The main work, however, is done by the nested <code>SqlInsertCommandVisitor</code> class:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">SqlInsertCommandVisitor</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>) : <span style="color:#2b91af;">ITableVisitor</span><<span style="color:#2b91af;">SqlCommand</span>>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">SqlCommand</span> <span style="font-weight:bold;color:#74531f;">VisitCommunal</span>(<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>)
{
<span style="color:blue;">const</span> <span style="color:blue;">string</span> createCommunalSql = <span style="color:maroon;">@"
INSERT INTO [dbo].[Tables] ([PublicId], [Capacity])
VALUES (@PublicId, @Capacity)"</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">cmd</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">SqlCommand</span>(createCommunalSql);
<span style="font-weight:bold;color:#1f377f;">cmd</span>.Parameters.<span style="font-weight:bold;color:#74531f;">AddWithValue</span>(<span style="color:#a31515;">"@PublicId"</span>, <span style="font-weight:bold;color:#1f377f;">id</span>);
<span style="font-weight:bold;color:#1f377f;">cmd</span>.Parameters.<span style="font-weight:bold;color:#74531f;">AddWithValue</span>(<span style="color:#a31515;">"@Capacity"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">capacity</span>);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">cmd</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">SqlCommand</span> <span style="font-weight:bold;color:#74531f;">VisitSingle</span>(<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>, <span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">minimalReservation</span>)
{
<span style="color:blue;">const</span> <span style="color:blue;">string</span> createSingleSql = <span style="color:maroon;">@"
INSERT INTO [dbo].[Tables] ([PublicId], [Capacity], [MinimalReservation])
VALUES (@PublicId, @Capacity, @MinimalReservation)"</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">cmd</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">SqlCommand</span>(createSingleSql);
<span style="font-weight:bold;color:#1f377f;">cmd</span>.Parameters.<span style="font-weight:bold;color:#74531f;">AddWithValue</span>(<span style="color:#a31515;">"@PublicId"</span>, <span style="font-weight:bold;color:#1f377f;">id</span>);
<span style="font-weight:bold;color:#1f377f;">cmd</span>.Parameters.<span style="font-weight:bold;color:#74531f;">AddWithValue</span>(<span style="color:#a31515;">"@Capacity"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">capacity</span>);
<span style="font-weight:bold;color:#1f377f;">cmd</span>.Parameters.<span style="font-weight:bold;color:#74531f;">AddWithValue</span>(<span style="color:#a31515;">"@MinimalReservation"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">minimalReservation</span>);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">cmd</span>;
}
}</pre>
</p>
<p>
It 'pattern-matches' on the two possible kinds of table and returns an appropriate <a href="https://learn.microsoft.com/dotnet/api/microsoft.data.sqlclient.sqlcommand">SqlCommand</a> that the <code>Create</code> method then executes. Notice that no 'Entity' class is needed. The code works straight on <code>SqlCommand</code>.
</p>
<p>
The same is true for the repository's <code>Read</code> method:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">Table</span>?> <span style="font-weight:bold;color:#74531f;">Read</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="color:blue;">const</span> <span style="color:blue;">string</span> readByIdSql = <span style="color:maroon;">@"
SELECT [Capacity], [MinimalReservation]
FROM [dbo].[Tables]
WHERE[PublicId] = @id"</span>;
<span style="color:blue;">using</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">conn</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">SqlConnection</span>(<span style="font-weight:bold;color:#1f377f;">connectionString</span>);
<span style="color:blue;">using</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">cmd</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">SqlCommand</span>(readByIdSql, <span style="font-weight:bold;color:#1f377f;">conn</span>);
<span style="font-weight:bold;color:#1f377f;">cmd</span>.Parameters.<span style="font-weight:bold;color:#74531f;">AddWithValue</span>(<span style="color:#a31515;">"@id"</span>, <span style="font-weight:bold;color:#1f377f;">id</span>);
<span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">conn</span>.<span style="font-weight:bold;color:#74531f;">OpenAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="color:blue;">using</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">rdr</span> = <span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">cmd</span>.<span style="font-weight:bold;color:#74531f;">ExecuteReaderAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (!<span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">rdr</span>.<span style="font-weight:bold;color:#74531f;">ReadAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">capacity</span> = (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">rdr</span>[<span style="color:#a31515;">"Capacity"</span>];
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">mimimalReservation</span> = <span style="font-weight:bold;color:#1f377f;">rdr</span>[<span style="color:#a31515;">"MinimalReservation"</span>] <span style="color:blue;">as</span> <span style="color:blue;">int</span>?;
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">mimimalReservation</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateCommunal</span>(<span style="font-weight:bold;color:#1f377f;">capacity</span>);
<span style="font-weight:bold;color:#8f08c4;">else</span>
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateSingle</span>(<span style="font-weight:bold;color:#1f377f;">capacity</span>, <span style="font-weight:bold;color:#1f377f;">mimimalReservation</span>.Value);
}</pre>
</p>
<p>
It works directly on <a href="https://learn.microsoft.com/dotnet/api/microsoft.data.sqlclient.sqldatareader">SqlDataReader</a>. Again, no extra 'Entity' class is required. If the data in the database makes sense, the <code>Read</code> method return a well-<a href="/encapsulation-and-solid">encapsulated</a> <code>Table</code> object.
</p>
<h3 id="2a52a80eef4a4168b281a376751415e2">
XML formats <a href="#2a52a80eef4a4168b281a376751415e2">#</a>
</h3>
<p>
That covers the basics, but how well does this kind of architecture stand up to changing requirements?
</p>
<p>
One axis of variation is when a service needs to support multiple representations. In this example, I'll imagine that the service also needs to support not just one, but two, XML formats.
</p>
<p>
Granted, you may not run into that particular requirement that often, but it's typical of a kind of change that you're likely to run into. In REST APIs, for example, <a href="/2015/06/22/rest-implies-content-negotiation">you should use content negotiation for versioning</a>, and that's the same kind of problem.
</p>
<p>
To be fair, application code also changes for a variety of other reasons, including new features, changes to business logic, etc. I can't possibly cover all, though, and many of these are much better described than changes in wire formats.
</p>
<p>
As described in the <a href="/2024/07/25/three-data-architectures-for-the-server">introduction article</a>, ideally the XML should support a format implied by these examples:
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">></span>
<span style="color:blue;"><</span><span style="color:#a31515;">single-table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>4<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>3<span style="color:blue;"></</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">single-table</span><span style="color:blue;">></span></pre>
</p>
<p>
Notice that while these two examples have different root elements, they're still considered to both represent <em>a table</em>. Although <a href="/2023/10/16/at-the-boundaries-static-types-are-illusory">at the boundaries, static types are illusory</a> we may still, loosely speaking, consider both of those XML documents as belonging to the same 'type'.
</p>
<p>
With both of the previous architectures described in this article series, I've had to give up on this schema. The present data architecture, finally, is able to handle this requirement.
</p>
<h3 id="a0f5e6525743464c97e3fc090d04efbe">
HTTP interactions with element-biased XML <a href="#a0f5e6525743464c97e3fc090d04efbe">#</a>
</h3>
<p>
The service should support the new XML format when presented with the the <code>"application/xml"</code> media type, either as a <code>content-type</code> header or <code>accept</code> header. An initial <code>POST</code> request may look like this:
</p>
<p>
<pre>POST /tables HTTP/1.1
content-type: application/xml
<span style="color:blue;"><</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">><</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">></span></pre>
</p>
<p>
Which produces a reply like this:
</p>
<p>
<pre>HTTP/1.1 201 Created
Location: https://example.com/Tables/a77ac3fd221e4a5caaca3a0fc2b83ffc</pre>
</p>
<p>
And just like before, a client can later use the address in the <code>Location</code> header to request the resource. By using the <code>accept</code> header, it can indicate that it wishes to receive the reply formatted as XML:
</p>
<p>
<pre>GET /Tables/a77ac3fd221e4a5caaca3a0fc2b83ffc HTTP/1.1
accept: application/xml</pre>
</p>
<p>
Which produces this response with XML content in the body:
</p>
<p>
<pre>HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
<span style="color:blue;"><</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">><</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">></span></pre>
</p>
<p>
How do you add support for this new format?
</p>
<h3 id="a94d98e6c9b6458d9754354f736c69be">
Element-biased XML formatters <a href="#a94d98e6c9b6458d9754354f736c69be">#</a>
</h3>
<p>
Not surprisingly, you can add support for the new format by adding new formatters.
</p>
<p>
<pre><span style="font-weight:bold;color:#1f377f;">opts</span>.InputFormatters.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">ElementBiasedTableXmlInputFormatter</span>());
<span style="font-weight:bold;color:#1f377f;">opts</span>.OutputFormatters.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">ElementBiasedTableXmlOutputFormatter</span>());</pre>
</p>
<p>
Importantly, and in stark contrast to <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">the DTO-based Ports and Adapters example</a>, you don't have to change the existing code to add XML support. If you're concerned about design heuristics such as the <a href="https://en.wikipedia.org/wiki/Single-responsibility_principle">Single Responsibility Principle</a>, you may consider this a win. Apart from the two lines of code adding the formatters, all other code to support this new feature is in new classes.
</p>
<p>
Both of the new formatters support the <code>"application/xml"</code> media type.
</p>
<h3 id="853eca2110634b5289ffb3fe16f9dacd">
Deserializing element-biased XML <a href="#853eca2110634b5289ffb3fe16f9dacd">#</a>
</h3>
<p>
The constructor and <code>CanReadType</code> implementation of <code>ElementBiasedTableXmlInputFormatter</code> is nearly identical to code you've already seen here, so I'll skip the repetition. The <code>ReadRequestBodyAsync</code> implementation is also conceptually similar, but of course differs in the details.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">InputFormatterResult</span>> <span style="font-weight:bold;color:#74531f;">ReadRequestBodyAsync</span>(
<span style="color:#2b91af;">InputFormatterContext</span> <span style="font-weight:bold;color:#1f377f;">context</span>,
<span style="color:#2b91af;">Encoding</span> <span style="font-weight:bold;color:#1f377f;">encoding</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">xml</span> = <span style="color:blue;">await</span> <span style="color:#2b91af;">XElement</span>
.<span style="color:#74531f;">LoadAsync</span>(<span style="font-weight:bold;color:#1f377f;">context</span>.HttpContext.Request.Body, <span style="color:#2b91af;">LoadOptions</span>.None, <span style="color:#2b91af;">CancellationToken</span>.None)
.<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">table</span> = <span style="color:#2b91af;">TableXml</span>.<span style="color:#74531f;">TryParseElementBiased</span>(<span style="font-weight:bold;color:#1f377f;">xml</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">table</span> <span style="color:blue;">is</span> { })
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">await</span> <span style="color:#2b91af;">InputFormatterResult</span>.<span style="color:#74531f;">SuccessAsync</span>(<span style="font-weight:bold;color:#1f377f;">table</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">else</span>
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">await</span> <span style="color:#2b91af;">InputFormatterResult</span>.<span style="color:#74531f;">FailureAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
}</pre>
</p>
<p>
As is also the case with the JSON input formatter, the <code>ReadRequestBodyAsync</code> method really only implements an <a href="https://en.wikipedia.org/wiki/Adapter_pattern">Adapter</a> over a more specialized parser function:
</p>
<p>
<pre><span style="color:blue;">internal</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">Table</span>? <span style="color:#74531f;">TryParseElementBiased</span>(<span style="color:#2b91af;">XElement</span> <span style="font-weight:bold;color:#1f377f;">xml</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">xml</span>.Name <span style="font-weight:bold;color:#74531f;">==</span> <span style="color:#a31515;">"communal-table"</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">capacity</span> = <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">Element</span>(<span style="color:#a31515;">"capacity"</span>)?.Value;
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">capacity</span> <span style="color:blue;">is</span> { })
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="color:blue;">int</span>.<span style="color:#74531f;">TryParse</span>(<span style="font-weight:bold;color:#1f377f;">capacity</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">c</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateCommunal</span>(<span style="font-weight:bold;color:#1f377f;">c</span>);
}
}
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">xml</span>.Name <span style="font-weight:bold;color:#74531f;">==</span> <span style="color:#a31515;">"single-table"</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">capacity</span> = <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">Element</span>(<span style="color:#a31515;">"capacity"</span>)?.Value;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">minimalReservation</span> = <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">Element</span>(<span style="color:#a31515;">"minimal-reservation"</span>)?.Value;
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">capacity</span> <span style="color:blue;">is</span> { } && <span style="font-weight:bold;color:#1f377f;">minimalReservation</span> <span style="color:blue;">is</span> { })
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="color:blue;">int</span>.<span style="color:#74531f;">TryParse</span>(<span style="font-weight:bold;color:#1f377f;">capacity</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">c</span>) &&
<span style="color:blue;">int</span>.<span style="color:#74531f;">TryParse</span>(<span style="font-weight:bold;color:#1f377f;">minimalReservation</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">mr</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateSingle</span>(<span style="font-weight:bold;color:#1f377f;">c</span>, <span style="font-weight:bold;color:#1f377f;">mr</span>);
}
}
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
}</pre>
</p>
<p>
In keeping with the common theme of the Domain Model Only data architecture, it deserialized by examining an <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> (AST) or document object model (DOM), specifically making use of the <a href="https://learn.microsoft.com/dotnet/api/system.xml.linq.xelement">XElement</a> API. This class is really part of the <a href="https://learn.microsoft.com/dotnet/standard/linq/linq-xml-overview">LINQ to XML</a> API, but you'll probably agree that the above code example makes little use of LINQ.
</p>
<h3 id="53fbee4be7ca45c090de48168de537fb">
Serializing element-biased XML <a href="#53fbee4be7ca45c090de48168de537fb">#</a>
</h3>
<p>
Hardly surprising, turning a <code>Table</code> object into element-biased XML involves steps similar to converting it to JSON. The <code>ElementBiasedTableXmlOutputFormatter</code> class' <code>WriteResponseBodyAsync</code> method contains this implementation:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:#2b91af;">Task</span> <span style="font-weight:bold;color:#74531f;">WriteResponseBodyAsync</span>(
<span style="color:#2b91af;">OutputFormatterWriteContext</span> <span style="font-weight:bold;color:#1f377f;">context</span>,
<span style="color:#2b91af;">Encoding</span> <span style="font-weight:bold;color:#1f377f;">selectedEncoding</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">context</span>.Object <span style="color:blue;">is</span> <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">context</span>.HttpContext.Response.<span style="font-weight:bold;color:#74531f;">WriteAsync</span>(
<span style="font-weight:bold;color:#1f377f;">table</span>.<span style="font-weight:bold;color:#74531f;">GenerateElementBiasedXml</span>(),
<span style="font-weight:bold;color:#1f377f;">selectedEncoding</span>);
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">InvalidOperationException</span>(<span style="color:#a31515;">"Expected a Table object."</span>);
}</pre>
</p>
<p>
Again, the heavy lifting is done by a specialized function:
</p>
<p>
<pre><span style="color:blue;">internal</span> <span style="color:blue;">static</span> <span style="color:blue;">string</span> <span style="color:#74531f;">GenerateElementBiasedXml</span>(<span style="color:blue;">this</span> <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">table</span>.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">ElementBiasedTableVisitor</span>());
}
<span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">ElementBiasedTableVisitor</span> : <span style="color:#2b91af;">ITableVisitor</span><<span style="color:blue;">string</span>>
{
<span style="color:blue;">public</span> <span style="color:blue;">string</span> <span style="font-weight:bold;color:#74531f;">VisitCommunal</span>(<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">xml</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">XElement</span>(
<span style="color:#a31515;">"communal-table"</span>,
<span style="color:blue;">new</span> <span style="color:#2b91af;">XElement</span>(<span style="color:#a31515;">"capacity"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">capacity</span>));
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">ToString</span>(<span style="color:#2b91af;">SaveOptions</span>.DisableFormatting);
}
<span style="color:blue;">public</span> <span style="color:blue;">string</span> <span style="font-weight:bold;color:#74531f;">VisitSingle</span>(
<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>,
<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">minimalReservation</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">xml</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">XElement</span>(
<span style="color:#a31515;">"single-table"</span>,
<span style="color:blue;">new</span> <span style="color:#2b91af;">XElement</span>(<span style="color:#a31515;">"capacity"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">capacity</span>),
<span style="color:blue;">new</span> <span style="color:#2b91af;">XElement</span>(<span style="color:#a31515;">"minimal-reservation"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">minimalReservation</span>));
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">ToString</span>(<span style="color:#2b91af;">SaveOptions</span>.DisableFormatting);
}
}</pre>
</p>
<p>
True to form, <code>GenerateElementBiasedXml</code> assembles an appropriate AST for the kind of table in question, and finally converts it to a <code>string</code> value.
</p>
<h3 id="32ae551ed0b84bb6947e612d08ff7c50">
Attribute-biased XML <a href="#32ae551ed0b84bb6947e612d08ff7c50">#</a>
</h3>
<p>
I was curious how far I could take this kind of variation, so for the sake of exploration, I invented yet another XML format to support. Instead of making exclusive use of XML elements, this format uses XML attributes for primitive values.
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">communal-table</span><span style="color:blue;"> </span><span style="color:red;">capacity</span><span style="color:blue;">=</span>"<span style="color:blue;">12</span>"<span style="color:blue;"> /></span>
<span style="color:blue;"><</span><span style="color:#a31515;">single-table</span><span style="color:blue;"> </span><span style="color:red;">capacity</span><span style="color:blue;">=</span>"<span style="color:blue;">4</span>"<span style="color:blue;"> </span><span style="color:red;">minimal-reservation</span><span style="color:blue;">=</span>"<span style="color:blue;">3</span>"<span style="color:blue;"> /></span></pre>
</p>
<p>
In order to distinguish this XML format from the other, I invented the vendor media type <code>"application/vnd.ploeh.table+xml"</code>. The new formatters only handle this media type.
</p>
<p>
There's not much new to report. The new formatters work like the previous. In order to parse the new format, a new function does that, still based on <code>XElement</code>:
</p>
<p>
<pre><span style="color:blue;">internal</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">Table</span>? <span style="color:#74531f;">TryParseAttributeBiased</span>(<span style="color:#2b91af;">XElement</span> <span style="font-weight:bold;color:#1f377f;">xml</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">xml</span>.Name <span style="font-weight:bold;color:#74531f;">==</span> <span style="color:#a31515;">"communal-table"</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">capacity</span> = <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">Attribute</span>(<span style="color:#a31515;">"capacity"</span>)?.Value;
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">capacity</span> <span style="color:blue;">is</span> { })
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="color:blue;">int</span>.<span style="color:#74531f;">TryParse</span>(<span style="font-weight:bold;color:#1f377f;">capacity</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">c</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateCommunal</span>(<span style="font-weight:bold;color:#1f377f;">c</span>);
}
}
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">xml</span>.Name <span style="font-weight:bold;color:#74531f;">==</span> <span style="color:#a31515;">"single-table"</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">capacity</span> = <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">Attribute</span>(<span style="color:#a31515;">"capacity"</span>)?.Value;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">minimalReservation</span> = <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">Attribute</span>(<span style="color:#a31515;">"minimal-reservation"</span>)?.Value;
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">capacity</span> <span style="color:blue;">is</span> { } && <span style="font-weight:bold;color:#1f377f;">minimalReservation</span> <span style="color:blue;">is</span> { })
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="color:blue;">int</span>.<span style="color:#74531f;">TryParse</span>(<span style="font-weight:bold;color:#1f377f;">capacity</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">c</span>) &&
<span style="color:blue;">int</span>.<span style="color:#74531f;">TryParse</span>(<span style="font-weight:bold;color:#1f377f;">minimalReservation</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">mr</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateSingle</span>(<span style="font-weight:bold;color:#1f377f;">c</span>, <span style="font-weight:bold;color:#1f377f;">mr</span>);
}
}
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
}</pre>
</p>
<p>
Likewise, converting a <code>Table</code> object to this format looks like code you've already seen:
</p>
<p>
<pre><span style="color:blue;">internal</span> <span style="color:blue;">static</span> <span style="color:blue;">string</span> <span style="color:#74531f;">GenerateAttributeBiasedXml</span>(<span style="color:blue;">this</span> <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">table</span>.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">AttributedBiasedTableVisitor</span>());
}
<span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">AttributedBiasedTableVisitor</span> : <span style="color:#2b91af;">ITableVisitor</span><<span style="color:blue;">string</span>>
{
<span style="color:blue;">public</span> <span style="color:blue;">string</span> <span style="font-weight:bold;color:#74531f;">VisitCommunal</span>(<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">xml</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">XElement</span>(
<span style="color:#a31515;">"communal-table"</span>,
<span style="color:blue;">new</span> <span style="color:#2b91af;">XAttribute</span>(<span style="color:#a31515;">"capacity"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">capacity</span>));
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">ToString</span>(<span style="color:#2b91af;">SaveOptions</span>.DisableFormatting);
}
<span style="color:blue;">public</span> <span style="color:blue;">string</span> <span style="font-weight:bold;color:#74531f;">VisitSingle</span>(
<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>,
<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">minimalReservation</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">xml</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">XElement</span>(
<span style="color:#a31515;">"single-table"</span>,
<span style="color:blue;">new</span> <span style="color:#2b91af;">XAttribute</span>(<span style="color:#a31515;">"capacity"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">capacity</span>),
<span style="color:blue;">new</span> <span style="color:#2b91af;">XAttribute</span>(<span style="color:#a31515;">"minimal-reservation"</span>, (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">minimalReservation</span>));
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">xml</span>.<span style="font-weight:bold;color:#74531f;">ToString</span>(<span style="color:#2b91af;">SaveOptions</span>.DisableFormatting);
}
}</pre>
</p>
<p>
Consistent with adding the first XML support, I didn't have to touch any of the existing Controller or data access code.
</p>
<h3 id="490e8625f0334deda0f377c8e8a3ad51">
Evaluation <a href="#490e8625f0334deda0f377c8e8a3ad51">#</a>
</h3>
<p>
If you're concerned with <a href="https://en.wikipedia.org/wiki/Separation_of_concerns">separation of concerns</a>, the Domain Model Only architecture gracefully handles variation in external formats without impacting application logic, Domain Model, or data access. You deal with each new format in a consistent and independent manner. The architecture offers the ultimate data representation flexibility, since everything you can write as a stream of bytes you can implement.
</p>
<p>
Since <a href="/2023/10/16/at-the-boundaries-static-types-are-illusory">at the boundary, static types are illusory</a> this architecture is congruent with reality. For a REST service, at least, reality is what goes on the wire. While static types can also be used to model what wire formats look like, there's always a risk that you can use your <a href="https://en.wikipedia.org/wiki/Integrated_development_environment">IDE's</a> refactoring tools to change a DTO in such a way that the code still compiles, but you've now changed the wire format. This could easily break existing clients.
</p>
<p>
When wire compatibility is important, I test-drive enough <a href="/2021/01/25/self-hosted-integration-tests-in-aspnet">self-hosted tests</a> that directly use and verify the wire format to give me a good sense of stability. Without DTO classes, it becomes increasingly important to cover externally visible behaviour with a trustworthy test suite, but really, if compatibility is important, you should be doing that anyway.
</p>
<p>
It almost goes without saying that a requirement for this architecture is that your chosen web framework supports it. As you've seen here, ASP.NET does, but that's not a given in general. Most web frameworks worth their salt will come with mechanisms that enable you to add new wire formats, but the question is how opinionated such extensibility points are. Do they expect you to work with DTOs, or are they more flexible than that?
</p>
<p>
You may consider the pure Domain Model Only data architecture too specialized for everyday use. I may do that, too. As I wrote in the <a href="/2024/07/25/three-data-architectures-for-the-server">introduction article</a>, I don't intent these walk-throughs to be prescriptive. Rather, they explore what's possible, so that you and I have a bigger set of alternatives to choose from.
</p>
<h3 id="d3dc45b5c52741a99bee6788610cc69c">
Hybrid architectures <a href="#d3dc45b5c52741a99bee6788610cc69c">#</a>
</h3>
<p>
In the code base that accompanies <a href="/2021/06/14/new-book-code-that-fits-in-your-head">Code That Fits in Your Head</a>, I use a hybrid data architecture that I've used for years. ADO.NET for data access, as shown here, but DTOs for external JSON serialization. As demonstrated in the article <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">Using Ports and Adapters to persist restaurant table configurations</a>, using DTOs for the presentation layer may cause trouble if you need to support multiple wire formats. On the other hand, if you don't expect that this is a concern, you may decide to run that risk. I often do that.
</p>
<p>
When presenting these three architectures to a larger audience, one audience member told me that his team used another hybrid architecture: DTOs for the presentation layer, and separate DTOs for data access, but no Domain Model. I can see how this makes sense in a mostly <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a>-heavy application where nonetheless you need to be able to vary user interfaces independently from the database schema.
</p>
<p>
Finally, I should point out that the Domain Model Only data architecture is, in reality, also a kind of Ports and Adapters architecture. It just uses more low-level Adapter implementations than you idiomatically see.
</p>
<h3 id="9b25fc7ec7754509b06585eaf757e0cb">
Conclusion <a href="#9b25fc7ec7754509b06585eaf757e0cb">#</a>
</h3>
<p>
The Domain Model Only data architecture emphasises modelling business logic as a strongly-typed, well-encapsulated Domain Model, while eschewing using statically-typed DTOs for communication with external processes. What I most like about this alternative is that it leaves little confusion as to where functionality goes.
</p>
<p>
When you have, say, <code>TableDto</code>, <code>Table</code>, and <code>TableEntity</code> classes, you need a sophisticated and mature team to trust all developers to add functionality in the right place. If there's only a single <code>Table</code> Domain Model, it may be more evident to developers that only business logic belongs there, and other concerns ought to be addressed in different ways.
</p>
<p>
Even so, you may consider all the low-level parsing code not to your liking, and instead decide to use DTOs. I may too, depending on context.
</p>
</div>
<div id="comments">
<hr>
<h2 id="comments-header">
Comments
</h2>
<div class="comment" id="ed975f7a8fc64d3e9ee35efaa8a6bcbc">
<div class="comment-author"><a href="https://github.com/JesHansen">Jes Hansen</a> <a href="#ed975f7a8fc64d3e9ee35efaa8a6bcbc">#</a></div>
<div class="comment-content">
<p>
In this version of the data archictecture, let's suppose that the controller that now accepts a Domain Object directly is part of a larger REST API. How would you handle discoverability of the API, as the usual OpenAPI (Swagger et.al.) tools probably takes offence at this type of request object?
</p>
</div>
<div class="comment-date">2024-08-19 12:10 UTC</div>
</div>
<div class="comment" id="3b2bacb8fa274590ad45cb7864f19848">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#3b2bacb8fa274590ad45cb7864f19848">#</a></div>
<div class="comment-content">
<p>
Jes, thank you for writing. If by discoverability you mean 'documentation', I would handle that the same way I usually handle documentation requirements for REST APIs: by writing one or my documents that explain how the API works. If there are other possible uses of OpenAPI than that, and the GUI to perform ad-hoc experiments, I'm going to need to be taken to task, because then I'm not aware of them.
</p>
<p>
I've recently discussed <a href="/2024/05/13/gratification">my general misgivings about OpenAPI</a>, and they apply here as well. I'm aware that other people feel differently about this, and that's okay too.
</p>
<blockquote>
"the usual OpenAPI (Swagger et.al.) tools probably takes offence at this type of request object"
</blockquote>
<p>
You may be right, but I haven't tried, so I don't know if this is the case.
</p>
</div>
<div class="comment-date">2024-08-22 16:55 UTC</div>
</div>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Using a Shared Data Model to persist restaurant table configurationshttps://blog.ploeh.dk/2024/08/05/using-a-shared-data-model-to-persist-restaurant-table-configurations2024-08-05T06:14:00+00:00Mark Seemann
<div id="post">
<p>
<em>A data architecture example in C# and ASP.NET.</em>
</p>
<p>
This is part of a <a href="/2024/07/25/three-data-architectures-for-the-server">small article series on data architectures</a>. In this, the second instalment, you'll see a common attempt at addressing the mapping issue that I mentioned in the <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">previous article</a>. As the introductory article explains, the example code shows how to create a new restaurant table configuration, or how to display an existing resource. The sample code base is an ASP.NET 8.0 <a href="https://en.wikipedia.org/wiki/REST">REST</a> API.
</p>
<p>
Keep in mind that while the sample code does store data in a relational database, the term <em>table</em> in this article mainly refers to physical tables, rather than database tables.
</p>
<p>
The idea in this data architecture is to use a single, shared data model for each business object in the service. This is in contrast to the Ports and Adapters architecture, where you typically have a <a href="https://en.wikipedia.org/wiki/Data_transfer_object">Data Transfer Object</a> (DTO) for (<a href="https://json.org/">JSON</a> or <a href="https://en.wikipedia.org/wiki/XML">XML</a>) serialization, another class for the Domain Model, and a third to support an <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">object-relational mapper</a>.
</p>
<p>
An architecture diagram may attempt to illustrate the idea like this:
</p>
<p>
<img src="/content/binary/shared-data-model-architecture.png" alt="Architecture diagram showing three vertically stacked layers named UI/data, business logic, and data access, with a vertical box labelled data model overlapping all three.">
</p>
<p>
While ostensibly keeping alive the idea of application <em>layers</em>, data models are allowed to cross layers to be used both for database persistence, business logic, and in the presentation layer.
</p>
<h3 id="880c5cdea9104efe99f0b816c6b2d632">
Data model <a href="#880c5cdea9104efe99f0b816c6b2d632">#</a>
</h3>
<p>
Since the goal is to use a single class to model all application concerns, it means that we also need to use it for database persistence. The most commonly used ORM in .NET is <a href="https://en.wikipedia.org/wiki/Entity_Framework">Entity Framework</a>, so I'll use that for the example. It's <a href="/2023/09/18/do-orms-reduce-the-need-for-mapping">not something that I normally do</a>, so it's possible that I could have done it better than what follows.
</p>
<p>
Still, assume that the database schema defines the <code>Tables</code> table like this:
</p>
<p>
<pre><span style="color:blue;">CREATE</span> <span style="color:blue;">TABLE</span> [dbo]<span style="color:gray;">.</span>[Tables]<span style="color:blue;"> </span><span style="color:gray;">(</span>
[Id] <span style="color:blue;">INT</span> <span style="color:gray;">NOT</span> <span style="color:gray;">NULL</span> <span style="color:blue;">IDENTITY</span> <span style="color:blue;">PRIMARY</span> <span style="color:blue;">KEY</span><span style="color:gray;">,</span>
[PublicId] <span style="color:blue;">UNIQUEIDENTIFIER</span> <span style="color:gray;">NOT</span> <span style="color:gray;">NULL</span> <span style="color:blue;">UNIQUE</span><span style="color:gray;">,</span>
[Capacity] <span style="color:blue;">INT</span> <span style="color:gray;">NOT</span> <span style="color:gray;">NULL,</span>
[MinimalReservation] <span style="color:blue;">INT</span> <span style="color:gray;">NULL</span>
<span style="color:gray;">)</span></pre>
</p>
<p>
I used a scaffolding tool to generate Entity Framework code from the database schema and then modified what it had created. This is the result:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">partial</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">Table</span>
{
[<span style="color:#2b91af;">JsonIgnore</span>]
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Id { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">JsonIgnore</span>]
<span style="color:blue;">public</span> <span style="color:#2b91af;">Guid</span> PublicId { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">string</span> Type => MinimalReservation.HasValue ? <span style="color:#a31515;">"single"</span> : <span style="color:#a31515;">"communal"</span>;
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Capacity { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">int</span>? MinimalReservation { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
}</pre>
</p>
<p>
Notice that I added <code>[JsonIgnore]</code> attributes to two of the properties, since I didn't want to serialize them to JSON. I also added the calculated property <code>Type</code> to include a discriminator in the JSON documents.
</p>
<h3 id="852e790115024988b43e57b369fe67e7">
HTTP interaction <a href="#852e790115024988b43e57b369fe67e7">#</a>
</h3>
<p>
A client can create a new table with a <code>POST</code> HTTP request:
</p>
<p>
<pre>POST /tables HTTP/1.1
content-type: application/json
{<span style="color:#2e75b6;">"type"</span>:<span style="color:#a31515;">"communal"</span>,<span style="color:#2e75b6;">"capacity"</span>:12}</pre>
</p>
<p>
Notice that the JSON document doesn't follow the desired schema described in the <a href="/2024/07/25/three-data-architectures-for-the-server">introduction article</a>. It can't, because the data architecture is bound to the shared <code>Table</code> class. Or at least, if it's possible to attain the desired format with a single class and only some strategically placed attributes, I'm not aware of it. As the article <a href="/2024/08/12/using-only-a-domain-model-to-persist-restaurant-table-configurations">Using only a Domain Model to persist restaurant table configurations</a> will show, it <em>is</em> possible to attain that goal with the appropriate middleware, but I consider doing that to be an example of the third architecture, so not something I will cover in this article.
</p>
<p>
The service will respond to the above request like this:
</p>
<p>
<pre>HTTP/1.1 201 Created
Location: https://example.com/Tables/777779466d2549d69f7e30b6c35bde3c</pre>
</p>
<p>
Clients can later use the address indicated by the <code>Location</code> header to retrieve a representation of the resource:
</p>
<p>
<pre>GET /Tables/777779466d2549d69f7e30b6c35bde3c HTTP/1.1
accept: application/json</pre>
</p>
<p>
Which elicits this response:
</p>
<p>
<pre>HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{<span style="color:#2e75b6;">"type"</span>:<span style="color:#a31515;">"communal"</span>,<span style="color:#2e75b6;">"capacity"</span>:12}</pre>
</p>
<p>
The JSON format still doesn't conform to the desired format because the Controller in question deals exclusively with the shared <code>Table</code> data model.
</p>
<h3 id="7dd82d2b3f4348a98d1125547dc35684">
Boundary <a href="#7dd82d2b3f4348a98d1125547dc35684">#</a>
</h3>
<p>
At the boundary of the application, Controllers handle HTTP requests with <em>action methods</em> (an ASP.NET term). The framework matches requests by a combination of naming conventions and attributes. The <code>Post</code> action method handles incoming <code>POST</code> requests.
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpPost</span>]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Post</span>(<span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">id</span> = <span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">NewGuid</span>();
<span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">repository</span>.<span style="font-weight:bold;color:#74531f;">Create</span>(<span style="font-weight:bold;color:#1f377f;">id</span>, <span style="font-weight:bold;color:#1f377f;">table</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">CreatedAtActionResult</span>(
<span style="color:blue;">nameof</span>(<span style="font-weight:bold;color:#74531f;">Get</span>),
<span style="color:blue;">null</span>,
<span style="color:blue;">new</span> { id = <span style="font-weight:bold;color:#1f377f;">id</span>.<span style="font-weight:bold;color:#74531f;">ToString</span>(<span style="color:#a31515;">"N"</span>) },
<span style="color:blue;">null</span>);
}</pre>
</p>
<p>
Notice that the input parameter isn't a separate DTO, but rather the shared <code>Table</code> object. Since it's shared, the Controller can pass it directly to the <code>repository</code> without any mapping.
</p>
<p>
The same simplicity is on display in the <code>Get</code> method:
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpGet</span>(<span style="color:#a31515;">"</span><span style="color:#0073ff;">{</span>id<span style="color:#0073ff;">}</span><span style="color:#a31515;">"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Get</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!<span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">TryParseExact</span>(<span style="font-weight:bold;color:#1f377f;">id</span>, <span style="color:#a31515;">"N"</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">guid</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">BadRequestResult</span>();
<span style="color:#2b91af;">Table</span>? <span style="font-weight:bold;color:#1f377f;">table</span> = <span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">repository</span>.<span style="font-weight:bold;color:#74531f;">Read</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">table</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">NotFoundResult</span>();
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">OkObjectResult</span>(<span style="font-weight:bold;color:#1f377f;">table</span>);
}</pre>
</p>
<p>
Once the <code>Get</code> method has parsed the <code>id</code> it goes straight to the <code>repository</code>, retrieves the <code>table</code> and returns it if it's there. No mapping is required by the Controller. What about the <code>repository</code>?
</p>
<h3 id="a3154e68acfa4976b9cf91e4e1036834">
Data access <a href="#a3154e68acfa4976b9cf91e4e1036834">#</a>
</h3>
<p>
The <code>SqlTablesRepository</code> class reads and writes data from <a href="https://en.wikipedia.org/wiki/Microsoft_SQL_Server">SQL Server</a> using Entity Framework. The <code>Create</code> method is as simple as this:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span> <span style="font-weight:bold;color:#74531f;">Create</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>, <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
{
<span style="color:#2b91af;">ArgumentNullException</span>.<span style="color:#74531f;">ThrowIfNull</span>(<span style="font-weight:bold;color:#1f377f;">table</span>);
<span style="font-weight:bold;color:#1f377f;">table</span>.PublicId = <span style="font-weight:bold;color:#1f377f;">id</span>;
<span style="color:blue;">await</span> context.Tables.<span style="font-weight:bold;color:#74531f;">AddAsync</span>(<span style="font-weight:bold;color:#1f377f;">table</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="color:blue;">await</span> context.<span style="font-weight:bold;color:#74531f;">SaveChangesAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
}</pre>
</p>
<p>
The <code>Read</code> method is even simpler - a one-liner:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">Table</span>?> <span style="font-weight:bold;color:#74531f;">Read</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">await</span> context.Tables
.<span style="font-weight:bold;color:#74531f;">SingleOrDefaultAsync</span>(<span style="font-weight:bold;color:#1f377f;">t</span> => <span style="font-weight:bold;color:#1f377f;">t</span>.PublicId <span style="font-weight:bold;color:#74531f;">==</span> <span style="font-weight:bold;color:#1f377f;">id</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
}</pre>
</p>
<p>
Again, no mapping. Just return the database Entity.
</p>
<h3 id="4f14688d058a469f858792ce8d129af9">
XML serialization <a href="#4f14688d058a469f858792ce8d129af9">#</a>
</h3>
<p>
Simple, so far, but how does this data architecture handle changing requirements?
</p>
<p>
One axis of variation is when a service needs to support multiple representations. In this example, I'll imagine that the service also needs to support XML.
</p>
<p>
Granted, you may not run into that particular requirement that often, but it's typical of a kind of change that you're likely to run into. In REST APIs, for example, <a href="/2015/06/22/rest-implies-content-negotiation">you should use content negotiation for versioning</a>, and that's the same kind of problem.
</p>
<p>
To be fair, application code also changes for a variety of other reasons, including new features, changes to business logic, etc. I can't possibly cover all, though, and many of these are much better described than changes in wire formats.
</p>
<p>
As was also the case in <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">the previous article</a>, it quickly turns out that it's not possible to support any of the desired XML formats described in the <a href="/2024/07/25/three-data-architectures-for-the-server">introduction article</a>. Instead, for the sake of exploring what <em>is</em> possible, I'll compromise and support XML documents like these examples:
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>communal<span style="color:blue;"></</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">table</span><span style="color:blue;">></span>
<span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>single<span style="color:blue;"></</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>4<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>3<span style="color:blue;"></</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">table</span><span style="color:blue;">></span></pre>
</p>
<p>
This schema, it turns out, is the same as the element-biased format from <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">the previous article</a>. I could, instead, have chosen to support the attribute-biased format, but, because of the shared data model, not both.
</p>
<p>
Notice how using statically typed classes, attributes, and Reflection to guide serialization leads toward certain kinds of formats. You can't easily support any arbitrary JSON or XML schema, but are rather nudged into a more constrained subset of possible formats. There's nothing too bad about this. As usual, there are trade-offs involved. You concede flexibility, but gain convenience: Just slab some attributes on your DTO, and it works well enough for most purposes. I mostly point it out because this entire article series is about awareness of choice. There's always some cost to be paid.
</p>
<p>
That said, supporting that XML format is surprisingly easy:
</p>
<p>
<pre>[<span style="color:#2b91af;">XmlRoot</span>(<span style="color:#a31515;">"table"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">partial</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">Table</span>
{
[<span style="color:#2b91af;">JsonIgnore</span>, <span style="color:#2b91af;">XmlIgnore</span>]
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Id { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">JsonIgnore</span>, <span style="color:#2b91af;">XmlIgnore</span>]
<span style="color:blue;">public</span> <span style="color:#2b91af;">Guid</span> PublicId { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">XmlElement</span>(<span style="color:#a31515;">"type"</span>), <span style="color:#2b91af;">NotMapped</span>]
<span style="color:blue;">public</span> <span style="color:blue;">string</span>? Type { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">XmlElement</span>(<span style="color:#a31515;">"capacity"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Capacity { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">XmlElement</span>(<span style="color:#a31515;">"minimal-reservation"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">int</span>? MinimalReservation { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">ShouldSerializeMinimalReservation</span>() =>
MinimalReservation.HasValue;
<span style="color:blue;">internal</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">InferType</span>()
{
Type = MinimalReservation.HasValue ? <span style="color:#a31515;">"single"</span> : <span style="color:#a31515;">"communal"</span>;
}
}</pre>
</p>
<p>
Most of the changes are simple additions of the <code>XmlRoot</code>, <code>XmlElement</code>, and <code>XmlIgnore</code> attributes. In order to serialize the <code><span style="color:blue;"><</span><span style="color:#a31515;">type</span><span style="color:blue;">></span></code> element, however, I also had to convert the <code>Type</code> property to a read/write property, which had some ripple effects.
</p>
<p>
For one, I had to add the <code>NotMapped</code> attribute to tell Entity Framework that it shouldn't try to save the value of that property in the database. As you can see in the above SQL schema, the <code>Tables</code> table has no <code>Type</code> column.
</p>
<p>
This also meant that I had to change the <code>Read</code> method in <code>SqlTablesRepository</code> to call the new <code>InferType</code> method:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">Table</span>?> <span style="font-weight:bold;color:#74531f;">Read</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">table</span> = <span style="color:blue;">await</span> context.Tables
.<span style="font-weight:bold;color:#74531f;">SingleOrDefaultAsync</span>(<span style="font-weight:bold;color:#1f377f;">t</span> => <span style="font-weight:bold;color:#1f377f;">t</span>.PublicId <span style="font-weight:bold;color:#74531f;">==</span> <span style="font-weight:bold;color:#1f377f;">id</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#1f377f;">table</span>?.<span style="font-weight:bold;color:#74531f;">InferType</span>();
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">table</span>;
}</pre>
</p>
<p>
I'm not happy with this kind of <a href="https://en.wikipedia.org/wiki/Sequential_coupling">sequential coupling</a>, but to be honest, this data architecture inherently has an appalling lack of <a href="/encapsulation-and-solid">encapsulation</a>. Having to call <code>InferType</code> is just par for the course.
</p>
<p>
That said, despite a few stumbling blocks, adding XML support turned out to be surprisingly easy in this data architecture. Granted, I had to compromise on the schema, and could only support one XML schema, so we shouldn't really take this as an endorsement. To <a href="/ref/psychology-of-computer-programming">paraphrase Gerald Weinberg</a>, if it doesn't have to work, it's easy to implement.
</p>
<h3 id="cd22920ca9564df0b88bd67d6fe2eef6">
Evaluation <a href="#cd22920ca9564df0b88bd67d6fe2eef6">#</a>
</h3>
<p>
There's no denying that the Shared Data Model architecture is <em>simple</em>. There's no mapping between different layers, and it's easy to get started. Like the <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">DTO-based Ports and Adapters architecture</a>, you'll find many documentation examples and <em>getting-started</em> guides that work like this. In a sense, you can say that it's what the ASP.NET framework, or, perhaps particularly the Entity Framework (EF), 'wants you to do'. To be fair, I find ASP.NET to be reasonably unopinionated, so what inveigling you may run into may be mostly attributable to EF.
</p>
<p>
While it may feel nice that it's easy to get started, <a href="/2024/05/13/gratification">instant gratification often comes at a cost</a>. Consider the <code>Table</code> class shown here. Because of various constraints imposed by EF and the JSON and XML serializers, it has no encapsulation. One thing is that the sophisticated <a href="/2018/06/25/visitor-as-a-sum-type">Visitor-encoded</a> <code>Table</code> class introduced in the article <a href="/2023/12/25/serializing-restaurant-tables-in-c">Serializing restaurant tables in C#</a> is completely out of the question, but you can't even add a required constructor like this one:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">Table</span>(<span style="color:blue;">int</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>)
{
Capacity = <span style="font-weight:bold;color:#1f377f;">capacity</span>;
}</pre>
</p>
<p>
Granted, it seems to work with both EF and the JSON serializer, which I suppose is a recent development, but it doesn't work with the XML serializer, which requires that
</p>
<blockquote>
<p>
"A class must have a parameterless constructor to be serialized by <strong>XmlSerializer</strong>."
</p>
<footer><cite><a href="https://learn.microsoft.com/dotnet/standard/serialization/introducing-xml-serialization">XML serialization</a></cite>, Microsoft documentation, 2023-04-05, retrieved 2024-07-27, their emphasis</footer>
</blockquote>
<p>
Even if this, too, changes in the future, DTO-based designs are at odds with encapsulation. If you doubt the veracity of that statement, I challenge you to complete <a href="/2024/06/12/simpler-encapsulation-with-immutability">the Priority Collection kata</a> with serializable DTOs.
</p>
<p>
Another problem with the Shared Data Model architecture is that it so easily decays to a <a href="https://wiki.c2.com/?BigBallOfMud">Big Ball of Mud</a>. Even though the above architecture diagram hollowly insists that layering is still possible, a Shared Data Model is an attractor of behaviour. You'll soon find that a class like <code>Table</code> has methods that serve presentation concerns, others that implement business logic, and others again that address persistence issues. It has become a <a href="https://en.wikipedia.org/wiki/God_object">God Class</a>.
</p>
<p>
From these problems it doesn't follow that the architecture doesn't have merit. If you're developing a <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a>-heavy application with a user interface (UI) that's merely a glorified table view, this could be a good choice. You <em>would</em> be coupling the UI to the database, so that if you need to change how the UI works, you might also have to modify the database schema, or vice versa.
</p>
<p>
This is still not an indictment, but merely an observation of consequences. If you can live with them, then choose the Shared Data Model architecture. I can easily imagine application types where that would be the case.
</p>
<h3 id="194d1086b32b49958ad88e5325b4e1f1">
Conclusion <a href="#194d1086b32b49958ad88e5325b4e1f1">#</a>
</h3>
<p>
In the Shared Data Model architecture you use a single model (here, a class) to handle all application concerns: UI, business logic, data access. While this shows a blatant disregard for the notion of separation of concerns, no law states that you must, always, separate concerns.
</p>
<p>
Sometimes it's okay to mix concerns, and then the Shared Data Model architecture is dead simple. Just make sure that you know when it's okay.
</p>
<p>
While this architecture is the ultimate in simplicity, it's also quite constrained. The third and final data architecture I'll cover, on the other hand, offers the ultimate in flexibility, at the expense (not surprisingly) of some complexity.
</p>
<p>
<strong>Next:</strong> <a href="/2024/08/12/using-only-a-domain-model-to-persist-restaurant-table-configurations">Using only a Domain Model to persist restaurant table configurations</a>.
</p>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Using Ports and Adapters to persist restaurant table configurationshttps://blog.ploeh.dk/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations2024-07-29T08:05:00+00:00Mark Seemann
<div id="post">
<p>
<em>A data architecture example in C# and ASP.NET.</em>
</p>
<p>
This is part of a <a href="/2024/07/25/three-data-architectures-for-the-server">small article series on data architectures</a>. In the first instalment, you'll see the outline of a Ports and Adapters implementation. As the introductory article explains, the example code shows how to create a new restaurant table configuration, or how to display an existing resource. The sample code base is an ASP.NET 8.0 <a href="https://en.wikipedia.org/wiki/REST">REST</a> API.
</p>
<p>
Keep in mind that while the sample code does store data in a relational database, the term <em>table</em> in this article mainly refers to physical tables, rather than database tables.
</p>
<p>
While Ports and Adapters architecture diagrams are usually drawn as concentric circles, you can also draw (subsets of) it as more traditional layered diagrams:
</p>
<p>
<img src="/content/binary/three-layer-table-architecture.png" alt="Three-layer architecture diagram showing TableDto, Table, and TableEntity as three vertically stacked boxes, with arrows between them.">
</p>
<p>
Here, the arrows indicate mappings, not dependencies.
</p>
<h3 id="5e95ae96906c43f9aee53cfbd680a378">
HTTP interaction <a href="#5e95ae96906c43f9aee53cfbd680a378">#</a>
</h3>
<p>
A client can create a new table with a <code>POST</code> HTTP request:
</p>
<p>
<pre>POST /tables HTTP/1.1
content-type: application/json
{ <span style="color:#2e75b6;">"communalTable"</span>: { <span style="color:#2e75b6;">"capacity"</span>: 16 } }</pre>
</p>
<p>
Which might elicit a response like this:
</p>
<p>
<pre>HTTP/1.1 201 Created
Location: https://example.com/Tables/844581613e164813aa17243ff8b847af</pre>
</p>
<p>
Clients can later use the address indicated by the <code>Location</code> header to retrieve a representation of the resource:
</p>
<p>
<pre>GET /Tables/844581613e164813aa17243ff8b847af HTTP/1.1
accept: application/json</pre>
</p>
<p>
Which would result in this response:
</p>
<p>
<pre>HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{<span style="color:#2e75b6;">"communalTable"</span>:{<span style="color:#2e75b6;">"capacity"</span>:16}}</pre>
</p>
<p>
By default, ASP.NET handles and returns JSON. Later in this article you'll see how well it deals with other data formats.
</p>
<h3 id="95914d7bd8c845d2b30d8ddc029c1711">
Boundary <a href="#95914d7bd8c845d2b30d8ddc029c1711">#</a>
</h3>
<p>
ASP.NET supports some variation of the <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">model-view-controller</a> (MVC) pattern, and Controllers handle HTTP requests. At the outset, the <em>action method</em> that handles the <code>POST</code> request looks like this:
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpPost</span>]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Post</span>(<span style="color:#2b91af;">TableDto</span> <span style="font-weight:bold;color:#1f377f;">dto</span>)
{
<span style="color:#2b91af;">ArgumentNullException</span>.<span style="color:#74531f;">ThrowIfNull</span>(<span style="font-weight:bold;color:#1f377f;">dto</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">id</span> = <span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">NewGuid</span>();
<span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">repository</span>.<span style="font-weight:bold;color:#74531f;">Create</span>(<span style="font-weight:bold;color:#1f377f;">id</span>, <span style="font-weight:bold;color:#1f377f;">dto</span>.<span style="font-weight:bold;color:#74531f;">ToTable</span>()).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">CreatedAtActionResult</span>(<span style="color:blue;">nameof</span>(<span style="font-weight:bold;color:#74531f;">Get</span>), <span style="color:blue;">null</span>, <span style="color:blue;">new</span> { id = <span style="font-weight:bold;color:#1f377f;">id</span>.<span style="font-weight:bold;color:#74531f;">ToString</span>(<span style="color:#a31515;">"N"</span>) }, <span style="color:blue;">null</span>);
}</pre>
</p>
<p>
As is <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatic</a> in ASP.NET, input and output are modelled by <a href="https://en.wikipedia.org/wiki/Data_transfer_object">data transfer objects</a> (DTOs), in this case called <code>TableDto</code>. I've already covered this little object model in the article <a href="/2023/12/25/serializing-restaurant-tables-in-c">Serializing restaurant tables in C#</a>, so I'm not going to repeat it here.
</p>
<p>
The <code>ToTable</code> method, on the other hand, is a good example of how trying to cut corners lead to more complicated code:
</p>
<p>
<pre><span style="color:blue;">internal</span> <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#74531f;">ToTable</span>()
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">candidate</span> =
<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateSingle</span>(SingleTable?.Capacity ?? -1, SingleTable?.MinimalReservation ?? -1);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">candidate</span> <span style="color:blue;">is</span> { })
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">candidate</span>.Value;
<span style="font-weight:bold;color:#1f377f;">candidate</span> = <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateCommunal</span>(CommunalTable?.Capacity ?? -1);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">candidate</span> <span style="color:blue;">is</span> { })
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">candidate</span>.Value;
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">InvalidOperationException</span>(<span style="color:#a31515;">"Invalid TableDto."</span>);
}</pre>
</p>
<p>
Compare it to the <code>TryParse</code> method in the <a href="/2023/12/25/serializing-restaurant-tables-in-c">Serializing restaurant tables in C#</a> article. That one is simpler, and less error-prone.
</p>
<p>
I think that I wrote <code>ToTable</code> that way because I didn't want to deal with error handling in the Controller, and while I test-drove the code, I never wrote a test that supply malformed input. I should have, and so should you, but this is demo code, and I never got around to it.
</p>
<p>
Enough about that. The other action method handles <code>GET</code> requests:
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpGet</span>(<span style="color:#a31515;">"</span><span style="color:#0073ff;">{</span>id<span style="color:#0073ff;">}</span><span style="color:#a31515;">"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Get</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!<span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">TryParseExact</span>(<span style="font-weight:bold;color:#1f377f;">id</span>, <span style="color:#a31515;">"N"</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">guid</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">BadRequestResult</span>();
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">table</span> = <span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">repository</span>.<span style="font-weight:bold;color:#74531f;">Read</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">table</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">NotFoundResult</span>();
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">OkObjectResult</span>(<span style="color:#2b91af;">TableDto</span>.<span style="color:#74531f;">From</span>(<span style="font-weight:bold;color:#1f377f;">table</span>.Value));
}</pre>
</p>
<p>
The static <code>TableDto.From</code> method is identical to the <code>ToDto</code> method from the <a href="/2023/12/25/serializing-restaurant-tables-in-c">Serializing restaurant tables in C#</a> article, just with a different name.
</p>
<p>
To summarize so far: At the boundary of the application, Controller methods receive or return <code>TableDto</code> objects, which are mapped to and from the Domain Model named <code>Table</code>.
</p>
<h3 id="b5cbc5042c01488da08a856d84d3f17e">
Domain Model <a href="#b5cbc5042c01488da08a856d84d3f17e">#</a>
</h3>
<p>
The Domain Model <code>Table</code> is also identical to the code shown in <a href="/2023/12/25/serializing-restaurant-tables-in-c">Serializing restaurant tables in C#</a>. In order to comply with the <a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion Principle</a> (DIP), mapping to and from <code>TableDto</code> is defined on the latter. The DTO, being an implementation detail, may depend on the abstraction (the Domain Model), but not the other way around.
</p>
<p>
In the same spirit, conversions to and from the database are defined entirely within the <code>repository</code> implementation.
</p>
<h3 id="84b01fa88e8541f5afbb9aa04f454645">
Data access layer <a href="#84b01fa88e8541f5afbb9aa04f454645">#</a>
</h3>
<p>
Keeping the example consistent, the code base also models data access with C# classes. It uses <a href="https://learn.microsoft.com/ef">Entity Framework</a> to read from and write to <a href="https://en.wikipedia.org/wiki/Microsoft_SQL_Server">SQL Server</a>. The class that models a row in the database is also a kind of DTO, even though here it's idiomatically called an <em>entity:</em>
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">partial</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">TableEntity</span>
{
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Id { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:#2b91af;">Guid</span> PublicId { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Capacity { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">int</span>? MinimalReservation { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
}</pre>
</p>
<p>
I had a command-line tool scaffold the code for me, and since <a href="/2023/09/18/do-orms-reduce-the-need-for-mapping">I don't usually live in that world</a>, I don't know why it's a <code>partial class</code>. It seems to be working, though.
</p>
<p>
The <code>SqlTablesRepository</code> class implements the mapping between <code>Table</code> and <code>TableEntity</code>. For instance, the <code>Create</code> method looks like this:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span> <span style="font-weight:bold;color:#74531f;">Create</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>, <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#1f377f;">table</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">entity</span> = <span style="font-weight:bold;color:#1f377f;">table</span>.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span> <span style="color:#2b91af;">TableToEntityConverter</span>(<span style="font-weight:bold;color:#1f377f;">id</span>));
<span style="color:blue;">await</span> context.Tables.<span style="font-weight:bold;color:#74531f;">AddAsync</span>(<span style="font-weight:bold;color:#1f377f;">entity</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="color:blue;">await</span> context.<span style="font-weight:bold;color:#74531f;">SaveChangesAsync</span>().<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
}</pre>
</p>
<p>
That looks simple, but is only because all the work is done by the <code>TableToEntityConverter</code>, which is a nested class:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">TableToEntityConverter</span> : <span style="color:#2b91af;">ITableVisitor</span><<span style="color:#2b91af;">TableEntity</span>>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Guid</span> id;
<span style="color:blue;">public</span> <span style="color:#2b91af;">TableToEntityConverter</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="color:blue;">this</span>.id = <span style="font-weight:bold;color:#1f377f;">id</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">TableEntity</span> <span style="font-weight:bold;color:#74531f;">VisitCommunal</span>(<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">TableEntity</span>
{
PublicId = id,
Capacity = (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">capacity</span>,
};
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">TableEntity</span> <span style="font-weight:bold;color:#74531f;">VisitSingle</span>(
<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">capacity</span>,
<span style="color:#2b91af;">NaturalNumber</span> <span style="font-weight:bold;color:#1f377f;">minimalReservation</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">TableEntity</span>
{
PublicId = id,
Capacity = (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">capacity</span>,
MinimalReservation = (<span style="color:blue;">int</span>)<span style="font-weight:bold;color:#1f377f;">minimalReservation</span>,
};
}
}</pre>
</p>
<p>
Mapping the other way is easier, so the <code>SqlTablesRepository</code> does it inline in the <code>Read</code> method:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">Table</span>?> <span style="font-weight:bold;color:#74531f;">Read</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">entity</span> = <span style="color:blue;">await</span> context.Tables
.<span style="font-weight:bold;color:#74531f;">SingleOrDefaultAsync</span>(<span style="font-weight:bold;color:#1f377f;">t</span> => <span style="font-weight:bold;color:#1f377f;">t</span>.PublicId <span style="font-weight:bold;color:#74531f;">==</span> <span style="font-weight:bold;color:#1f377f;">id</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">entity</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">null</span>;
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">entity</span>.MinimalReservation <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateCommunal</span>(<span style="font-weight:bold;color:#1f377f;">entity</span>.Capacity);
<span style="font-weight:bold;color:#8f08c4;">else</span>
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateSingle</span>(
<span style="font-weight:bold;color:#1f377f;">entity</span>.Capacity,
<span style="font-weight:bold;color:#1f377f;">entity</span>.MinimalReservation.Value);
}</pre>
</p>
<p>
Similar to the case of the DTO, mapping between <code>Table</code> and <code>TableEntity</code> is the responsibility of the <code>SqlTablesRepository</code> class, since data persistence is an implementation detail. According to the DIP it shouldn't be part of the Domain Model, and it isn't.
</p>
<h3 id="77dda87b99ac49bf91d08079e252fc50">
XML formats <a href="#77dda87b99ac49bf91d08079e252fc50">#</a>
</h3>
<p>
That covers the basics, but how well does this kind of architecture stand up to changing requirements?
</p>
<p>
One axis of variation is when a service needs to support multiple representations. In this example, I'll imagine that the service also needs to support not just one, but two, XML formats.
</p>
<p>
Granted, you may not run into that particular requirement that often, but it's typical of a kind of change that you're likely to run into. In REST APIs, for example, <a href="/2015/06/22/rest-implies-content-negotiation">you should use content negotiation for versioning</a>, and that's the same kind of problem.
</p>
<p>
To be fair, application code also changes for a variety of other reasons, including new features, changes to business logic, etc. I can't possibly cover all, though, and many of these are much better described than changes in wire formats.
</p>
<p>
As described in the <a href="/2024/07/25/three-data-architectures-for-the-server">introduction article</a>, ideally the XML should support a format implied by these examples:
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">></span>
<span style="color:blue;"><</span><span style="color:#a31515;">single-table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>4<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>3<span style="color:blue;"></</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">single-table</span><span style="color:blue;">></span></pre>
</p>
<p>
Notice that while these two examples have different root elements, they're still considered to both represent <em>a table</em>. Although <a href="/2023/10/16/at-the-boundaries-static-types-are-illusory">at the boundaries, static types are illusory</a> we may still, loosely speaking, consider both of those XML documents as belonging to the same 'type'.
</p>
<p>
To be honest, if there's a way to support this kind of <a href="/2024/04/15/services-share-schema-and-contract-not-class">schema</a> by defining DTOs to be serialized and deserialized, I don't know what it looks like. That's not meant to imply that it's impossible. There's often an epistemological problem associated with proving things impossible, so I'll just leave it there.
</p>
<p>
To be clear, it's not that I don't know how to support that kind of schema at all. I do, as the article <a href="/2024/08/12/using-only-a-domain-model-to-persist-restaurant-table-configurations">Using only a Domain Model to persist restaurant table configurations</a> will show. I just don't know how to do it with DTO-based serialisation.
</p>
<h3 id="6b0409d4-67fd-4e86-9a83-538fa5b690d4">
Element-biased XML <a href="#6b0409d4-67fd-4e86-9a83-538fa5b690d4">#</a>
</h3>
<p>
Instead of the above XML schema, I will, instead explore how hard it is to support a variant schema, implied by these two examples:
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>communal<span style="color:blue;"></</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">table</span><span style="color:blue;">></span>
<span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>single<span style="color:blue;"></</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>4<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>3<span style="color:blue;"></</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">table</span><span style="color:blue;">></span></pre>
</p>
<p>
This variation shares the same <code><span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;">></span></code> root element and instead distinguishes between the two kinds of table with a <code><span style="color:blue;"><</span><span style="color:#a31515;">type</span><span style="color:blue;">></span></code> discriminator.
</p>
<p>
This kind of schema we can define with a DTO:
</p>
<p>
<pre>[<span style="color:#2b91af;">XmlRoot</span>(<span style="color:#a31515;">"table"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">ElementBiasedTableXmlDto</span>
{
[<span style="color:#2b91af;">XmlElement</span>(<span style="color:#a31515;">"type"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">string</span>? Type { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">XmlElement</span>(<span style="color:#a31515;">"capacity"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Capacity { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">XmlElement</span>(<span style="color:#a31515;">"minimal-reservation"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">int</span>? MinimalReservation { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">ShouldSerializeMinimalReservation</span>() =>
MinimalReservation.HasValue;
<span style="color:green;">// Mapping methods not shown here...</span>
}</pre>
</p>
<p>
As you may have already noticed, however, this isn't the same type as <code>TableJsonDto</code>, so how are we going to implement the Controller methods that receive and send objects of this type?
</p>
<h3 id="28e522bca7b04f94a68c00f15f0d7243">
Posting XML <a href="#28e522bca7b04f94a68c00f15f0d7243">#</a>
</h3>
<p>
The service should still accept JSON as shown above, but now, additionally, it should also support HTTP requests like this one:
</p>
<p>
<pre>POST /tables HTTP/1.1
content-type: application/xml
<span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;">><</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>communal<span style="color:blue;"></</span><span style="color:#a31515;">type</span><span style="color:blue;">><</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></</span><span style="color:#a31515;">table</span><span style="color:blue;">></span></pre>
</p>
<p>
How do you implement this new feature?
</p>
<p>
My first thought was to add a <code>Post</code> overload to the Controller:
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpPost</span>]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Post</span>(<span style="color:#2b91af;">ElementBiasedTableXmlDto</span> <span style="font-weight:bold;color:#1f377f;">dto</span>)
{
<span style="color:#2b91af;">ArgumentNullException</span>.<span style="color:#74531f;">ThrowIfNull</span>(<span style="font-weight:bold;color:#1f377f;">dto</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">id</span> = <span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">NewGuid</span>();
<span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">repository</span>.<span style="font-weight:bold;color:#74531f;">Create</span>(<span style="font-weight:bold;color:#1f377f;">id</span>, <span style="font-weight:bold;color:#1f377f;">dto</span>.<span style="font-weight:bold;color:#74531f;">ToTable</span>()).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">CreatedAtActionResult</span>(
<span style="color:blue;">nameof</span>(<span style="font-weight:bold;color:#74531f;">Get</span>),
<span style="color:blue;">null</span>,
<span style="color:blue;">new</span> { id = <span style="font-weight:bold;color:#1f377f;">id</span>.<span style="font-weight:bold;color:#74531f;">ToString</span>(<span style="color:#a31515;">"N"</span>) },
<span style="color:blue;">null</span>);
}</pre>
</p>
<p>
I just copied and pasted the original <code>Post</code> method and changed the type of the <code>dto</code> parameter. I also had to add a <code>ToTable</code> conversion to <code>ElementBiasedTableXmlDto</code>:
</p>
<p>
<pre><span style="color:blue;">internal</span> <span style="color:#2b91af;">Table</span> <span style="font-weight:bold;color:#74531f;">ToTable</span>()
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (Type == <span style="color:#a31515;">"single"</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">t</span> = <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateSingle</span>(Capacity, MinimalReservation ?? 0);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">t</span> <span style="color:blue;">is</span> { })
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">t</span>.Value;
}
<span style="font-weight:bold;color:#8f08c4;">if</span> (Type == <span style="color:#a31515;">"communal"</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">t</span> = <span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">TryCreateCommunal</span>(Capacity);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">t</span> <span style="color:blue;">is</span> { })
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">t</span>.Value;
}
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">InvalidOperationException</span>(<span style="color:#a31515;">"Invalid Table DTO."</span>);
}</pre>
</p>
<p>
While all of that compiles, it doesn't work.
</p>
<p>
When you attempt to <code>POST</code> a request against the service, the ASP.NET framework now throws an <code>AmbiguousMatchException</code> indicating that "The request matched multiple endpoints". Which is understandable.
</p>
<p>
This lead me to the first round of <a href="/2023/10/02/dependency-whac-a-mole">Framework Whac-A-Mole</a>. What I'd like to do is to select the appropriate action method based on <code>content-type</code> or <code>accept</code> headers. How does one do that?
</p>
<p>
After some web searching, I came across <a href="https://stackoverflow.com/a/1045616/126014">a Stack Overflow answer</a> that seemed to indicate a way forward.
</p>
<h3 id="5f262b2b42c542148b62223f0fb3d9a9">
Selecting the right action method <a href="#5f262b2b42c542148b62223f0fb3d9a9">#</a>
</h3>
<p>
One way to address the issue is to implement a custom <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.mvc.actionconstraints.actionmethodselectorattribute">ActionMethodSelectorAttribute</a>:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">SelectTableActionMethodAttribute</span> : <span style="color:#2b91af;">ActionMethodSelectorAttribute</span>
{
<span style="color:blue;">public</span> <span style="color:blue;">override</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">IsValidForRequest</span>(<span style="color:#2b91af;">RouteContext</span> <span style="font-weight:bold;color:#1f377f;">routeContext</span>, <span style="color:#2b91af;">ActionDescriptor</span> <span style="font-weight:bold;color:#1f377f;">action</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">action</span> <span style="color:blue;">is</span> <span style="color:blue;">not</span> <span style="color:#2b91af;">ControllerActionDescriptor</span> <span style="font-weight:bold;color:#1f377f;">cad</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">false</span>;
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">cad</span>.Parameters.Count != 1)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">false</span>;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">dtoType</span> = <span style="font-weight:bold;color:#1f377f;">cad</span>.Parameters[0].ParameterType;
<span style="color:green;">// Demo code only. This doesn't take into account a possible charset</span>
<span style="color:green;">// parameter. See RFC 9110, section 8.3</span>
<span style="color:green;">// (https://www.rfc-editor.org/rfc/rfc9110#field.content-type) for more</span>
<span style="color:green;">// information.</span>
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">routeContext</span>?.HttpContext.Request.ContentType == <span style="color:#a31515;">"application/json"</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">dtoType</span> <span style="font-weight:bold;color:#74531f;">==</span> <span style="color:blue;">typeof</span>(<span style="color:#2b91af;">TableJsonDto</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">routeContext</span>?.HttpContext.Request.ContentType == <span style="color:#a31515;">"application/xml"</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">dtoType</span> <span style="font-weight:bold;color:#74531f;">==</span> <span style="color:blue;">typeof</span>(<span style="color:#2b91af;">ElementBiasedTableXmlDto</span>);
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">false</span>;
}
}</pre>
</p>
<p>
As the code comment suggests, this isn't as robust as it should be. A <code>content-type</code> header may also look like this:
</p>
<p>
<pre>Content-Type: application/json; charset=utf-8</pre>
</p>
<p>
The exact string equality check shown above would fail in such a scenario, suggesting that a more sophisticated implementation is warranted. I'll skip that for now, since this demo code already compromises on the overall XML schema. For an example of more robust <a href="https://en.wikipedia.org/wiki/Content_negotiation">content negotiation</a> implementations, see <a href="/2024/08/12/using-only-a-domain-model-to-persist-restaurant-table-configurations">Using only a Domain Model to persist restaurant table configurations</a>.
</p>
<p>
Adorn both <code>Post</code> action methods with this custom attribute, and the service now handles both formats:
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpPost</span>, <span style="color:#2b91af;">SelectTableActionMethod</span>]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Post</span>(<span style="color:#2b91af;">TableJsonDto</span> <span style="font-weight:bold;color:#1f377f;">dto</span>)
<span style="color:green;">// ...</span>
[<span style="color:#2b91af;">HttpPost</span>, <span style="color:#2b91af;">SelectTableActionMethod</span>]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Post</span>(<span style="color:#2b91af;">ElementBiasedTableXmlDto</span> <span style="font-weight:bold;color:#1f377f;">dto</span>)
<span style="color:green;">// ...</span></pre>
</p>
<p>
While that handles <code>POST</code> requests, it doesn't implement content negotiation for <code>GET</code> requests.
</p>
<h3 id="4cc040875e3349d996b3711a6fea20c0">
Getting XML <a href="#4cc040875e3349d996b3711a6fea20c0">#</a>
</h3>
<p>
In order to <code>GET</code> an XML representation, clients can supply an <code>accept</code> header value:
</p>
<p>
<pre>GET /Tables/153f224c91fb4403988934118cc14024 HTTP/1.1
accept: application/xml</pre>
</p>
<p>
which will reply with
</p>
<p>
<pre>HTTP/1.1 200 OK
Content-Length: 59
Content-Type: application/xml; charset=utf-8
<span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;">><</span><span style="color:#a31515;">type</span><span style="color:blue;">></span>communal<span style="color:blue;"></</span><span style="color:#a31515;">type</span><span style="color:blue;">><</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></</span><span style="color:#a31515;">table</span><span style="color:blue;">></span></pre>
</p>
<p>
How do we implement that?
</p>
<p>
Keep in mind that since this data-architecture variation uses two different DTOs to model JSON and XML, respectively, an action method can't just return an object of a single type and hope that the ASP.NET framework takes care of the rest. Again, I'm aware of middleware that'll deal nicely with this kind of problem, but not in this architecture; see <a href="/2024/08/12/using-only-a-domain-model-to-persist-restaurant-table-configurations">Using only a Domain Model to persist restaurant table configurations</a> for such a solution.
</p>
<p>
The best I could come up with, given the constraints I'd imposed on myself, then, was this:
</p>
<p>
<pre>[<span style="color:#2b91af;">HttpGet</span>(<span style="color:#a31515;">"</span><span style="color:#0073ff;">{</span>id<span style="color:#0073ff;">}</span><span style="color:#a31515;">"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">async</span> <span style="color:#2b91af;">Task</span><<span style="color:#2b91af;">IActionResult</span>> <span style="font-weight:bold;color:#74531f;">Get</span>(<span style="color:blue;">string</span> <span style="font-weight:bold;color:#1f377f;">id</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!<span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">TryParseExact</span>(<span style="font-weight:bold;color:#1f377f;">id</span>, <span style="color:#a31515;">"N"</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">guid</span>))
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">BadRequestResult</span>();
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">table</span> = <span style="color:blue;">await</span> <span style="font-weight:bold;color:#1f377f;">repository</span>.<span style="font-weight:bold;color:#74531f;">Read</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>).<span style="font-weight:bold;color:#74531f;">ConfigureAwait</span>(<span style="color:blue;">false</span>);
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">table</span> <span style="color:blue;">is</span> <span style="color:blue;">null</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">NotFoundResult</span>();
<span style="color:green;">// Demo code only. This doesn't take into account quality values.</span>
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">accept</span> =
<span style="font-weight:bold;color:#1f377f;">httpContextAccessor</span>?.HttpContext?.Request.Headers.Accept.<span style="font-weight:bold;color:#74531f;">ToString</span>();
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">accept</span> == <span style="color:#a31515;">"application/json"</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">OkObjectResult</span>(<span style="color:#2b91af;">TableJsonDto</span>.<span style="color:#74531f;">From</span>(<span style="font-weight:bold;color:#1f377f;">table</span>.Value));
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">accept</span> == <span style="color:#a31515;">"application/xml"</span>)
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">OkObjectResult</span>(<span style="color:#2b91af;">ElementBiasedTableXmlDto</span>.<span style="color:#74531f;">From</span>(<span style="font-weight:bold;color:#1f377f;">table</span>.Value));
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">StatusCodeResult</span>((<span style="color:blue;">int</span>)<span style="color:#2b91af;">HttpStatusCode</span>.NotAcceptable);
}</pre>
</p>
<p>
As the comment suggests, this is once again code that barely passes the few tests that I have, but really isn't production-ready. An <code>accept</code> header may also look like this:
</p>
<p>
<pre>accept: application/xml; q=1.0,application/json; q=0.5</pre>
</p>
<p>
Given such an <code>accept</code> header, the service ought to return an XML representation with the <code>application/xml</code> content type, but instead, this <code>Get</code> method returns <code>406 Not Acceptable</code>.
</p>
<p>
As I've already outlined, I'm not going to fix this problem, as this is only an exploration. It seems that we can already conclude that this style of architecture is ill-suited to deal with this kind of problem. If that's the conclusion, then why spend time fixing outstanding problems?
</p>
<h3 id="6db23995819543c3920bc2e7c5d16bb0">
Attribute-biased XML <a href="#6db23995819543c3920bc2e7c5d16bb0">#</a>
</h3>
<p>
Even so, just to punish myself, apparently, I also tried to add support for an alternative XML format that use attributes to record primitive values. Again, I couldn't make the schema described in the <a href="/2024/07/25/three-data-architectures-for-the-server">introductory article</a> work, but I did manage to add support for XML documents like these:
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;"> </span><span style="color:red;">type</span><span style="color:blue;">=</span>"<span style="color:blue;">communal</span>"<span style="color:blue;"> </span><span style="color:red;">capacity</span><span style="color:blue;">=</span>"<span style="color:blue;">12</span>"<span style="color:blue;"> /></span>
<span style="color:blue;"><</span><span style="color:#a31515;">table</span><span style="color:blue;"> </span><span style="color:red;">type</span><span style="color:blue;">=</span>"<span style="color:blue;">single</span>"<span style="color:blue;"> </span><span style="color:red;">capacity</span><span style="color:blue;">=</span>"<span style="color:blue;">4</span>"<span style="color:blue;"> </span><span style="color:red;">minimal-reservation</span><span style="color:blue;">=</span>"<span style="color:blue;">3</span>"<span style="color:blue;"> /></span></pre>
</p>
<p>
The code is similar to what I've already shown, so I'll only list the DTO:
</p>
<p>
<pre>[<span style="color:#2b91af;">XmlRoot</span>(<span style="color:#a31515;">"table"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">AttributeBiasedTableXmlDto</span>
{
[<span style="color:#2b91af;">XmlAttribute</span>(<span style="color:#a31515;">"type"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">string</span>? Type { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">XmlAttribute</span>(<span style="color:#a31515;">"capacity"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Capacity { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
[<span style="color:#2b91af;">XmlAttribute</span>(<span style="color:#a31515;">"minimal-reservation"</span>)]
<span style="color:blue;">public</span> <span style="color:blue;">int</span> MinimalReservation { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">ShouldSerializeMinimalReservation</span>() => 0 < MinimalReservation;
<span style="color:green;">// Mapping methods not shown here...</span>
}</pre>
</p>
<p>
This DTO looks a lot like the <code>ElementBiasedTableXmlDto</code> class, only it adorns properties with <code>XmlAttribute</code> rather than <code>XmlElement</code>.
</p>
<h3 id="b3b79b4075b1457dbe92a1a4aae944c6">
Evaluation <a href="#b3b79b4075b1457dbe92a1a4aae944c6">#</a>
</h3>
<p>
Even though I had to compromise on essential goals, I wasted an appalling amount of time and energy on <a href="https://projects.csail.mit.edu/gsb/old-archive/gsb-archive/gsb2000-02-11.html">yak shaving</a> and <a href="/2023/10/02/dependency-whac-a-mole">Framework Whac-A-Mole</a>. The DTO-based approach to modelling external resources really doesn't work when you need to do substantial content negotiation.
</p>
<p>
Even so, a DTO-based Ports and Adapters architecture may be useful when that's not a concern. If, instead of a REST API, you're developing a web site, you'll typically not need to vary representation independently of resource. In other words, a web page is likely to have at most one underlying model.
</p>
<p>
Compared to other large frameworks I've run into, ASP.NET is fairly unopinionated. Even so, the idiomatic way to use it is based on DTOs. DTOs to represent external data. DTOs to represent UI components. DTOs to represent database rows (although they're often called <em>entities</em> in that context). You'll find a ton of examples using this data architecture, so it's incredibly well-described. If you run into problems, odds are that someone has blazed a trail before you.
</p>
<p>
Even outside of .NET, <a href="https://alistair.cockburn.us/hexagonal-architecture/">this kind of architecture is well-known</a>. While I've learned a thing or two from experience, I've picked up a lot of my knowledge about software architecture from people like <a href="https://martinfowler.com/">Martin Fowler</a> and <a href="https://en.wikipedia.org/wiki/Robert_C._Martin">Robert C. Martin</a>.
</p>
<p>
When you also apply the Dependency Inversion Principle, you'll get good separations of concerns. This aspect of Ports and Adapters is most explicitly described in <a href="/ref/clean-architecture">Clean Architecture</a>. For example, a change to the UI generally doesn't affect the database. You may find that example ridiculous, because why should it, but consult the article <a href="/2024/08/05/using-a-shared-data-model-to-persist-restaurant-table-configurations">Using a Shared Data Model to persist restaurant table configurations</a> to see how this may happen.
</p>
<p>
The major drawbacks of the DTO-based data architecture is that much mapping is required. With three different DTOs (e.g. JSON DTO, Domain Model, and <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">ORM</a> Entity), you need four-way translation as indicated in the above figure. People often complain about all that mapping, and no: <a href="/2023/09/18/do-orms-reduce-the-need-for-mapping">ORMs don't reduce the need for mapping</a>.
</p>
<p>
Another problem is that this style of architecture is <em>complicated</em>. As I've <a href="/2016/03/18/functional-architecture-is-ports-and-adapters">argued elsewhere</a>, Ports and Adapters often constitute an unstable equilibrium. While you can make it work, it requires a level of sophistication and maturity among team members that is not always present. And when it goes wrong, it may quickly deteriorate into a <a href="https://wiki.c2.com/?BigBallOfMud">Big Ball of Mud</a>.
</p>
<h3 id="162f6985f9674d6397869620b904de1f">
Conclusion <a href="#162f6985f9674d6397869620b904de1f">#</a>
</h3>
<p>
A DTO-based Ports and Adapters architecture is well-described and has good separation of concerns. In this article, however, we've seen that it doesn't deal successfully with realistic content negotiation. While that may seem like a shortcoming, it's a drawback that you may be able to live with. Particularly if you don't need to do content negotiation at all.
</p>
<p>
This way of organizing code around data is quite common. It's often the default data architecture, and I sometimes get the impression that a development team has 'chosen' to use it without considering alternatives.
</p>
<p>
It's not a bad architecture despite evidence to the contrary in this article. The scenario examined here may not be relevant. The main drawback of having all these objects playing different roles is all the mapping that's required.
</p>
<p>
The next data architecture attempts to address that concern.
</p>
<p>
<strong>Next:</strong> <a href="/2024/08/05/using-a-shared-data-model-to-persist-restaurant-table-configurations">Using a Shared Data Model to persist restaurant table configurations</a>.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Three data architectures for the serverhttps://blog.ploeh.dk/2024/07/25/three-data-architectures-for-the-server2024-07-25T18:30:00+00:00Mark Seemann
<div id="post">
<p>
<em>A comparison, for educational purposes.</em>
</p>
<p>
<em>Use the right tool for the job.</em> How often have you encountered that phrase when discussing software architecture?
</p>
<p>
There's nothing wrong with the sentiment per se, but it's almost devoid of meaning. It doesn't pass the 'not test'. Try to negate it and imagine if anyone would seriously hold that belief: <em>Don't use the right tool for the job,</em> said no-one ever.
</p>
<p>
Even so, the underlying idea is that there are better and worse ways to solve problems. In software architecture too. It follows that you should choose the better solution.
</p>
<p>
How to do that requires skill and experience. When planning a good software architecture, an important consideration is how it'll handle future requirements. This seems to indicate that an architect should be able to predict the future in order to pick the best architecture. Which is, in general, not possible. Predicting the future is not the topic of this article.
</p>
<p>
There is, however, a more practical issue related to the notion of using the right tool for the job. One that we <em>can</em> address.
</p>
<h3 id="19b9dea780d2475fb4e0311dc1cc6893">
Choice <a href="#19b9dea780d2475fb4e0311dc1cc6893">#</a>
</h3>
<p>
In order to choose the better solution, you need to be aware of alternatives. You can't choose if there's nothing to choose from. This seems obvious, but a flowchart may drive home the point in an even stronger fashion.
</p>
<p>
<img src="/content/binary/flowchart-without-choice.png" alt="A flowchart diagram, but without any choice at the decision shape.">
</p>
<p>
On the other hand, if you have options, you're now in a position to choose.
</p>
<p>
<img src="/content/binary/flowchart-with-choice.png" alt="A flowchart diagram, now with three options available from the decision shape.">
</p>
<p>
In order to make a decision, you must be able to identify alternatives. This is hardly earth-shattering, but perhaps a bit abstract. To make it concrete, in this article, I'll look at a particular example.
</p>
<h3 id="4b9045825d9a47c3a6d8f0af1de89a2c">
Default data architecture <a href="#4b9045825d9a47c3a6d8f0af1de89a2c">#</a>
</h3>
<p>
Many applications need some sort of persistent storage. Particularly when it comes to (relational) database-based systems, I've seen more than one organization defaulting to a single data architecture: A presentation layer with View Models, a business logic layer with Domain Models, and a data access layer with ORM objects. A few decades ago, you'd typically see that model illustrated with horizontal layers. This is no longer en vogue. Today, most organizations that I consult with will tell me that they've decided on Ports and Adapters. Even so, if you do it right, <a href="/2013/12/03/layers-onions-ports-adapters-its-all-the-same">it's the same architecture</a>.
</p>
<p>
Reusing a diagram from <a href="/2024/07/08/should-interfaces-be-asynchronous">a recent article</a>, we may draw it like this:
</p>
<p>
<img src="/content/binary/ports-and-adapters-dependency-graph-2.png" alt="Ports and Adapters diagram, with arrows pointing inward.">
</p>
<p>
The architect or senior developer who made that decision is obviously aware of some of the lore in the industry. He or she can often name that data architecture as either Ports and Adapters, <a href="https://alistair.cockburn.us/hexagonal-architecture/">Hexagonal Architecture</a>, <a href="/ref/clean-architecture">Clean Architecture</a>, or, more rarely, <a href="https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/">Onion Architecture</a>.
</p>
<p>
I still get the impression that this way of arranging code was chosen by default, without much deliberation. I see it so often that it strikes me as a 'default architecture'. Are architects aware of alternatives? Can they compare the benefits and drawbacks of each alternative?
</p>
<h3 id="38ef737999f04f2d8c8d9fe7a44b47be">
Three alternatives <a href="#38ef737999f04f2d8c8d9fe7a44b47be">#</a>
</h3>
<p>
As an example, I'll explore three alternative data architectures, one of them being Ports and Adapters. My goal with this is only to raise awareness. Since I rarely (if ever) see my customers use anything other than Ports and Adapters, I think some readers may benefit from seeing some alternatives.
</p>
<p>
I'll show three ways to organize data with code, but that doesn't imply that these are the only three options. At the very least, some hybrid combinations are also possible. It's also possible that a fourth or fifth alternative exists, and I'm just not aware of it.
</p>
<p>
In three articles, you'll see each data architecture explored in more detail.
</p>
<ul>
<li><a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">Using Ports and Adapters to persist restaurant table configurations</a></li>
<li><a href="/2024/08/05/using-a-shared-data-model-to-persist-restaurant-table-configurations">Using a Shared Data Model to persist restaurant table configurations</a></li>
<li><a href="/2024/08/12/using-only-a-domain-model-to-persist-restaurant-table-configurations">Using only a Domain Model to persist restaurant table configurations</a></li>
</ul>
<p>
As the titles suggest, all three examples will attempt to address the same problem: How to persist restaurant table configuration for a restaurant. The scenario is the same as already outlined in the article <a href="/2023/12/04/serialization-with-and-without-reflection">Serialization with and without Reflection</a>, and the example code base also attempts to follow the external data format of those articles.
</p>
<h3 id="0b2358ba517444eeb990d1ff72613b82">
Data formats <a href="#0b2358ba517444eeb990d1ff72613b82">#</a>
</h3>
<p>
In JSON, a table may be represented like this:
</p>
<p>
<pre>{
<span style="color:#2e75b6;">"singleTable"</span>: {
<span style="color:#2e75b6;">"capacity"</span>: 16,
<span style="color:#2e75b6;">"minimalReservation"</span>: 10
}
}</pre>
</p>
<p>
Or like this:
</p>
<p>
<pre>{ <span style="color:#2e75b6;">"communalTable"</span>: { <span style="color:#2e75b6;">"capacity"</span>: 10 } }</pre>
</p>
<p>
But I'll also explore what happens if you need to support multiple external formats, such as <a href="https://en.wikipedia.org/wiki/XML">XML</a>. Generally speaking, a given XML specification may lean towards favouring a verbose style based on elements, or a terser style based on attributes. An example of the former could be:
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>12<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">communal-table</span><span style="color:blue;">></span></pre>
</p>
<p>
or
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">single-table</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>4<span style="color:blue;"></</span><span style="color:#a31515;">capacity</span><span style="color:blue;">></span>
<span style="color:blue;"> <</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>3<span style="color:blue;"></</span><span style="color:#a31515;">minimal-reservation</span><span style="color:blue;">></span>
<span style="color:blue;"></</span><span style="color:#a31515;">single-table</span><span style="color:blue;">></span></pre>
</p>
<p>
while examples of the latter style include
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">communal-table</span><span style="color:blue;"> </span><span style="color:red;">capacity</span><span style="color:blue;">=</span>"<span style="color:blue;">12</span>"<span style="color:blue;"> /></span></pre>
</p>
<p>
and
</p>
<p>
<pre><span style="color:blue;"><</span><span style="color:#a31515;">single-table</span><span style="color:blue;"> </span><span style="color:red;">capacity</span><span style="color:blue;">=</span>"<span style="color:blue;">4</span>"<span style="color:blue;"> </span><span style="color:red;">minimal-reservation</span><span style="color:blue;">=</span>"<span style="color:blue;">3</span>"<span style="color:blue;"> /></span></pre>
</p>
<p>
As it turns out, only one of the three data architectures is flexible enough to fully address such requirements.
</p>
<h3 id="76af298edac94997a28a92b865b2e508">
Comparisons <a href="#76af298edac94997a28a92b865b2e508">#</a>
</h3>
<p>
A <a href="https://en.wikipedia.org/wiki/REST">REST</a> API is the kind of application where data representation flexibility is most likely to be an issue. Thus, that only one of the three alternative architectures is able to exhibit enough expressive power in that dimension doesn't disqualify the other two. Each come with their own benefits and drawbacks.
</p>
<table>
<thead>
<tr>
<td></td>
<td>Ports and Adapters</td>
<td>Shared Data Model</td>
<td>Domain Model only</td>
</tr>
</thead>
<tbody>
<tr>
<td>Advantages</td>
<td>
<ul>
<li>Separation of concerns</li>
<li>Well-described</li>
</ul>
</td>
<td>
<ul>
<li>Simple</li>
<li>No mapping</li>
</ul>
</td>
<td>
<ul>
<li>Flexible</li>
<li>Congruent with reality</li>
</ul>
</td>
</tr>
<tr>
<td>Disadvantages</td>
<td>
<ul>
<li>Much mapping</li>
<li>Easy to get wrong</li>
</ul>
</td>
<td>
<ul>
<li>Inflexible</li>
<li>God Class attractor</li>
</ul>
</td>
<td>
<ul>
<li>Requires non-opinionated framework</li>
<li>Requires more testing</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>
I'll discuss each alternative's benefits and drawbacks in their individual articles.
</p>
<p>
An important point of all this is that none of these articles are meant to be prescriptive. While I do have favourites, my biases are shaped by the kind of work I typically do. In other contexts, another alternative may prevail.
</p>
<h3 id="3db82a1056ff4f4fbcb9bb2dd9c4643c">
Example code <a href="#3db82a1056ff4f4fbcb9bb2dd9c4643c">#</a>
</h3>
<p>
As usual, example code is in C#. Of the three languages in which I'm most proficient (the other two being <a href="https://fsharp.org/">F#</a> and <a href="https://www.haskell.org/">Haskell</a>), this is the most easily digestible for a larger audience.
</p>
<p>
All three alternatives are written with ASP.NET 8.0, and it's unavoidable that there will be some framework-specific details. In <a href="/code-that-fits-in-your-head">Code That Fits in Your Head</a>, I made it an explicit point that while the examples in the book are in C#, the book (and the code in it) should be understandable by developers who normally use <a href="https://www.java.com/">Java</a>, <a href="https://en.wikipedia.org/wiki/C%2B%2B">C++</a>, <a href="https://www.typescriptlang.org/">TypeScript</a>, or similar C-based languages.
</p>
<p>
The book is, for that reason, light on .NET-specific details. Instead, I published <a href="/2021/06/14/new-book-code-that-fits-in-your-head">an article</a> that collects all the interesting .NET things I ran into while writing the book.
</p>
<p>
Not so here. The three articles cover enough ASP.NET particulars that readers who don't care about that framework are encouraged to skim-read.
</p>
<p>
I've developed the three examples as three branches of the same Git repository. The code is available upon request against a small <a href="/support">support donation</a> of 10 USD (or more). If you're one of my regular supporters, you have my gratitude and can get the code without further donation. <a href="/about#contact">Send me an email</a> in both cases.
</p>
<h3 id="83a76525d22a49d898609fc6c1963acf">
Conclusion <a href="#83a76525d22a49d898609fc6c1963acf">#</a>
</h3>
<p>
There's more than one way to organize a code base to deal with data. Depending on context, one may be a better choice than another. Thus, it pays to be aware of alternatives.
</p>
<p>
In the remaining articles in this series, you'll see three examples of how to deal with persistent data from a database. In order to establish a baseline, the first covers the well-known Ports and Adapters architecture.
</p>
<p>
<strong>Next:</strong> <a href="/2024/07/29/using-ports-and-adapters-to-persist-restaurant-table-configurations">Using Ports and Adapters to persist restaurant table configurations</a>.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.The end of trust?https://blog.ploeh.dk/2024/07/15/the-end-of-trust2024-07-15T19:07:00+00:00Mark Seemann
<div id="post">
<p>
<em>Software development in a globalized, hostile world.</em>
</p>
<p>
Imagine that you're perusing the thriller section in an airport book store and come across a book with the following back cover blurb:
</p>
<blockquote>
<p>
Programmers are dying.
</p>
<p>
Holly-Ann Kerr works as a data scientist for an NGO that fights workplace discrimination. While scrubbing input, she discovers an unusual pattern in the data. Some employees seem to have an unusually high fatal accident rate. Programmers are dying in traffic accidents, falling on stairs, defect electrical wiring, smoking in bed. They work for a variety of companies. Some for Big Tech, others for specialized component vendors, some for IT-related NGOs, others again for utility companies. The deaths seem to have nothing in common, until H-A uncovers a disturbing pattern.
</p>
<p>
All victims had recently started in a new position. And all were of Iranian descent.
</p>
<p>
Is a racist killer on the loose? But if so, why is he only targeting new hires? And why only software developers?
</p>
<p>
When H-A shares her discovery with the wrong people, she soon discovers that she'll be the next victim.
</p>
</blockquote>
<p>
Okay, I'm not a professional editor, so this could probably do with a bit of polish. Does it sound like an exiting piece of fiction, though?
</p>
<p>
<img src="/content/binary/the-long-game-cover.jpg" alt="Cover of the imaginary thriller, The Long Game.">
</p>
<p>
I'm going to spoil the plot, since the book doesn't exist anyway.
</p>
<h3 id="269cc12b04c24fadb740f64ef4045625">
An international plot <a href="#269cc12b04c24fadb740f64ef4045625">#</a>
</h3>
<p>
(Apologies to Iranian readers. I have nothing against Iranians, but find the regime despicable. In any case, nothing in the following hinges on the <a href="https://en.wikipedia.org/wiki/Council_for_Intelligence_Coordination">ICC</a>. You can replace it with another adversarial intelligence agency that you don't like, including, but not limited to <a href="https://en.wikipedia.org/wiki/Reconnaissance_General_Bureau">RGB</a>, <a href="https://en.wikipedia.org/wiki/Federal_Security_Service">FSB</a>, or a clandestine Chinese intelligence organization. You could probably even swap the roles and make <a href="https://en.wikipedia.org/wiki/Central_Intelligence_Agency">CIA</a>, <a href="https://en.wikipedia.org/wiki/MI5">MI5</a>, or <a href="https://en.wikipedia.org/wiki/Mossad">Mossad</a> be the bad guys, if your loyalties lie elsewhere.)
</p>
<p>
In the story, it turns out that clandestine Iranian special operations are attempting to recruit <a href="https://en.wikipedia.org/wiki/Mole_(espionage)">moles</a> in software organizations that constitute the supply chain of Western digital infrastructure.
</p>
<p>
Intelligence bureaus and software organizations that directly develop sensitive software tend to have good security measures. Planting a mole in such an organization is difficult. The entire supply chain of software dependencies, on the other hand, is much more vulnerable. If you can get an employee to install a <a href="https://en.wikipedia.org/wiki/Backdoor_(computing)">backdoor</a> in <a href="https://en.wikipedia.org/wiki/Npm_left-pad_incident">left-pad</a>, chances are that you may attain <a href="https://en.wikipedia.org/wiki/Arbitrary_code_execution">remote execution</a> capabilities on an ostensibly secure system.
</p>
<p>
In my hypothetical thriller, the Iranians kill those software developers that they <em>fail</em> to recruit. After all, one can't run a clandestine operation if people notify the police that they've been approached by a foreign power.
</p>
<h3 id="8979c9d3d6484a9b8356b887220a594f">
Long game <a href="#8979c9d3d6484a9b8356b887220a594f">#</a>
</h3>
<p>
Does that plot sound far-fetched?
</p>
<p>
I admit that I did <a href="https://en.wikipedia.org/wiki/Up_to_eleven">turn to 11</a> some plot elements. This is, after all, supposed to be a thriller.
</p>
<p>
The story is, however, 'loosely based on real events'. Earlier this year, <a href="https://arstechnica.com/security/2024/04/what-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world/">a Microsoft developer revealed a backdoor that someone had intentionally planted in xz Utils</a>. That version of the software was close to being merged into <a href="https://www.debian.org/">Debian</a> and <a href="https://www.redhat.com/">Red Hat</a> Linux distributions. It would have enabled an attacker to execute arbitrary code on an infected machine.
</p>
<p>
The attack was singularly sophisticated. It also looks as though it was initiated years ago by one or more persons who contributed real, useful work to an open-source project, apparently (in hindsight) with the sole intention of gaining the trust of the rest of the community.
</p>
<p>
This is such a long game that it reeks of an adversarial state actor. The linked article speculates on which foreign power may be behind the attack. No, not the Iranians, after all.
</p>
<p>
If you think about it, it's an entirely rational gambit for a foreign intelligence agency to make. It's not that the <a href="https://en.wikipedia.org/wiki/Stuxnet">NSA hasn't already tried something comparable</a>. If anything, the xz hack mostly seems far-fetched because it's so unnecessarily sophisticated.
</p>
<p>
Usually, the most effective hacking techniques utilize human trust or gullibility. Why spend enormous effort developing sophisticated buffer overrun exploits if you can get a (perhaps unwitting) insider to run arbitrary code for you?
</p>
<p>
It'd be much cheaper, and much more reliable, to recruit moles on the inside of software companies, and get them to add the backdoors you need. It doesn't necessary have to be new hires, but perhaps (I'm speculating) it's easier to recruit people before they've developed any loyalty to their new team mates.
</p>
<h3 id="3a6d30419c8d4e869309502db610dfd6">
The soft underbelly <a href="#3a6d30419c8d4e869309502db610dfd6">#</a>
</h3>
<p>
Which software organizations are the most promising targets? If it were me, I'd particularly try to go after various component vendors. One category may be companies that produce <a href="https://en.wikipedia.org/wiki/Rapid_application_development">RAD</a> tools such as grid <a href="https://en.wikipedia.org/wiki/Graphical_user_interface">GUIs</a>, but also service providers that offer free <a href="https://en.wikipedia.org/wiki/Software_development_kit">SDKs</a> to, say, send email, generate invoices, send SMS, charge credit cards, etc.
</p>
<p>
I'm <em>not</em> implying that any such company has ill intent, but since such software run on many machines, it's a juicy target if you can sneak a backdoor into one.
</p>
<p>
Why not open-source software (OSS)? Many OSS libraries run on even more machines, so wouldn't that be an even more attractive target for an adversary? Yes, but on the other hand, most popular open-source code is also scrutinized by many independent agents, so it's harder to sneak in a backdoor. As the attempted xz hack demonstrates, even a year-long sophisticated attack is at risk of being discovered.
</p>
<p>
Doesn't commercial or closed-source code receive the same level of scrutiny?
</p>
<p>
In my experience, not always. Of course, some development organizations use proper shared-code-ownership techniques like code reviews or pair programming, but others rely on siloed solo development. Programmers just check in code that no-one else ever looks at.
</p>
<p>
In such an organization, imagine how easy it'd be for a mole to add a backdoor to a widely-distributed library. He or she wouldn't even have to resort to sophisticated ways to obscure the backdoor, because no colleague would be likely to look at the code. Particularly not if you bury it in seven levels of nested <code>for</code> loops and call the class <code>MonitorManager</code> or similar. As long as the reusable library ships as compiled code, it's unlikely that customers will discover the backdoor before its too late.
</p>
<h3 id="2987e2669c4c46c29a45281d3a6b3adc">
Trust <a href="#2987e2669c4c46c29a45281d3a6b3adc">#</a>
</h3>
<p>
Last year I published an article <a href="/2023/03/20/on-trust-in-software-development">on trust in software development</a>. The point of that piece wasn't that you should suspect your colleagues of ill intent, but rather that you can trust neither yourself nor your co-workers for the simple reason that people make mistakes.
</p>
<p>
Since then, I've been doing some work in the digital security space, and I've been forced to think about concerns like <a href="https://en.wikipedia.org/wiki/Supply_chain_attack">supply-chain attacks</a>. The implications are, unfortunately, that you can't automatically trust that your colleague has benign intentions.
</p>
<p>
This, obviously, will vary with context. If you're only writing a small web site for your HR department to use, it's hard to imagine how an adversarial state actor could take advantage of a backdoor in <em>your</em> code. If so, it's unlikely that anyone will go to the trouble of planting a mole in your organization.
</p>
<p>
On the other hand, if you're writing any kind of reusable library or framework, you just might be an interesting target. If so, you can no longer entirely trust your team mates.
</p>
<p>
As a Dane, that bothers me deeply. Denmark, along with the other Nordic countries, exhibit <a href="https://ourworldindata.org/trust">the highest levels of inter-societal trust in the world</a>. I was raised to trust strangers, and so far, it's worked well enough for me. A business transaction in Denmark is often just a short email exchange. It's a great benefit to the business environment, and the economy in general, that we don't have to waste a lot of resources filling out formulas, contracts, agreements, etc. Trust is grease that makes society run smoother.
</p>
<p>
Even so, Scandinavians aren't <em>naive</em>. We don't believe that we can trust everyone. To a large degree, we rely on a lot of subtle social cues to assess a given situation. Some people shouldn't be trusted, and we're able to identify those situations, too.
</p>
<p>
What remains is that insisting that you can trust your colleague, just because he or she is your colleague, would be descending into teleology. I'm not a proponent of wishful thinking if good arguments suggest the contrary.
</p>
<h3 id="295deb8a2c1041678830fcf173f7abf4">
Shared code ownership <a href="#295deb8a2c1041678830fcf173f7abf4">#</a>
</h3>
<p>
Perhaps you shouldn't trust your colleagues. How does that impact software development?
</p>
<p>
The good news is that this is yet another argument to practice the beneficial practices of shared code ownership. Crucially, what this should entail is not just that everyone is allowed to edit any line of code, but rather that all team members take responsibility for the entire code base. No-one should be allowed to write code in splendid isolation.
</p>
<p>
There are several ways to address this concern. I often phrase it as follows: <em>There should be at least two pair of eyes on every line of code before a merge to master</em>.
</p>
<p>
As I describe in <a href="/2021/06/14/new-book-code-that-fits-in-your-head">Code That Fits in Your Head</a>, you can achieve that goal with pair programming, ensemble programming, or code reviews (including <a href="/2021/06/21/agile-pull-requests">agile pull request</a> reviews). That's a broad enough palette that it should be possible for every developer in every organization to find a modus vivendi that fits any personality and context.
</p>
<p>
Just looking at each others' code could significantly raise the bar for a would-be mole to add a backdoor to the code base. As an added benefit, it might also raise the general code quality.
</p>
<p>
What this <em>does</em> suggest to me, however, is that a too simplistic notion of <em>running on trunk</em> may be dangerous. Letting everyone commit to <em>master</em> and trusting that everyone means well no longer strikes me as a good idea (again, given the context, and all that).
</p>
<p>
Or, if you do, you should consider having some sort of systematic <ins datetime="2024-07-26T08:09Z">posterior</ins> <del datetime="2024-07-26T08:09Z">post mortem</del> review process. I've read of organizations that do that, but specific sources escape me at the moment. With Git, however, it's absolutely within the realms of the possible to make a diff of all change since the last ex-post review, and then go through those changes.
</p>
<h3 id="be306c291a644cd09762335becd1291e">
Conclusion <a href="#be306c291a644cd09762335becd1291e">#</a>
</h3>
<p>
The world is changed. I feel it in the <a href="https://owasp.org/www-project-top-ten/">OWASP top 10</a>. I sense it in the shifting geopolitical climate. I smell it on the code I review.
</p>
<p>
Much that once was, is lost. The dream of a global computer network with boundless trust is no more. There are countries whose interests no longer align with ours. Who pay full-time salaries to people whose job it is to wage 'cyber warfare' against us. We can't rule out that parts of such campaigns include planting moles in our midsts. Moles whose task it is to weaken the foundations of our digital infrastructure.
</p>
<p>
In that light, should you always trust your colleagues?
</p>
<p>
Despite the depressing thought that I probably shouldn't, I'm likely to bounce back to my usual Danish most-people-are-to-be-trusted attitude tomorrow. On the other hand, I'll still insist that more than one person is involved with every line of code. Not only because every other person may be a foreign agent, but mostly, still, because humans are fallible, and two brains think better than one.
</p>
</div>
<div id="comments">
<hr>
<h2 id="comments-header">
Comments
</h2>
<div class="comment" id="95fab96f981647a9a852c8d960b7f824">
<div class="comment-author"><a href="https://about.me/tysonwilliams">Tyson Williams</a> <a href="#95fab96f981647a9a852c8d960b7f824">#</a></div>
<div class="comment-content">
<blockquote>
Or, if you do, you should consider having some sort of systematic post mortem review process. I've read of organizations that do that, but specific sources escape me at the moment.
</blockquote>
<p>
My company has a Google Docs template for postmortem analysis that we use when something goes especially wrong. The primary focus is stating what went wrong according to the "five whys technique". Our template links to <a href="http://www.startuplessonslearned.com/2008/11/five-whys.html">this post by Eric Ries</a>. There is also<a href="https://en.wikipedia.org/wiki/Five_whys">this Wikipedia article on the subject</a>. The section heading are "What happened" (one sentence), "Impact on Customers" (duration and severity), "What went wrong (5 Whys)", "What went right (optional)", "Corrective Actions" (and all of the content so far should be short enough to fit on one page), "Timeline" (a bulleted list asking for "Event beginning", "Time to Detect (monitoring)", "Time to Notify (alerting)", "Time to Respond (devops)", "Time to Troubleshoot (devops)", "Time to Mitigate (devops)", "Event end"), "Logs (optional)".
</p>
</div>
<div class="comment-date">2024-07-21 15:37 UTC</div>
</div>
<div class="comment" id="0c1f8083882c4de8a11be963869cc098">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#0c1f8083882c4de8a11be963869cc098">#</a></div>
<div class="comment-content">
<p>
Tyson, thank you for writing. I now realize that 'post mortem' was a poor choice of words on my part, since it implies that something went wrong. I should have written 'posterior' instead. I'll update the article.
</p>
<p>
I've been digging around a bit to see if I can find the article that originally made me aware of that option. I'm fairly sure that it wasn't <a href="https://itnext.io/optimizing-the-software-development-process-for-continuous-integration-and-flow-of-work-56cf614b3f59">Optimizing the Software development process for continuous integration and flow of work</a>, but that article, on the other hand, seems to be the source that other articles cite. It's fairly long, and also discusses other concepts; the relevant section here is the one called <em>Non-blocking reviews</em>.
</p>
<p>
An shorter overview of this kind of process can be found in <a href="https://thinkinglabs.io/articles/2023/05/02/non-blocking-continuous-code-reviews-a-case-study.html">Non-Blocking, Continuous Code Reviews - a case study</a>.
</p>
</div>
<div class="comment-date">2024-07-26 08:04 UTC</div>
</div>
<div class="comment" id="b3ae6a8c02584d80aaa69eb00ca39548">
<div class="comment-author">Jiehong <a href="#b3ae6a8c02584d80aaa69eb00ca39548">#</a></div>
<div class="comment-content">
<p>
In change management/risk control, your <em>There should be at least two pair of eyes on every line of code</em> is called <a href="https://www.openriskmanual.org/wiki/Four_Eyes_Principle">four eye principle</a>,
and is a standard practice in my industry (IT services provider for the travel industry).
</p>
<p>
It goes further, and requires 2 more pair of eyes for any changes from the code review, to the load of a specific software in production.
</p>
<p>
I has a nice side-effect during code reviews: it's an automatic way to dessiminate knowledge in the team, so the bus factor is never 1.
</p>
<p>
I think that <em>real</em> people can <em>mostly</em> be trusted. But, software is not always run by people.
Even when it is, a single non-trust-worthy person's action is amplified by software being run by mindless computers.
It's like one rotten apple is enough to poison the full bag.
</p>
<p>
In the end, and a bit counter-intuitively, trusting people less now is leading to being able to trust more soon:
people are forced to say "you can trust me, and here are the proofs". (Eg: the recently announced Apple's <a href="https://security.apple.com/blog/private-cloud-compute/">Private Cloud Compute</a>).
</p>
</div>
<div class="comment-date">2024-07-29 14:29 UTC</div>
</div>
<div class="comment" id="4655bc2aa6664d5ca10dfb069102bbfd">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#4655bc2aa6664d5ca10dfb069102bbfd">#</a></div>
<div class="comment-content">
<p>
Jiehong, thank you for writing. Indeed, in <a href="/code-that-fits-in-your-head">Code That Fits in Your Head</a> I discuss how shared code ownership reduces the bus factor.
</p>
<p>
From this article and previous discussions I've had, I can see that the term <em>trust</em> is highly charged. People really don't like the notion that trust may be misplaced, or that mistrust, even, might be appropriate. I can't tell if it's a cultural bias of which I'm not aware. While English isn't my native language, I believe that I'm sufficiently acquainted with anglo-saxon culture to know of its most obvious quirks. Still, I'm sometimes surprised.
</p>
<p>
I admit that I, too, <em>first</em> consider whether I'm dealing with a deliberate adversary if I'm asked whether I trust someone, but soon after, there's a secondary interpretation that originates from normal human fallibility. I've <a href="/2023/03/20/on-trust-in-software-development">already written about that</a>: No, I don't trust my colleagues to be infallible, as I don't trust myself to be so.
</p>
<p>
Fortunately, it seems to me that the remedies that may address such concerns are the same, regardless of the underlying reasons.
</p>
</div>
<div class="comment-date">2024-08-06 05:57 UTC</div>
</div>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Should interfaces be asynchronous?https://blog.ploeh.dk/2024/07/08/should-interfaces-be-asynchronous2024-07-08T13:52:00+00:00Mark Seemann
<div id="post">
<p>
<em>Async and await are notorious for being contagious. Must all interfaces be Task-based, just in case?</em>
</p>
<p>
I recently came across this question on Mastodon:
</p>
<blockquote>
<p>
"To async or not to async?
</p>
<p>
"How would you define a library interface for a service that probably will be implemented with an in memory procedure - let's say returning a mapped value to a key you registered programmatically - and a user of your API might want to implement a decorator that needs a 'long running task' - for example you want to log a msg into your db or load additional mapping from a file?
</p>
<p>
"Would you define the interface to return a Task<string> or just a string?"
</p>
<footer><cite><a href="https://fosstodon.org/@Fandermill/112613967801632197">Fandermill</a></cite></footer>
</blockquote>
<p>
While seemingly a simple question, it's both fundamental and turns out to have deeper implications than you may at first realize.
</p>
<h3 id="e4c03ad0436340b4b510d51e14acd794">
Interpretation <a href="#e4c03ad0436340b4b510d51e14acd794">#</a>
</h3>
<p>
Before I proceed, I'll make my interpretation of the question more concrete. This is just how I <em>interpret</em> the question, so doesn't necessarily reflect the original poster's views.
</p>
<p>
The post itself doesn't explicitly mention a particular language, and since several languages now have <code>async</code> and <code>await</code> features, the question may be of more general interest that a question constrained to a single language. On the other hand, in order to have something concrete to discuss, it'll be useful with some real code examples. From perusing the discussion surrounding the original post, I get the impression that the language in question may be C#. That suits me well, since it's one of the languages with which I'm most familiar, and is also a language where programmers of other C-based languages should still be able to follow along.
</p>
<p>
My interpretation of the implementation, then, is this:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NameMap</span>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">Guid</span>, <span style="color:blue;">string</span>> knownIds = <span style="color:blue;">new</span>()
{
{ <span style="color:blue;">new</span> <span style="color:#2b91af;">Guid</span>(<span style="color:#a31515;">"4778CA3D-FB1B-4665-AAC1-6649CEFA4F05"</span>), <span style="color:#a31515;">"Bob"</span> },
{ <span style="color:blue;">new</span> <span style="color:#2b91af;">Guid</span>(<span style="color:#a31515;">"8D3B9093-7D43-4DD2-B317-DCEE4C72D845"</span>), <span style="color:#a31515;">"Alice"</span> }
};
<span style="color:blue;">public</span> <span style="color:blue;">string</span> <span style="font-weight:bold;color:#74531f;">GetName</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">guid</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> knownIds.<span style="font-weight:bold;color:#74531f;">TryGetValue</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">name</span>) ? <span style="font-weight:bold;color:#1f377f;">name</span> : <span style="color:#a31515;">"Trudy"</span>;
}
}</pre>
</p>
<p>
Nothing fancy, but, as <a href="https://fosstodon.org/@Fandermill">Fandermill</a> writes in a follow-up post:
</p>
<blockquote>
<p>
"Used examples that first came into mind, but it could be anything really."
</p>
<footer><cite><a href="https://fosstodon.org/@Fandermill/112613968890232099">Fandermill</a></cite></footer>
</blockquote>
<p>
The point, as I understand it, is that the intended implementation doesn't require asynchrony. A <a href="https://en.wikipedia.org/wiki/Decorator_pattern">Decorator</a>, on the other hand, may.
</p>
<p>
Should we, then, declare an interface like the following?
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">interface</span> <span style="color:#2b91af;">INameMap</span>
{
<span style="color:#2b91af;">Task</span><<span style="color:blue;">string</span>> <span style="font-weight:bold;color:#74531f;">GetName</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">guid</span>);
}</pre>
</p>
<p>
If we do, the <code>NameMap</code> class can't automatically implement that interface because the return types of the two <code>GetName</code> methods don't match. What are the options?
</p>
<h3 id="9da822948cd049c0a625bb9a2c013d7b">
Conform <a href="#9da822948cd049c0a625bb9a2c013d7b">#</a>
</h3>
<p>
While the following may not be the 'best' answer, let's get the obvious solution out of the way first. Let the implementation conform to the interface:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NameMap</span> : <span style="color:#2b91af;">INameMap</span>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">Guid</span>, <span style="color:blue;">string</span>> knownIds = <span style="color:blue;">new</span>()
{
{ <span style="color:blue;">new</span> <span style="color:#2b91af;">Guid</span>(<span style="color:#a31515;">"4778CA3D-FB1B-4665-AAC1-6649CEFA4F05"</span>), <span style="color:#a31515;">"Bob"</span> },
{ <span style="color:blue;">new</span> <span style="color:#2b91af;">Guid</span>(<span style="color:#a31515;">"8D3B9093-7D43-4DD2-B317-DCEE4C72D845"</span>), <span style="color:#a31515;">"Alice"</span> }
};
<span style="color:blue;">public</span> <span style="color:#2b91af;">Task</span><<span style="color:blue;">string</span>> <span style="font-weight:bold;color:#74531f;">GetName</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">guid</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Task</span>.<span style="color:#74531f;">FromResult</span>(
knownIds.<span style="font-weight:bold;color:#74531f;">TryGetValue</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">name</span>) ? <span style="font-weight:bold;color:#1f377f;">name</span> : <span style="color:#a31515;">"Trudy"</span>);
}
}</pre>
</p>
<p>
This variation of the <code>NameMap</code> class conforms to the interface by making the <code>GetName</code> method look asynchronous.
</p>
<p>
We may even keep the synchronous implementation around as a public method if some client code might need it:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NameMap</span> : <span style="color:#2b91af;">INameMap</span>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">Guid</span>, <span style="color:blue;">string</span>> knownIds = <span style="color:blue;">new</span>()
{
{ <span style="color:blue;">new</span> <span style="color:#2b91af;">Guid</span>(<span style="color:#a31515;">"4778CA3D-FB1B-4665-AAC1-6649CEFA4F05"</span>), <span style="color:#a31515;">"Bob"</span> },
{ <span style="color:blue;">new</span> <span style="color:#2b91af;">Guid</span>(<span style="color:#a31515;">"8D3B9093-7D43-4DD2-B317-DCEE4C72D845"</span>), <span style="color:#a31515;">"Alice"</span> }
};
<span style="color:blue;">public</span> <span style="color:#2b91af;">Task</span><<span style="color:blue;">string</span>> <span style="font-weight:bold;color:#74531f;">GetName</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">guid</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Task</span>.<span style="color:#74531f;">FromResult</span>(<span style="font-weight:bold;color:#74531f;">GetNameSync</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>));
}
<span style="color:blue;">public</span> <span style="color:blue;">string</span> <span style="font-weight:bold;color:#74531f;">GetNameSync</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">guid</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> knownIds.<span style="font-weight:bold;color:#74531f;">TryGetValue</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>, <span style="color:blue;">out</span> <span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">name</span>) ? <span style="font-weight:bold;color:#1f377f;">name</span> : <span style="color:#a31515;">"Trudy"</span>;
}
}</pre>
</p>
<p>
Since C# doesn't support return-type-based overloading, we need to distinguish these two methods by giving them different names. In C# it might be more <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatic</a> to name the asynchronous method <code>GetNameAsync</code> and the synchronous method just <code>GetName</code>, but for reasons that would be too much of a digression now, I've never much liked that naming convention. In any case, I'm not going to go in this direction for much longer, so it hardly matters how we name these two methods.
</p>
<h3 id="821f1bb35dac41eeade7c5d7b28a3b18">
Kinds of interfaces <a href="#821f1bb35dac41eeade7c5d7b28a3b18">#</a>
</h3>
<p>
Another digression is, however, quite important. Before we can look at some more code, I'm afraid that we have to perform a bit of practical ontology, as it were. It starts with the question: <em>Why do we even need interfaces?</em>
</p>
<p>
I should also make clear, as a digression within a digression, that by 'interface' in this context, I'm really interested in any kind of mechanism that enables you to achieve polymorphism. In languages like C# or <a href="https://www.java.com/">Java</a>, we may in fact avail ourselves of the <code>interface</code> keyword, as in the above <code>INameMap</code> example, but we may equally well use a base class or perhaps just what C# calls a <a href="https://learn.microsoft.com/dotnet/csharp/programming-guide/delegates/">delegate</a>. In other languages, we may use function or action types, or even <a href="https://en.wikipedia.org/wiki/Function_pointer">function pointers</a>.
</p>
<p>
Regardless of specific language constructs, there are, as far as I can tell, two kinds of interfaces:
</p>
<ul>
<li>Interfaces that enable variability or extensibility in behaviour.</li>
<li>Interfaces that mostly or exclusively exist to support automated testing.</li>
</ul>
<p>
While there may be some overlap between these two kinds, in my experience, the intersection between the two tends to be surprisingly small. Interfaces tend to mostly belong to one of those two categories.
</p>
<h3 id="d990222c075942ab851c1455c8efcb95">
Strategies and higher-order functions <a href="#d990222c075942ab851c1455c8efcb95">#</a>
</h3>
<p>
In design-patterns parlance, examples of the first kind are <a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder</a>, <a href="https://en.wikipedia.org/wiki/State_pattern">State</a>, <a href="https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern">Chain of Responsibility</a>, <a href="https://en.wikipedia.org/wiki/Template_method_pattern">Template Method</a>, and perhaps most starkly represented by the <a href="https://en.wikipedia.org/wiki/Strategy_pattern">Strategy</a> pattern. A Strategy is an encapsulated piece of behaviour that you pass around as a single 'thing' (an <em>object</em>).
</p>
<p>
And granted, you could also use a Strategy to access a database or make a web-service call, but that's not how the pattern was <a href="/ref/dp">originally described</a>. We'll return to that use case in the next section.
</p>
<p>
Rather, the first kind of interface exists to enable extensibility or variability in algorithms. Typical examples (from Design Patterns) include page layout, user interface component rendering, building a maze, finding the most appropriate help topic for a given application context, and so on. If we wish to relate this kind of interface to the <a href="https://en.wikipedia.org/wiki/SOLID">SOLID</a> principles, it mostly exists to support the <a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle">Open-closed principle</a>.
</p>
<p>
A good heuristics for identifying such interfaces is to consider the Reused Abstractions Principle (Jason Gorman, 2010, I'd link to it, but the page has fallen off the internet. Use your favourite web archive to read it.). If your code base contains <em>multiple</em> production-ready implementations of the same interface, you're reusing the interface, most likely to vary the behaviour of a general-purpose data structure.
</p>
<p>
And before the functional-programming (FP) crowd becomes too smug: FP uses this kind of interface <em>all the time</em>. In the FP jargon, however, we rather talk about <a href="https://en.wikipedia.org/wiki/Higher-order_function">higher-order functions</a> and the interfaces we use to modify behaviour are typically modelled as functions and passed as <a href="https://en.wikipedia.org/wiki/Anonymous_function">lambda expressions</a>. So when you write <code>Cata((_, xs) => xs.Sum(), _ => 1)</code> (<a href="/2019/08/05/rose-tree-catamorphism">as one does</a>), you <a href="/2018/06/25/visitor-as-a-sum-type">might as well</a> just have passed a <a href="https://en.wikipedia.org/wiki/Visitor_pattern">Visitor</a> implementation to an <code>Accept</code> method.
</p>
<p>
This hints at a more quantifiable distinction: If the interface models something that's intended to be a <a href="https://en.wikipedia.org/wiki/Pure_function">pure function</a>, it'd typically be part of a higher-order API in FP, while we in object-oriented design (once again) lack the terminology to distinguish these interfaces from the other kind.
</p>
<p>
These days, in C# <a href="/2023/09/04/decomposing-ctfiyhs-sample-code-base">I mostly use these kinds of interfaces for the Visitor pattern</a>.
</p>
<h3 id="36e2464953344fa2a0b173f98bb260c9">
Seams <a href="#36e2464953344fa2a0b173f98bb260c9">#</a>
</h3>
<p>
The other kind of interface exists to afford automated testing. In <a href="/ref/wewlc">Working Effectively with Legacy Code</a>, Michael Feathers calls such interfaces <em>Seams</em>. Modern object-oriented code bases often use <a href="/dippp">Dependency Injection</a> (DI) to control which Strategies are in use in a given context. The production system may use an object that communicates with a relational database, while an automated test environment might replace that with a <a href="https://martinfowler.com/bliki/TestDouble.html">Test Double</a>.
</p>
<p>
Yes, I wrote <em>Strategies</em>. As I suggested above, a Strategy is really a replaceable object in its purest form. When you use DI you may call all those interfaces <code>IUserRepository</code>, <code>ICommandHandler</code>, <code>IEmailGateway</code>, and so on, but they're really all Strategies.
</p>
<p>
Contrary to the first kind of interface, you typically only find a single production implementation of each of these interfaces. If you find more that one, the rest are usually <a href="https://en.wikipedia.org/wiki/Decorator_pattern">Decorators</a> (one that logs, one that caches, one that works as a <a href="https://martinfowler.com/bliki/CircuitBreaker.html">Circuit Breaker</a>, etc.). All other implementations will be defined in the test code as dynamic mocks or <a href="http://xunitpatterns.com/Fake%20Object.html">Fakes</a>.
</p>
<p>
Code bases that rely heavily on DI in order to support testing rub many people the wrong way. In 2014 <a href="https://en.wikipedia.org/wiki/David_Heinemeier_Hansson">David Heinemeier Hansson</a> published a serious criticism of such <a href="https://dhh.dk/2014/test-induced-design-damage.html">test-induced damage</a>. For the record, I agree with the criticism, but <a href="/2020/08/17/unit-testing-is-fine">not with the conclusion</a>. While I still practice test-driven development, I <a href="https://stackoverflow.blog/2022/01/03/favor-real-dependencies-for-unit-testing/">only define interfaces for true architectural dependencies</a>. So, yes, my code bases may have an <code>IReservationsRepository</code> or <code>IEmailGateway</code>, but no <code>ICommandHandler</code> or <code>IUserManager</code>.
</p>
<p>
The bottom line, though, is that some interfaces exist to support testing. If there's a better way to make inherently non-deterministic systems behave deterministically in a test context, I've yet to discover it.
</p>
<p>
(As an aside, it's worth looking into tests that adopt non-deterministic behaviour as a driving principle, or at least an unavoidable state of affairs. Property-based testing is one such approach, but I also found the article <a href="https://arialdomartini.github.io/when-im-done-i-dont-clean-up">When I'm done, I don't clean up</a> by <a href="https://arialdomartini.github.io/">Arialdo Martini</a> interesting. You may also want to refer to my article <a href="/2021/01/11/waiting-to-happen">Waiting to happen</a> for a discussion of how to make tests independent of system time.)
</p>
<h3 id="f8bd1ea29b2a4ddbaf6538c238ec6979">
Where to define interfaces <a href="#f8bd1ea29b2a4ddbaf6538c238ec6979">#</a>
</h3>
<p>
The reason the above distinction is important is that it fundamentally determines where interfaces should be defined. In short, the first kind of interface is part of an object model's API, and should be defined together with that API. The second kind, on the other hand, is part of a particular application's architecture, and should be defined by the client code that talks to the interface.
</p>
<p>
As an example of the first kind, consider <a href="/2024/06/24/a-mutable-priority-collection">this recent example</a>, where the <code><span style="color:#2b91af;">IPriorityEditor</span><<span style="color:#2b91af;">T</span>></code> interface is part of the <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> API. You <em>must</em> ship the interface together with the class, because the <code>Edit</code> method takes an interface implementation as an argument. It's how client code interacts with the API.
</p>
<p>
Another example is <a href="/2023/12/25/serializing-restaurant-tables-in-c">this Table class</a> that comes with an <code>ITableVisitor<T></code> interface. In both cases, we'd expect interface implementations to be deterministic. These interfaces don't exist to support automated testing, but rather to afford a flexible programming model.
</p>
<p>
For the sake of argument, imagine that you package such APIs in reusable libraries that you publish via a package manager. In that case, it's obvious that the interface is as much part of the package as the class.
</p>
<p>
Contrast this with the other kind of interface, as described in the article <a href="/2023/09/04/decomposing-ctfiyhs-sample-code-base">Decomposing CTFiYH's sample code base</a> or showcased in the article <a href="/2019/04/01/an-example-of-state-based-testing-in-c">An example of state-based testing in C#</a>. In the latter example, the interfaces <code>IUserReader</code> and <code>IUserRepository</code> are <em>not</em> part of any pre-packaged library. Rather, they are defined by the application code to support application-specific needs.
</p>
<p>
This may be even more evident if you contemplate the diagram in <a href="/2023/09/04/decomposing-ctfiyhs-sample-code-base">Decomposing CTFiYH's sample code base</a>. Interfaces like <code>IPostOffice</code> and <code>IReservationsRepository</code> only exist to support the application. Following the <a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion Principle</a>
</p>
<blockquote>
<p>
"clients [...] own the abstract interfaces"
</p>
<footer><cite>Robert C. Martin, <a href="/ref/appp">APPP</a>, chapter 11</cite></footer>
</blockquote>
<p>
In these code bases, only the Controllers (or rather the tests that exercise them) need these interfaces, so the Controllers get to define them.
</p>
<h3 id="8674154df1bf4c22b59f1fd3baf5996e">
Should it be asynchronous, then? <a href="#8674154df1bf4c22b59f1fd3baf5996e">#</a>
</h3>
<p>
Okay, so should <code>INameMap.GetName</code> return <code><span style="color:blue;">string</span></code> or <code><span style="color:#2b91af;">Task</span><<span style="color:blue;">string</span>></code>, then?
</p>
<p>
Hopefully, at this point, it should be clear that the answer depends on what kind of interface it is.
</p>
<p>
If it's the first kind, the return type should support the requirements of the API. If the object model doesn't need the return type to be asynchronous, it shouldn't be.
</p>
<p>
If it's the second kind of interface, the application code decides what <em>it</em> needs, and defines the interface accordingly.
</p>
<p>
In neither case, however, is it the concrete class' responsibility to second-guess what client code might need.
</p>
<p>
<em>But client code may need the method to be asynchronous. What's the harm of returning <code><span style="color:#2b91af;">Task</span><<span style="color:blue;">string</span>></code>, just in case?</em>
</p>
<p>
The problem, as you may well be aware, is that <a href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/">the asynchronous programming model is contagious</a>. Once you've made an API asynchronous, you can't easily make it synchronous, whereas if you have a synchronous API, you can easily make it asynchronous. This follows from <a href="https://en.wikipedia.org/wiki/Postel%27s_law">Postel's law</a>, in this case: Be conservative with what you send.
</p>
<h3 id="17aebf480ad4468cac7eb1045dfa6041">
Library API <a href="#17aebf480ad4468cac7eb1045dfa6041">#</a>
</h3>
<p>
Imagine, for the sake of argument, that the <code>NameMap</code> class is defined in a reusable library, wrapped in a package and imported into your code base via a package manager (NuGet, Maven, pip, NPM, Hackage, RubyGems, etc.).
</p>
<p>
Clearly it shouldn't implement any interface in order to 'support unit testing', since such interfaces should be defined by application code.
</p>
<p>
It <em>could</em> implement one or more 'extensibility' interfaces, if such interfaces are part of the wider API offered by the library. In the case of the <code>NameMap</code> class, we don't really know if that's the case. To complete this part of the argument, then, I'd just leave it as shown in the first code example, shown above. It doesn't need to implement any interface, and <code>GetName</code> can just return <code>string</code>.
</p>
<h3 id="66d0c20621ef43e5808f589a30314d6f">
Domain Model <a href="#66d0c20621ef43e5808f589a30314d6f">#</a>
</h3>
<p>
What if, instead of an external library, the <code>NameMap</code> class is part of an application's Domain Model?
</p>
<p>
In that case, you <em>could</em> define application-level interfaces as part of the Domain Model. In fact, most people do. Even so, I'd recommend that you don't, at least if you're aiming for a <a href="https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell">Functional Core, Imperative Shell</a> architecture, a <a href="/2018/11/19/functional-architecture-a-definition">functional architecture</a>, or even a <a href="/2013/12/03/layers-onions-ports-adapters-its-all-the-same">Ports and Adapters</a> or, if you will, <a href="/ref/clean-architecture">Clean Architecture</a>. The interfaces that exist only to support testing are application concerns, so keep them out of the Domain Model and instead define them in the Application Model.
</p>
<p>
<img src="/content/binary/ports-and-adapters-dependency-graph-2.png" alt="Ports and Adapters diagram, with arrows pointing inward.">
</p>
<p>
You don't have to follow my advice. If you want to define interfaces in the Domain Model, I can't stop you. But what if, as I recommend, you define application-specific interfaces in the Application Model? If you do that, your <code>NameMap</code> Domain Model can't implement your <code>INameMap</code> interface, because the dependencies point the other way, and most languages will not allow circular dependencies.
</p>
<p>
In that case, what do you do if, as the original toot suggested, you need to Decorate the <code>GetName</code> method with some asynchronous behaviour?
</p>
<p>
You can always introduce an <a href="https://en.wikipedia.org/wiki/Adapter_pattern">Adapter</a>:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NameMapAdapter</span> : <span style="color:#2b91af;">INameMap</span>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">NameMap</span> imp;
<span style="color:blue;">public</span> <span style="color:#2b91af;">NameMapAdapter</span>(<span style="color:#2b91af;">NameMap</span> <span style="font-weight:bold;color:#1f377f;">imp</span>)
{
<span style="color:blue;">this</span>.imp = <span style="font-weight:bold;color:#1f377f;">imp</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">Task</span><<span style="color:blue;">string</span>> <span style="font-weight:bold;color:#74531f;">GetName</span>(<span style="color:#2b91af;">Guid</span> <span style="font-weight:bold;color:#1f377f;">guid</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:#2b91af;">Task</span>.<span style="color:#74531f;">FromResult</span>(imp.<span style="font-weight:bold;color:#74531f;">GetName</span>(<span style="font-weight:bold;color:#1f377f;">guid</span>));
}
}</pre>
</p>
<p>
Now any <code>NameMap</code> object can look like an <code>INameMap</code>. This is exactly the kind of problem that the Adapter pattern addresses.
</p>
<p>
<em>But,</em> you say, <em>that's too much trouble! I don't want to have to maintain two classes that are almost identical.</em>
</p>
<p>
I understand the concern, and it may even be appropriate. Maybe you're right. As usual, I don't really intend this article to be prescriptive. Rather, I'm offering ideas for your consideration, and you can choose to adopt them or ignore them as it best fits your context.
</p>
<p>
When it comes to whether or not an Adapter is an unwarranted extra complication, I'll return to that topic later in this article.
</p>
<h3 id="f51b8986514046e989556923bc19a063">
Application Model <a href="#f51b8986514046e989556923bc19a063">#</a>
</h3>
<p>
The final architectural option is when the concrete <code>NameMap</code> class is part of the Application Model, where you'd also define the application-specific <code>INameMap</code> interface. In that case, we must assume that the <code>NameMap</code> class implements some application-specific concern. If you want it to implement an interface so that you can wrap it in a Decorator, then do that. This means that the <code>GetName</code> method must conform to the interface, and if that means that it must be asynchronous, then so be it.
</p>
<p>
As <a href="https://en.wikipedia.org/wiki/Kent_Beck">Kent Beck</a> wrote in a Facebook article that used to be accessible without a Facebook account (but isn't any longer):
</p>
<blockquote>
<p>
"Things that change at the same rate belong together. Things that change at different rates belong apart."
</p>
<footer><cite><a href="https://www.facebook.com/notes/kent-beck/naming-from-the-outside-in/464270190272517">Naming From the Outside In</a>, Kent Beck, Facebook, 2012</cite></footer>
</blockquote>
<p>
If the concrete <code>NameMap</code> class and the <code>INameMap</code> interface are both part of the application model, it's not unreasonable to guess that they may change together. (Do be mindful of <a href="https://en.wikipedia.org/wiki/Shotgun_surgery">Shotgun Surgery</a>, though. If you expect the interface and the concrete class to frequently change, then perhaps another design might be more appropriate.)
</p>
<h3 id="9cf2a82474ea4af49b7f5b556a1e7fce">
Easier Adapters <a href="#9cf2a82474ea4af49b7f5b556a1e7fce">#</a>
</h3>
<p>
Before concluding this article, let's revisit the topic of introducing an Adapter for the sole purpose of 'architectural purity'. Should you really go to such lengths only to 'do it right'? You decide, but
</p>
<blockquote>
<p>
You can only be pragmatic if you know how to be dogmatic.
</p>
<footer><cite><a href="/2018/11/12/what-to-test-and-not-to-test">What to test and not to test</a></cite>, me</footer>
</blockquote>
<p>
I'm presenting a dogmatic solution for your consideration, so that you know what it might look like. Would I follow my own 'dogmatic' advice? Yes, I usually do, but then, <a href="/2020/03/23/repeatable-execution">I wouldn't log the return value of a pure function</a>, so I wouldn't introduce an interface for <em>that</em> purpose, at least. To be fair to Fandermill, he or she also wrote: "or load additional mapping from a file", which could be an appropriate motivation for introducing an interface. I'd probably go with an Adapter in that case.
</p>
<p>
Whether or not an Adapter is an unwarranted complication depends, however, on language specifics. In high-<a href="/2019/12/16/zone-of-ceremony">ceremony</a> languages like C#, Java, or <a href="https://en.wikipedia.org/wiki/C%2B%2B">C++</a>, adding an Adapter involves at least one new file, and dozens of lines of code.
</p>
<p>
Consider, on the other hand, a low-ceremony language like <a href="https://www.haskell.org/">Haskell</a>. The corresponding <code>getName</code> function might close over a statically defined map and have the type <code><span style="color:#2b91af;">getName</span> <span style="color:blue;">::</span> <span style="color:blue;">UUID</span> <span style="color:blue;">-></span> <span style="color:#2b91af;">String</span></code>.
</p>
<p>
How do you adapt such a pure function to an API that returns <a href="/2020/06/08/the-io-container">IO</a> (which is <a href="/2020/07/27/task-asynchronous-programming-as-an-io-surrogate"><em>roughly</em> comparable to task-based programming</a>)? Trivially:
</p>
<p>
<pre><span style="color:#2b91af;">getNameM</span> <span style="color:blue;">::</span> <span style="color:blue;">Monad</span> m <span style="color:blue;">=></span> <span style="color:blue;">UUID</span> <span style="color:blue;">-></span> m <span style="color:#2b91af;">String</span>
getNameM = <span style="color:blue;">return</span> . getName</pre>
</p>
<p>
For didactic purposes I have here shown the 'Adapter' as an explicit function, but in idiomatic Haskell I'd consider this below the <a href="https://wiki.haskell.org/Fairbairn_threshold">Fairbairn threshold</a>; I'd usually just inline the composition <code><span style="color:blue;">return</span> . getName</code> if I needed to adapt the <code>getName</code> function to the <a href="/2022/04/04/kleisli-composition">Kleisli</a> category.
</p>
<p>
You can do the same in <a href="https://fsharp.org/">F#</a>, where the composition would be <code><span style="color:#74531f;">getName</span> >> <span style="color:#2b91af;">Task</span>.<span style="color:#74531f;">FromResult</span></code>. F# compositions usually go in the (for Westerners) intuitive left-to-right directions, whereas Haskell compositions follow the mathematical right-to-left convention.
</p>
<p>
The point, however, is that there's nothing conceptually complicated about an Adapter. Unfortunately, however, some languages require substantial ceremony to implement them.
</p>
<h3 id="39dae93245f141a09754ff56305fe805">
Conclusion <a href="#39dae93245f141a09754ff56305fe805">#</a>
</h3>
<p>
Should an API return a Task-based (asynchronous) value 'just in case'? In general: No.
</p>
<p>
You can't predict all possible use cases, so don't make an API more complicated than it has to be. If you need to implement an application-specific interface, use the Adapter design pattern.
</p>
<p>
A possible exception to this rule is if the entire API (the concrete implementation <em>and</em> the interface) only exists to support a specific application. If the interface and its concrete implementation are both part of the Application Model, you may as well skip the Adapter step and consider the concrete implementation as its own Adapter.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.An immutable priority collectionhttps://blog.ploeh.dk/2024/07/01/an-immutable-priority-collection2024-07-01T17:28:00+00:00Mark Seemann
<div id="post">
<p>
<em>With examples in C# and F#.</em>
</p>
<p>
This article is part of a <a href="/2024/06/12/simpler-encapsulation-with-immutability">series about encapsulation and immutability</a>. After two attempts at an object-oriented, mutable implementation, I now turn toward immutability. As already suggested in the introductory article, immutability makes it easier to maintain invariants.
</p>
<p>
In the introductory article, I described the example problem in more details, but in short, the exercise is to develop a class that holds a collection of prioritized items, with the invariant that the priorities must always sum to 100. It should be impossible to leave the object in a state where that's not true. It's quite an illuminating exercise, so if you have the time, you should try it for yourself before reading on.
</p>
<h3 id="8543ed3d0ac44d3a8d75145da7e10626">
Initialization <a href="#8543ed3d0ac44d3a8d75145da7e10626">#</a>
</h3>
<p>
Once again, I begin by figuring out how to initialize the object, and how to model it. Since it's a kind of collection, and since I now plan to keep it immutable, it seems natural to implement <a href="https://learn.microsoft.com/dotnet/api/system.collections.generic.ireadonlycollection-1">IReadOnlyCollection<T></a>.
</p>
<p>
In this, the third attempt, I'll reintroduce <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code>, with one important difference. It's now an immutable record:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">record</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">Item</span>, <span style="color:blue;">byte</span> <span style="font-weight:bold;color:#1f377f;">Priority</span>);</pre>
</p>
<p>
If you're not on a version of C# that supports <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/record">records</a> (which is also trivially true if you're not using C# at all), you can always define an immutable class by hand. It just requires more <a href="https://buttondown.email/hillelwayne/archive/why-do-we-call-it-boilerplate-code/">boilerplate</a> code.
</p>
<p>
<code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code> is going to be the <code>T</code> in the <code>IReadOnlyCollection<T></code> implementation:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>> : <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>></pre>
</p>
<p>
Since an invariant should always hold, it should also hold at initialization, so the <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> constructor must check that all is as it should be:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>[] priorities;
<span style="color:blue;">public</span> <span style="color:#2b91af;">PriorityCollection</span>(<span style="color:blue;">params</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>[] <span style="font-weight:bold;color:#1f377f;">priorities</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">priorities</span>.<span style="font-weight:bold;color:#74531f;">Sum</span>(<span style="font-weight:bold;color:#1f377f;">p</span> => <span style="font-weight:bold;color:#1f377f;">p</span>.Priority) != 100)
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ArgumentException</span>(
<span style="color:#a31515;">"The sum of all priorities must be 100."</span>,
<span style="color:blue;">nameof</span>(<span style="font-weight:bold;color:#1f377f;">priorities</span>));
<span style="color:blue;">this</span>.priorities = <span style="font-weight:bold;color:#1f377f;">priorities</span>;
}</pre>
</p>
<p>
The rest of the class is just the <code>IReadOnlyCollection<T></code> implementation, which just delegates to the <code>priorities</code> field.
</p>
<p>
That's it, really. That's the API. We're done.
</p>
<h3 id="8b7c8d67ea144bcfbdc10823bee1e770">
Projection <a href="#8b7c8d67ea144bcfbdc10823bee1e770">#</a>
</h3>
<p>
<em>But,</em> you may ask, <em>how does one edit such a collection?</em>
</p>
<p>
<img src="/content/binary/immutable-edit-comic.jpg" alt="Bob: How do I edit an immutable object Other man: You don't, because it's a persistent data structure. Bob: Fine, it's persist. How do I edit it? Other man: You make it a monomorphic functor and compose it with projections. Bob: Did you just tell me to go fuck myself? Other man: I believe I did, Bob.">
</p>
<p>
(Comic originally by John Muellerleile.)
</p>
<p>
Humour aside, you don't edit an immutable object, but rather make a new object from a previous one. Most modern languages now come with built-in collection-projection APIs; in .NET, it's called <a href="https://learn.microsoft.com/dotnet/csharp/linq/">LINQ</a>. Here's an example. You begin with a collection with two items:
</p>
<p>
<pre><span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">pc</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:blue;">string</span>>(
<span style="color:blue;">new</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"foo"</span>, 60),
<span style="color:blue;">new</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"bar"</span>, 40));</pre>
</p>
<p>
You'd now like to add a third item with priority 20:
</p>
<p>
<pre><span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">newPriority</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:blue;">string</span>>(<span style="color:#a31515;">"baz"</span>, 20);</pre>
</p>
<p>
How should you make room for this new item? One option is to evenly reduce each of the existing priorities:
</p>
<p>
<pre><span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">reduction</span> = <span style="font-weight:bold;color:#1f377f;">newPriority</span>.Priority / <span style="font-weight:bold;color:#1f377f;">pc</span>.Count;
<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:blue;">string</span>>> <span style="font-weight:bold;color:#1f377f;">reduced</span> = <span style="font-weight:bold;color:#1f377f;">pc</span>
.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">p</span> => <span style="font-weight:bold;color:#1f377f;">p</span> <span style="color:blue;">with</span> { Priority = (<span style="color:blue;">byte</span>)(<span style="font-weight:bold;color:#1f377f;">p</span>.Priority - <span style="font-weight:bold;color:#1f377f;">reduction</span>) });</pre>
</p>
<p>
Notice that while the sum of priorities in <code>reduced</code> no longer sum to 100, it's okay, because <code>reduced</code> isn't a <code>PriorityCollection</code> object. It's just an <code><span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:blue;">string</span>>></code>.
</p>
<p>
You can now <a href="https://learn.microsoft.com/dotnet/api/system.linq.enumerable.append">Append</a> the <code>newPriority</code> to the <code>reduced</code> sequence and repackage that in a <code>PriorityCollection</code>:
</p>
<p>
<pre><span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">adjusted</span> = <span style="color:blue;">new</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:blue;">string</span>>(<span style="font-weight:bold;color:#1f377f;">reduced</span>.<span style="font-weight:bold;color:#74531f;">Append</span>(<span style="font-weight:bold;color:#1f377f;">newPriority</span>).<span style="font-weight:bold;color:#74531f;">ToArray</span>());</pre>
</p>
<p>
Like the original <code>pc</code> object, the <code>adjusted</code> object is valid upon construction, and since its immutable, it'll remain valid.
</p>
<h3 id="53475fec07ce46929951858e3d5be5ba">
Edit <a href="#53475fec07ce46929951858e3d5be5ba">#</a>
</h3>
<p>
If you think this process of unwrapping and rewrapping seems cumbersome, we can make it a bit more palatable by defining a wrapping <code>Edit</code> function, similar to the one in the <a href="/2024/06/24/a-mutable-priority-collection">previous article</a>:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#74531f;">Edit</span>(
<span style="color:#2b91af;">Func</span><<span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>>, <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>>> <span style="font-weight:bold;color:#1f377f;">edit</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">edit</span>(<span style="color:blue;">this</span>).<span style="font-weight:bold;color:#74531f;">ToArray</span>());
}</pre>
</p>
<p>
You can now write code equivalent to the above example like this:
</p>
<p>
<pre><span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">adjusted</span> = <span style="font-weight:bold;color:#1f377f;">pc</span>.<span style="font-weight:bold;color:#74531f;">Edit</span>(<span style="font-weight:bold;color:#1f377f;">col</span> =>
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">reduced</span> = <span style="font-weight:bold;color:#1f377f;">col</span>.<span style="font-weight:bold;color:#74531f;">Select</span>(<span style="font-weight:bold;color:#1f377f;">p</span> => <span style="font-weight:bold;color:#1f377f;">p</span> <span style="color:blue;">with</span> { Priority = (<span style="color:blue;">byte</span>)(<span style="font-weight:bold;color:#1f377f;">p</span>.Priority - <span style="font-weight:bold;color:#1f377f;">reduction</span>) });
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">reduced</span>.<span style="font-weight:bold;color:#74531f;">Append</span>(<span style="font-weight:bold;color:#1f377f;">newPriority</span>);
});</pre>
</p>
<p>
I'm not sure it's much of an improvement, though.
</p>
<h3 id="12f521756ae949f1bafc8294074446b4">
Using the right tool for the job <a href="#12f521756ae949f1bafc8294074446b4">#</a>
</h3>
<p>
While C# over the years has gained some functional-programming features, it's originally an object-oriented language, and working with immutable values may still seem a bit cumbersome. If so, consider using a language natively designed for this style of programming. On .NET, <a href="https://fsharp.org/">F#</a> is the obvious choice.
</p>
<p>
First, you define the required types:
</p>
<p>
<pre><span style="color:blue;">type</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">'a</span>> = { Item: <span style="color:#2b91af;">'a</span>; Priority: <span style="color:#2b91af;">byte</span> }
<span style="color:blue;">type</span> <span style="color:#2b91af;">PriorityList</span> = <span style="color:blue;">private</span> <span style="color:#2b91af;">PriorityList</span> <span style="color:blue;">of</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">string</span>> <span style="color:#2b91af;">list</span></pre>
</p>
<p>
Notice that <code>PriorityList</code> has a <code>private</code> constructor, so that client code can't just create any value. The type should protect its invariants, since <a href="/2022/10/24/encapsulation-in-functional-programming">encapsulation is also relevant in functional programming</a>. Since client code can't directly create <code>PriorityList</code> objects, you instead supply a function for that purpose:
</p>
<p>
<pre><span style="color:blue;">module</span> <span style="color:#2b91af;">PriorityList</span> =
<span style="color:blue;">let</span> <span style="color:#74531f;">tryCreate</span> <span style="font-weight:bold;color:#1f377f;">priorities</span> =
<span style="color:blue;">if</span> <span style="font-weight:bold;color:#1f377f;">priorities</span> |> <span style="color:#2b91af;">List</span>.<span style="color:#74531f;">sumBy</span> (_.Priority) = 100uy
<span style="color:blue;">then</span> <span style="color:#2b91af;">Some</span> (<span style="color:#2b91af;">PriorityList</span> <span style="font-weight:bold;color:#1f377f;">priorities</span>)
<span style="color:blue;">else</span> <span style="color:#2b91af;">None</span></pre>
</p>
<p>
That's really it, although you also need a way to work with the data. We supply two alternatives that correspond to the above C#:
</p>
<p>
<pre><span style="color:blue;">let</span> edit f (PriorityList priorities) = f priorities |> tryCreate
<span style="color:blue;">let</span> toList (PriorityList priorities) = priorities</pre>
</p>
<p>
These functions are also defined on the <code>PriorityList</code> module.
</p>
<p>
Here's the same adjustment example as shown above in C#:
</p>
<p>
<pre><span style="color:blue;">let</span> pl =
[ { Item = <span style="color:#a31515;">"foo"</span>; Priority = 60uy }; { Item = <span style="color:#a31515;">"bar"</span>; Priority = 40uy } ]
|> <span style="color:#2b91af;">PriorityList</span>.<span style="color:#74531f;">tryCreate</span>
<span style="color:blue;">let</span> newPriority = { Item = <span style="color:#a31515;">"baz"</span>; Priority = 20uy }
<span style="color:blue;">let</span> adjusted =
pl
|> <span style="color:#2b91af;">Option</span>.<span style="color:#74531f;">bind</span> (<span style="color:#2b91af;">PriorityList</span>.<span style="color:#74531f;">edit</span> (<span style="color:blue;">fun</span> <span style="font-weight:bold;color:#1f377f;">l</span> <span style="color:blue;">-></span>
<span style="font-weight:bold;color:#1f377f;">l</span>
|> <span style="color:#2b91af;">List</span>.<span style="color:#74531f;">map</span> (<span style="color:blue;">fun</span> <span style="font-weight:bold;color:#1f377f;">p</span> <span style="color:blue;">-></span>
{ <span style="font-weight:bold;color:#1f377f;">p</span> <span style="color:blue;">with</span> Priority = <span style="font-weight:bold;color:#1f377f;">p</span>.Priority - (newPriority.Priority / <span style="color:#74531f;">byte</span> <span style="font-weight:bold;color:#1f377f;">l</span>.Length) })
|> <span style="color:#2b91af;">List</span>.<span style="color:#74531f;">append</span> [ newPriority ]))</pre>
</p>
<p>
The entire F# definition is 15 lines of code, including namespace declaration and blank lines.
</p>
<h3 id="653bf17ab4cc4353b165638d497b74f1">
Conclusion <a href="#653bf17ab4cc4353b165638d497b74f1">#</a>
</h3>
<p>
With an immutable data structure, you only need to check the invariants upon creation. Invariants therefore become preconditions. Once a value is created in a valid state, it stays valid because it never changes state.
</p>
<p>
If you're having trouble maintaining invariants in an object-oriented design, try making the object immutable. It's likely to make it easier to attain good encapsulation.
</p>
</div>
<div id="comments">
<hr>
<h2 id="comments-header">
Comments
</h2>
<div class="comment" id="67a3a8d099f04aee9e38633c24919e03">
<div class="comment-author">Jiehong <a href="#67a3a8d099f04aee9e38633c24919e03">#</a></div>
<div class="comment-content">
<p>
First, it's a nice series of articles.
</p>
<p>
I see that nowadays C# has a generic projection, which is a sort of <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/with-expression">wither</a>
in Java parlance.
I should be usable instead of having to define the `Edit` one.
</p>
<p>
A way to make it more palatable would be to have a `tryAddAndRedistrube(Prioritized<T> element) : PriorityCollection | None` method to `PriorityCollection` that would try to reduce
priorities of elements, before adding the new one and returning a new `PriorityCollection` using that same `with` projection. This would allow the caller to
have a slightly simpler method to call, at the expense of having to store the new collection and assuming this is the intended way the caller wants to insert the element.
</p>
<p>
But, it's usually not possible to anticipate all the ways the clients wants to add elements to something, so I think I prefer the open-ended way this API lets clients choose.
</p>
</div>
<div class="comment-date">2024-07-29 13:53 UTC</div>
</div>
<div class="comment" id="caea05695c184c8294874896fa8b7553">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#caea05695c184c8294874896fa8b7553">#</a></div>
<div class="comment-content">
<p>
Thank you for writing. Whether or not a <em>wither</em> works in this case depends on language implementation details. For example, the F# example code doesn't allow <a href="https://learn.microsoft.com/dotnet/fsharp/language-reference/copy-and-update-record-expressions">copy-and-update expressions</a> because the record constructor is <code>private</code>. This is as it should be, since otherwise, client code would be able to circumvent the encapsulation.
</p>
<p>
I haven't tried to refactor the C# class to a <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/record">record</a>, and I don't recall whether C# <em>with expressions</em> respect custom constructors. That's a good exercise for any reader to try out; unfortunately, I don't have time for that at the moment.
</p>
<p>
As to your other point, it's definitely conceivable that a library developer could add more convenient methods to the <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> class, including one that uses a simple formula to redistribute existing priorities to make way for the new one. As far as I can tell, though, you'd be able to implement such more convenient APIs as extension methods that are implemented using the basic affordances already on display here. If so, we may consider the constructor and the <code><span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>></code> interface as the fundamental API. Everything else, including the <code>Edit</code> method, could build off that.
</p>
</div>
<div class="comment-date">2024-07-30 06:46 UTC</div>
</div>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.A mutable priority collectionhttps://blog.ploeh.dk/2024/06/24/a-mutable-priority-collection2024-06-24T17:59:00+00:00Mark Seemann
<div id="post">
<p>
<em>An encapsulated, albeit overly complicated, implementation.</em>
</p>
<p>
This is the second in a <a href="/2024/06/12/simpler-encapsulation-with-immutability">series of articles about encapsulation and immutability</a>. In the next article, you'll see how immutability makes encapsulation easier, but in order to appreciate that, you should see the alternative. This article, then, shows a working, albeit overly complicated, implementation that does maintain its invariants.
</p>
<p>
In the introductory article, I described the example problem in more details, but in short, the exercise is to develop a class that holds a collection of prioritized items, with the invariant that the priorities must always sum to 100. It should be impossible to leave the object in a state where that's not true. It's quite an illuminating exercise, so if you have the time, you should try it for yourself before reading on.
</p>
<h3 id="9f40c96077664ab7acbc2705d9e0d2ea">
Initialization <a href="#9f40c96077664ab7acbc2705d9e0d2ea">#</a>
</h3>
<p>
As the <a href="/2024/06/17/a-failed-attempt-at-priority-collection-with-inheritance">previous article</a> demonstrated, inheriting directly from a base class seems like a dead end. Once you see the direction that I go in this article, you may argue that it'd be possible to also make that design work with an inherited collection. It may be, but I'm not convinced that it would improve anything. Thus, for this iteration, I decided to eschew inheritance.
</p>
<p>
On the other hand, we need an API to <a href="https://en.wikipedia.org/wiki/Command%E2%80%93query_separation">query</a> the object about its state, and I found that it made sense to implement the <a href="https://learn.microsoft.com/dotnet/api/system.collections.generic.ireadonlydictionary-2">IReadOnlyDictionary</a> interface.
</p>
<p>
As before, invariants are statements that are always true about an object, and that includes a newly initialized object. Thus, the <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> class should require enough information to safely initialize.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>> : <span style="color:#2b91af;">IReadOnlyDictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> <span style="color:blue;">where</span> <span style="color:#2b91af;">T</span> : <span style="color:blue;">notnull</span>
{
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> dict;
<span style="color:blue;">public</span> <span style="color:#2b91af;">PriorityCollection</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">initial</span>)
{
dict = <span style="color:blue;">new</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> { { <span style="font-weight:bold;color:#1f377f;">initial</span>, 100 } };
}
<span style="color:green;">// IReadOnlyDictionary implemented by delegating to dict field...</span>
}</pre>
</p>
<p>
Several design decisions are different from the previous article. This design has no <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code> class. Instead it treats the item (of type <code>T</code>) as a dictionary key, and the priority as the value. The most important motivation for this design decision was that this enables me to avoid the 'leaf node mutation' problem that I demonstrated in the previous article. Notice how, while the general design in this iteration will be object-oriented and mutable, I already take advantage of a bit of immutability to make the design simpler and safer.
</p>
<p>
Another difference is that you can't initialize a <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> object with a list. Instead, you only need to tell the constructor what the <code>initial</code> item is. The constructor will then infer that, since this is the only item so far, its priority must be 100. It can't be anything else, because that would violate the invariant. Thus, no assertion is required in the constructor.
</p>
<h3 id="f3c5abe45ba949e69c349dc8e21e959a">
Mutation API <a href="#f3c5abe45ba949e69c349dc8e21e959a">#</a>
</h3>
<p>
So far, the code only implements the <code>IReadOnlyDictionary</code> API, so we need to add some methods that will enable us to add new items and so on. As a start, we can add methods to add, remove, or update items:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">key</span>, <span style="color:blue;">byte</span> <span style="font-weight:bold;color:#1f377f;">value</span>)
{
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(dict.<span style="font-weight:bold;color:#74531f;">Append</span>(<span style="color:#2b91af;">KeyValuePair</span>.<span style="color:#74531f;">Create</span>(<span style="font-weight:bold;color:#1f377f;">key</span>, <span style="font-weight:bold;color:#1f377f;">value</span>)));
dict.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="font-weight:bold;color:#1f377f;">key</span>, <span style="font-weight:bold;color:#1f377f;">value</span>);
}
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">Remove</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">key</span>)
{
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(dict.<span style="font-weight:bold;color:#74531f;">Where</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span> => !<span style="font-weight:bold;color:#1f377f;">kvp</span>.Key.<span style="font-weight:bold;color:#74531f;">Equals</span>(<span style="font-weight:bold;color:#1f377f;">key</span>)));
dict.<span style="font-weight:bold;color:#74531f;">Remove</span>(<span style="font-weight:bold;color:#1f377f;">key</span>);
}
<span style="color:blue;">public</span> <span style="color:blue;">byte</span> <span style="color:blue;">this</span>[<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">key</span>]
{
<span style="color:blue;">get</span> { <span style="font-weight:bold;color:#8f08c4;">return</span> dict[<span style="font-weight:bold;color:#1f377f;">key</span>]; }
<span style="color:blue;">set</span>
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">l</span> = dict.<span style="font-weight:bold;color:#74531f;">ToDictionary</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span> => <span style="font-weight:bold;color:#1f377f;">kvp</span>.Key, <span style="font-weight:bold;color:#1f377f;">kvp</span> => <span style="font-weight:bold;color:#1f377f;">kvp</span>.Value);
<span style="font-weight:bold;color:#1f377f;">l</span>[<span style="font-weight:bold;color:#1f377f;">key</span>] = <span style="color:blue;">value</span>;
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(<span style="font-weight:bold;color:#1f377f;">l</span>);
dict[<span style="font-weight:bold;color:#1f377f;">key</span>] = <span style="color:blue;">value</span>;
}
}</pre>
</p>
<p>
I'm not going to show the <code>AssertInvariants</code> helper method yet, since it's going to change anyway.
</p>
<p>
At this point, the implementation suffers from the same problem as the example in the previous article. While you can add new items, you can only add an item with priority 0. You can only remove items if they have priority 0. And you can only 'update' an item if you set the priority to the same value as it already had.
</p>
<p>
We need to be able to add new items, change their priorities, and so on. How do we get around the above problem, without breaking the invariant?
</p>
<h3 id="f9400ef096f94b15b4c32ae2f35ba000">
Edit mode <a href="#f9400ef096f94b15b4c32ae2f35ba000">#</a>
</h3>
<p>
One way out of this conundrum is introduce a kind of 'edit mode'. The idea is to temporarily turn off the maintenance of the invariant for long enough to allow edits.
</p>
<p>
Af first glance, such an idea seems to go against the very definition of an invariant. After all, an invariant is a statement about the object that is <em>always</em> true. If you allow a client developer to turn off that guarantee, then, clearly, the guarantee is gone. Guarantees only work if you can trust them, and you can't trust them if they can be cancelled.
</p>
<p>
That idea in itself doesn't work, but if we can somehow encapsulate such an 'edit action' in an isolated scope that either succeeds or fails in its entirety, we may be getting somewhere. It's an idea similar to <a href="https://en.wikipedia.org/wiki/Unit_of_work">Unit of Work</a>, although here we're not involving an actual database. Still, an 'edit action' is a kind of in-memory transaction.
</p>
<p>
For didactic reasons, I'll move toward that design in a series of step, where the intermediate steps fail to maintain the invariant. We'll get there eventually. The first step is to introduce 'edit mode'.
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">bool</span> isEditing;</pre>
</p>
<p>
While I could have made that flag <code>public</code>, I found it more natural to wrap access to it in two methods:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">BeginEdit</span>()
{
isEditing = <span style="color:blue;">true</span>;
}
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">EndEdit</span>()
{
isEditing = <span style="color:blue;">false</span>;
}</pre>
</p>
<p>
This still doesn't accomplishes anything in itself, but the final change in this step is to change the assertion so that it respects the flag:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">KeyValuePair</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>>> <span style="font-weight:bold;color:#1f377f;">candidate</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!isEditing && <span style="font-weight:bold;color:#1f377f;">candidate</span>.<span style="font-weight:bold;color:#74531f;">Sum</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span> => <span style="font-weight:bold;color:#1f377f;">kvp</span>.Value) != 100)
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">InvalidOperationException</span>(
<span style="color:#a31515;">"The sum of all values must be 100."</span>);
}</pre>
</p>
<p>
Finally, you can add or change priorities, as this little <a href="https://fsharp.org/">F#</a> example shows:
</p>
<p>
<pre>sut.BeginEdit ()
sut[<span style="color:#a31515;">"foo"</span>] <span style="color:blue;"><-</span> 50uy
sut[<span style="color:#a31515;">"bar"</span>] <span style="color:blue;"><-</span> 50uy
sut.EndEdit ()</pre>
</p>
<p>
Even if you nominally 'don't read F#', this little example is almost like C# without semicolons. The <code><span style="color:blue;"><-</span></code> arrow is F#'s mutation or assignment operator, which in C# would be <code>=</code>, and the <code>uy</code> suffix is <a href="https://learn.microsoft.com/dotnet/fsharp/language-reference/literals">the F# way of stating that the literal is a <code>byte</code></a>.
</p>
<p>
The above example is well-behaved because the final state of the object is valid. The priorities sum to 100. Even so, no code in <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> actually checks that, so we could trivially leave the object in an invalid state.
</p>
<h3 id="bcd53701e2214e99adcb1090acf3536a">
Assert invariant at end of edit <a href="#bcd53701e2214e99adcb1090acf3536a">#</a>
</h3>
<p>
The first step toward remedying that problem is to add a check to the <code>EndEdit</code> method:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">EndEdit</span>()
{
isEditing = <span style="color:blue;">false</span>;
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(dict);
}</pre>
</p>
<p>
The class is still not effectively protecting its invariants, because a client developer could forget to call <code>EndEdit</code>, or client code might pass around a collection in edit mode. Other code, receiving such an object as an argument, may not know whether or not it's in edit mode, so again, doesn't know if it can trust it.
</p>
<p>
We'll return to that problem shortly, but first, there's another, perhaps more pressing issue that we should attend to.
</p>
<h3 id="45cbf95701e14f08974cb5f1a585ad79">
Edit dictionary <a href="#45cbf95701e14f08974cb5f1a585ad79">#</a>
</h3>
<p>
The current implementation directly edits the collection, and even if a client developer remembers to call <code>EndEdit</code>, other code, higher up in the call stack could circumvent the check and leave the object in an invalid state. Not that I expect client developers to be deliberately malicious, but the notion that someone might wrap a method call in a <code>try-catch</code> block seems realistic.
</p>
<p>
The following F# unit test demonstrates the issue:
</p>
<p>
<pre>[<<span style="color:#2b91af;">Fact</span>>]
<span style="color:blue;">let</span> <span style="color:#74531f;">``Attempt to circumvent``</span> () =
<span style="color:blue;">let</span> <span style="font-weight:bold;color:#1f377f;">sut</span> = <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">string</span>> <span style="color:#a31515;">"foo"</span>
<span style="color:blue;">try</span>
<span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">BeginEdit</span> ()
<span style="font-weight:bold;color:#1f377f;">sut</span>[<span style="color:#a31515;">"foo"</span>] <span style="color:blue;"><-</span> 50uy
<span style="font-weight:bold;color:#1f377f;">sut</span>[<span style="color:#a31515;">"bar"</span>] <span style="color:blue;"><-</span> 48uy
<span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">EndEdit</span> ()
<span style="color:blue;">with</span> _ <span style="color:blue;">-></span> ()
100uy =! <span style="font-weight:bold;color:#1f377f;">sut</span>[<span style="color:#a31515;">"foo"</span>]
<span style="color:#74531f;">test</span> <@ <span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">ContainsKey</span> <span style="color:#a31515;">"bar"</span> |> <span style="color:#74531f;">not</span> @></pre>
</p>
<p>
Again, let me walk you through it in case you're unfamiliar with F#.
</p>
<p>
The <a href="https://learn.microsoft.com/dotnet/fsharp/language-reference/exception-handling/the-try-with-expression">try-with</a> block works just like C# <code>try-catch</code> blocks. Inside of that <code>try-with</code> block, the test enters edit mode, changes the values in such a way that the sum of them is 98, and then calls <code>EndEdit</code>. While <code>EndEdit</code> throws an exception, those four lines of code are wrapped in a <code>try-with</code> block that suppresses all exceptions.
</p>
<p>
The test attempts to verify that, since the edit failed, the <code>"foo"</code> value should be 100, and there should be no <code>"bar"</code> value. This turns out not to be the case. The test fails. The edits persist, even though <code>EndEdit</code> throws an exception, because there's no roll-back.
</p>
<p>
You could probably resolve that defect in various ways, but I chose to address it by introducing two, instead of one, backing dictionaries. One holds the data that always maintains the invariant, and the other is a temporary dictionary for editing.
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> current;
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> encapsulated;
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> editable;
<span style="color:blue;">private</span> <span style="color:blue;">bool</span> isEditing;
<span style="color:blue;">public</span> <span style="color:#2b91af;">PriorityCollection</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">initial</span>)
{
encapsulated = <span style="color:blue;">new</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> { { <span style="font-weight:bold;color:#1f377f;">initial</span>, 100 } };
editable = [];
current = encapsulated;
}</pre>
</p>
<p>
There are two dictionaries: <code>encapsulated</code> holds the always-valid list of priorities, while <code>editable</code> is the dictionary that client code will be editing when in edit mode. Finally, <code>current</code> is either of these: <code>editable</code> when the object is in edit mode, and <code>encapsulated</code> when it's not. Most of the existing code shown so far now uses <code>current</code>, which before was called <code>dict</code>. The important changes are in <code>BeginEdit</code> and <code>EndEdit</code>.
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">BeginEdit</span>()
{
isEditing = <span style="color:blue;">true</span>;
editable.<span style="font-weight:bold;color:#74531f;">Clear</span>();
<span style="font-weight:bold;color:#8f08c4;">foreach</span> (<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">kvp</span> <span style="font-weight:bold;color:#8f08c4;">in</span> current)
editable.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span>.Key, <span style="font-weight:bold;color:#1f377f;">kvp</span>.Value);
current = editable;
}</pre>
</p>
<p>
Besides setting the <code>isEditing</code> flag, <code>BeginEdit</code> now copies all data from <code>current</code> to <code>editable</code>, and then sets <code>current</code> to <code>editable</code>. Keep in mind that <code>encapsulated</code> still holds the original, valid values.
</p>
<p>
Now that I'm writing this, I'm not even sure if this method is re-entrant, in the following sense: What happens if client code calls <code>BeginEdit</code>, makes some changes, and then calls <code>BeginEdit</code> again? It's questions like these that I don't feel intelligent enough to feel safe that I always answer correctly. That's why I like functional programming better. I don't have to think so hard.
</p>
<p>
Anyway, this will soon become irrelevant, since <code>BeginEdit</code> and <code>EndEdit</code> will eventually become <code>private</code> methods.
</p>
<p>
The <code>EndEdit</code> method performs the inverse manoeuvre:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">EndEdit</span>()
{
isEditing = <span style="color:blue;">false</span>;
<span style="font-weight:bold;color:#8f08c4;">try</span>
{
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(current);
encapsulated.<span style="font-weight:bold;color:#74531f;">Clear</span>();
<span style="font-weight:bold;color:#8f08c4;">foreach</span> (<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">kvp</span> <span style="font-weight:bold;color:#8f08c4;">in</span> current)
encapsulated.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span>.Key, <span style="font-weight:bold;color:#1f377f;">kvp</span>.Value);
current = encapsulated;
}
<span style="font-weight:bold;color:#8f08c4;">catch</span>
{
current = encapsulated;
<span style="font-weight:bold;color:#8f08c4;">throw</span>;
}
}</pre>
</p>
<p>
It first checks the invariant, and only copies the edited values to the <code>encapsulated</code> dictionary if the invariant still holds. Otherwise, it restores the original <code>encapsulated</code> values and rethrows the exception.
</p>
<p>
This helps to make the nature of editing 'transactional' in nature, but it doesn't address the issue that the collection is in an invalid state during editing, or that a client developer may forget to call <code>EndEdit</code>.
</p>
<h3 id="d53f9fe83e944d1bbd58d478f9fc27bc">
Edit action <a href="#d53f9fe83e944d1bbd58d478f9fc27bc">#</a>
</h3>
<p>
As the next step towards addressing that problem, we may now introduce a 'wrapper method' for that little object protocol:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">Edit</span>(<span style="color:#2b91af;">Action</span><<span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>>> <span style="font-weight:bold;color:#1f377f;">editAction</span>)
{
<span style="font-weight:bold;color:#74531f;">BeginEdit</span>();
<span style="font-weight:bold;color:#1f377f;">editAction</span>(<span style="color:blue;">this</span>);
<span style="font-weight:bold;color:#74531f;">EndEdit</span>();
}</pre>
</p>
<p>
As you can see, it just wraps that little call sequence so that you don't have to remember to call <code>BeginEdit</code> and <code>EndEdit</code>. My F# test code comes with this example:
</p>
<p>
<pre>sut.Edit (<span style="color:blue;">fun</span> col <span style="color:blue;">-></span>
col[<span style="color:#a31515;">"bar"</span>] <span style="color:blue;"><-</span> 55uy
col[<span style="color:#a31515;">"baz"</span>] <span style="color:blue;"><-</span> 45uy
col.Remove <span style="color:#a31515;">"foo"</span>
)</pre>
</p>
<p>
The <code><span style="color:blue;">fun</span> <span style="font-weight:bold;color:#1f377f;">col</span> <span style="color:blue;">-></span></code> part is just F# syntax for a lambda expression. In C#, you'd write it as <code>col =></code>.
</p>
<p>
We're close to a solution. What remains is to make <code>BeginEdit</code> and <code>EndEdit</code> <code>private</code>. This means that client code can only edit a <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> object through the <code>Edit</code> method.
</p>
<h3 id="b04cc69a08c749f39d8e9276e444046a">
Replace action with interface <a href="#b04cc69a08c749f39d8e9276e444046a">#</a>
</h3>
<p>
You may complain that this solution isn't properly object-oriented, since it makes use of <a href="https://learn.microsoft.com/dotnet/api/system.action-1">Action<T></a> and requires that client code uses lambda expressions.
</p>
<p>
We can easily fix that.
</p>
<p>
Instead of the action, you can introduce a <a href="https://en.wikipedia.org/wiki/Command_pattern">Command</a> interface with the same signature:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">interface</span> <span style="color:#2b91af;">IPriorityEditor</span><<span style="color:#2b91af;">T</span>> <span style="color:blue;">where</span> <span style="color:#2b91af;">T</span> : <span style="color:blue;">notnull</span>
{
<span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">EditPriorities</span>(<span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">priorities</span>);
}</pre>
</p>
<p>
Next, change the <code>Edit</code> method:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">Edit</span>(<span style="color:#2b91af;">IPriorityEditor</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">editor</span>)
{
<span style="font-weight:bold;color:#74531f;">BeginEdit</span>();
<span style="font-weight:bold;color:#1f377f;">editor</span>.<span style="font-weight:bold;color:#74531f;">EditPriorities</span>(<span style="color:blue;">this</span>);
<span style="font-weight:bold;color:#74531f;">EndEdit</span>();
}</pre>
</p>
<p>
Now you have a nice, object-oriented design, with no lambda expressions in sight.
</p>
<h3 id="e15b63b0a3ef4f229caedc15a2b64f39">
Full code dump <a href="#e15b63b0a3ef4f229caedc15a2b64f39">#</a>
</h3>
<p>
The final code is complex enough that it's easy to lose track of what it looks like, as I walk through my process. To make it easer, here's the full code for the collection class:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>> : <span style="color:#2b91af;">IReadOnlyDictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>>
<span style="color:blue;">where</span> <span style="color:#2b91af;">T</span> : <span style="color:blue;">notnull</span>
{
<span style="color:blue;">private</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> current;
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> encapsulated;
<span style="color:blue;">private</span> <span style="color:blue;">readonly</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> editable;
<span style="color:blue;">private</span> <span style="color:blue;">bool</span> isEditing;
<span style="color:blue;">public</span> <span style="color:#2b91af;">PriorityCollection</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">initial</span>)
{
encapsulated = <span style="color:blue;">new</span> <span style="color:#2b91af;">Dictionary</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>> { { <span style="font-weight:bold;color:#1f377f;">initial</span>, 100 } };
editable = [];
current = encapsulated;
}
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">Add</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">key</span>, <span style="color:blue;">byte</span> <span style="font-weight:bold;color:#1f377f;">value</span>)
{
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(current.<span style="font-weight:bold;color:#74531f;">Append</span>(<span style="color:#2b91af;">KeyValuePair</span>.<span style="color:#74531f;">Create</span>(<span style="font-weight:bold;color:#1f377f;">key</span>, <span style="font-weight:bold;color:#1f377f;">value</span>)));
current.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="font-weight:bold;color:#1f377f;">key</span>, <span style="font-weight:bold;color:#1f377f;">value</span>);
}
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">Remove</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">key</span>)
{
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(current.<span style="font-weight:bold;color:#74531f;">Where</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span> => !<span style="font-weight:bold;color:#1f377f;">kvp</span>.Key.<span style="font-weight:bold;color:#74531f;">Equals</span>(<span style="font-weight:bold;color:#1f377f;">key</span>)));
current.<span style="font-weight:bold;color:#74531f;">Remove</span>(<span style="font-weight:bold;color:#1f377f;">key</span>);
}
<span style="color:blue;">public</span> <span style="color:blue;">byte</span> <span style="color:blue;">this</span>[<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">key</span>]
{
<span style="color:blue;">get</span> { <span style="font-weight:bold;color:#8f08c4;">return</span> current[<span style="font-weight:bold;color:#1f377f;">key</span>]; }
<span style="color:blue;">set</span>
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">l</span> = current.<span style="font-weight:bold;color:#74531f;">ToDictionary</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span> => <span style="font-weight:bold;color:#1f377f;">kvp</span>.Key, <span style="font-weight:bold;color:#1f377f;">kvp</span> => <span style="font-weight:bold;color:#1f377f;">kvp</span>.Value);
<span style="font-weight:bold;color:#1f377f;">l</span>[<span style="font-weight:bold;color:#1f377f;">key</span>] = <span style="color:blue;">value</span>;
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(<span style="font-weight:bold;color:#1f377f;">l</span>);
current[<span style="font-weight:bold;color:#1f377f;">key</span>] = <span style="color:blue;">value</span>;
}
}
<span style="color:blue;">public</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">Edit</span>(<span style="color:#2b91af;">IPriorityEditor</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">editor</span>)
{
<span style="font-weight:bold;color:#74531f;">BeginEdit</span>();
<span style="font-weight:bold;color:#1f377f;">editor</span>.<span style="font-weight:bold;color:#74531f;">EditPriorities</span>(<span style="color:blue;">this</span>);
<span style="font-weight:bold;color:#74531f;">EndEdit</span>();
}
<span style="color:blue;">private</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">BeginEdit</span>()
{
isEditing = <span style="color:blue;">true</span>;
editable.<span style="font-weight:bold;color:#74531f;">Clear</span>();
<span style="font-weight:bold;color:#8f08c4;">foreach</span> (<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">kvp</span> <span style="font-weight:bold;color:#8f08c4;">in</span> current)
editable.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span>.Key, <span style="font-weight:bold;color:#1f377f;">kvp</span>.Value);
current = editable;
}
<span style="color:blue;">private</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">EndEdit</span>()
{
isEditing = <span style="color:blue;">false</span>;
<span style="font-weight:bold;color:#8f08c4;">try</span>
{
<span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(current);
encapsulated.<span style="font-weight:bold;color:#74531f;">Clear</span>();
<span style="font-weight:bold;color:#8f08c4;">foreach</span> (<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">kvp</span> <span style="font-weight:bold;color:#8f08c4;">in</span> current)
encapsulated.<span style="font-weight:bold;color:#74531f;">Add</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span>.Key, <span style="font-weight:bold;color:#1f377f;">kvp</span>.Value);
current = encapsulated;
}
<span style="font-weight:bold;color:#8f08c4;">catch</span>
{
current = encapsulated;
<span style="font-weight:bold;color:#8f08c4;">throw</span>;
}
}
<span style="color:blue;">private</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">AssertInvariants</span>(<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">KeyValuePair</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>>> <span style="font-weight:bold;color:#1f377f;">candidate</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!isEditing && <span style="font-weight:bold;color:#1f377f;">candidate</span>.<span style="font-weight:bold;color:#74531f;">Sum</span>(<span style="font-weight:bold;color:#1f377f;">kvp</span> => <span style="font-weight:bold;color:#1f377f;">kvp</span>.Value) != 100)
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">InvalidOperationException</span>(
<span style="color:#a31515;">"The sum of all values must be 100."</span>);
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">T</span>> Keys
{
<span style="color:blue;">get</span> { <span style="font-weight:bold;color:#8f08c4;">return</span> current.Keys; }
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:blue;">byte</span>> Values
{
<span style="color:blue;">get</span> { <span style="font-weight:bold;color:#8f08c4;">return</span> current.Values; }
}
<span style="color:blue;">public</span> <span style="color:blue;">int</span> Count
{
<span style="color:blue;">get</span> { <span style="font-weight:bold;color:#8f08c4;">return</span> current.Count; }
}
<span style="color:blue;">public</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">ContainsKey</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">key</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> current.<span style="font-weight:bold;color:#74531f;">ContainsKey</span>(<span style="font-weight:bold;color:#1f377f;">key</span>);
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">IEnumerator</span><<span style="color:#2b91af;">KeyValuePair</span><<span style="color:#2b91af;">T</span>, <span style="color:blue;">byte</span>>> <span style="font-weight:bold;color:#74531f;">GetEnumerator</span>()
{
<span style="font-weight:bold;color:#8f08c4;">return</span> current.<span style="font-weight:bold;color:#74531f;">GetEnumerator</span>();
}
<span style="color:blue;">public</span> <span style="color:blue;">bool</span> <span style="font-weight:bold;color:#74531f;">TryGetValue</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">key</span>, [<span style="color:#2b91af;">MaybeNullWhen</span>(<span style="color:blue;">false</span>)] <span style="color:blue;">out</span> <span style="color:blue;">byte</span> <span style="font-weight:bold;color:#1f377f;">value</span>)
{
<span style="font-weight:bold;color:#8f08c4;">return</span> current.<span style="font-weight:bold;color:#74531f;">TryGetValue</span>(<span style="font-weight:bold;color:#1f377f;">key</span>, <span style="color:blue;">out</span> <span style="font-weight:bold;color:#1f377f;">value</span>);
}
<span style="color:#2b91af;">IEnumerator</span> <span style="color:#2b91af;">IEnumerable</span>.<span style="font-weight:bold;color:#74531f;">GetEnumerator</span>()
{
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#74531f;">GetEnumerator</span>();
}
}</pre>
</p>
<p>
The <code><span style="color:#2b91af;">IPriorityEditor</span><<span style="color:#2b91af;">T</span>></code> interface remains as shown above.
</p>
<h3 id="7994e307ceaf4857901378fe711f3ceb">
Conclusion <a href="#7994e307ceaf4857901378fe711f3ceb">#</a>
</h3>
<p>
Given how simple the problem is, this solution is surprisingly complicated, and I'm fairly sure that it's not even thread-safe.
</p>
<p>
At least it does, as far as I can tell, protect the invariant that the sum of priorities must always be exactly 100. Even so, it's just complicated enough that I wouldn't be surprised if a bug is lurking somewhere. It'd be nice if a simpler design existed.
</p>
<p>
<strong>Next:</strong> <a href="/2024/07/01/an-immutable-priority-collection">An immutable priority collection</a>.
</p>
</div>
<div id="comments">
<hr>
<h2 id="comments-header">
Comments
</h2>
<div class="comment" id="667d3faaebff4009bfffcd15612280ac">
<div class="comment-author">Joker_vD <a href="#667d3faaebff4009bfffcd15612280ac">#</a></div>
<div class="comment-content">
<p>
Where does the notion come that a data structure invariant has to be true <i>at all times</i>? I am fairly certain that it's only required to be true at "quiescent" points of executions. That is, just as the loop invariant is only required to hold before and after each loop step but not inside the loop step, so is the data structure invariant is only required to hold before and after each invocation of its public methods.
</p>
<p>
This definition actually has an interesting quirk which is absent in the loop invariant: a data structure's method can't, generally speaking, call other public methods of the very same data structure because the invariant might not hold at this particular point of execution! I've been personally bitten by this a couple of times, and I've seen others tripping over this subtle point as well. You yourself notice it when you muse about the re-entrancy of the <code>BeginEdit</code> method.
</p>
<p>
Now, this particular problem is quite similar to the problem with inner iteration, and can be solved the same way, with the outer editor, as you've done, although I would have probably provided each editor with its own, separate <code>editable</code> dictionary because right now, the editors cannot nest/compose... but that'd complicate implementation even further.
</p>
</div>
<div class="comment-date">2024-07-03 22:19 UTC</div>
</div>
<div class="comment" id="6a880573a3424f37b74bc78a8276d441">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#6a880573a3424f37b74bc78a8276d441">#</a></div>
<div class="comment-content">
<p>
Thank you for writing. As so many other areas of knowledge, the wider field of software development suffers from the problem of overlapping or overloaded terminology. The word <em>invariant</em> is just one of them. In this context, <em>invariant</em> doesn't refer to loop invariants, or any other kind of invariants used in algorithmic analysis.
</p>
<p>
As outlined in the <a href="/2024/06/12/simpler-encapsulation-with-immutability">introduction article</a>, when discussing <a href="/encapsulation-and-solid">encapsulation</a>, I follow <a href="/ref/oosc">Object-Oriented Software Construction</a> (OOSC). In that seminal work, <a href="https://en.wikipedia.org/wiki/Bertrand_Meyer">Bertrand Meyer</a> proposes the notion of design-by-contract, and specifically decomposes a contract into three parts: preconditions, invariants, and postconditions.
</p>
<p>
Having actually read the book, I'm well aware that it uses <a href="https://en.wikipedia.org/wiki/Eiffel_(programming_language)">Eiffel</a> as an exemplar of the concept. This has led many readers to conflate design-by-contract with Eiffel, and (in yet another logical derailment) conclude that it doesn't apply to, say, Java or C# programming.
</p>
<p>
It turns out, however, to transfer easily to other languages, and it's a concept with much practical potential.
</p>
<p>
A major problem with object-oriented design is that most ideas about good design are too 'fluffy' to be of immediate use to most developers. Take the <a href="https://en.wikipedia.org/wiki/Single-responsibility_principle">Single Responsibility Principle</a> (SRP) as an example. It's seductively easy to grasp the overall idea, but turns out to be hard to apply. Being able to identify <em>reasons to change</em> requires more programming experience than most people have. Or rather, the SRP is mostly useful to programmers who already have that experience. Being too 'fluffy', it's not a good learning tool.
</p>
<p>
I've spent quite some time with development organizations and individual programmers eager to learn, but struggling to find useful, concrete design rules. The decomposition of encapsulation into preconditions, invariants, and postconditions works well as a concrete, almost quantifiable heuristic.
</p>
<p>
Does it encompass everything that encapsulation means? Probably not, but it's by far the most effective heuristic that I've found so far.
</p>
<p>
Since I'm currently travelling, I don't have my copy of OOSC with me, but as far as I remember, the notion that an invariant should be true at all times originates there.
</p>
<p>
In any case, if an invariant doesn't always hold, then of what value is it? The whole idea behind encapsulation (as I read Meyer) is that client developers should be able to use 'objects' without having intimate knowledge of their implementation details. The use of <em>contracts</em> proposes to achieve that ideal by decoupling affordances from implementation details by condensing the legal protocol between object and client code into a contract. This means that a client developer, when making programming decisions, should be able to trust that certain guarantees stipulated by a contract always hold. If a client developer can't trust those guarantees, they aren't really guarantees.
</p>
<blockquote>
<p>
"the data structure invariant is only required to hold before and after each invocation of its public methods"
</p>
</blockquote>
<p>
I can see how a literal reading of OOSC may leave one with that impression. One must keep in mind, however, that the book was written in the eighties, at a time when multithreading wasn't much of a concern. (Incidentally, this is an omission that also mars a much later book on API design, the first edition of the .NET <a href="/ref/fdg">Framework Design Guidelines</a>.)
</p>
<p>
In modern code, concurrent execution is a real possibility, so is at least worth keeping in mind. I'm still most familiar with the .NET ecosystem, and in it, there are plenty of classes that are documented as <em>not</em> being thread-safe. You could say that such a statement is part of the contract, in which case what you wrote is true: The invariant is only required to hold before and after each method invocation.
</p>
<p>
If, on the other hand, you want to make the code thread-safe, you must be more rigorous than that. Then an invariant must truly always hold.
</p>
<p>
This is, of course, a design decision one may take. Just don't bother with thread-safety if it's not important.
</p>
<p>
Still, the overall thrust of this article series is that immutability makes encapsulation much simpler. This is also true when it comes to concurrency. Immutable data structures are automatically thread-safe.
</p>
</div>
<div class="comment-date">2024-07-06 8:07 UTC</div>
</div>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.A failed attempt at priority collection with inheritancehttps://blog.ploeh.dk/2024/06/17/a-failed-attempt-at-priority-collection-with-inheritance2024-06-17T08:04:00+00:00Mark Seemann
<div id="post">
<p>
<em>An instructive dead end.</em>
</p>
<p>
This article is part of <a href="/2024/06/12/simpler-encapsulation-with-immutability">a short series on encapsulation and immutability</a>. As the introductory article claims, object mutation makes it difficult to maintain invariants. In order to demonstrate the problem, I deliberately set out to do it wrong, and report on the result.
</p>
<p>
In subsequent articles in this series I will then show one way you can maintain the invariants in the face of mutation, as well as how much easier everything becomes if you choose an immutable design.
</p>
<p>
For now, however, I'll pretend to be naive and see how far I can get with that.
</p>
<p>
In the first article, I described the example problem in more details, but in short, the exercise is to develop a class that holds a collection of prioritized items, with the invariant that the priorities must always sum to 100. It should be impossible to leave the object in a state where that's not true. It's quite an illuminating exercise, so if you have the time, you should try it for yourself before reading on.
</p>
<h3 id="e5060f80472a46a7b5aac3061558f993">
Initialization <a href="#e5060f80472a46a7b5aac3061558f993">#</a>
</h3>
<p>
In object-oriented design it's common to inherit from a base class. Since I'll try to implement a collection of prioritized items, it seems natural to inherit from <a href="https://learn.microsoft.com/dotnet/api/system.collections.objectmodel.collection-1">Collection<T></a>:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>> : <span style="color:#2b91af;">Collection</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>></pre>
</p>
<p>
Of course, I also had to define <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code>:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">Prioritized</span>(<span style="color:#2b91af;">T</span> <span style="font-weight:bold;color:#1f377f;">item</span>, <span style="color:blue;">byte</span> <span style="font-weight:bold;color:#1f377f;">priority</span>)
{
Item = <span style="font-weight:bold;color:#1f377f;">item</span>;
Priority = <span style="font-weight:bold;color:#1f377f;">priority</span>;
}
<span style="color:blue;">public</span> <span style="color:#2b91af;">T</span> Item { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
<span style="color:blue;">public</span> <span style="color:blue;">byte</span> Priority { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }
}</pre>
</p>
<p>
Since <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code> is generic, it can be used to prioritize any kind of object. In the tests I wrote, however, I exclusively used strings.
</p>
<p>
A priority is a number between 0 and 100, so I chose to represent that with a <code>byte</code>. Not that this strongly protects invariants, because values can still exceed 100, but on the other hand, there's no reason to use a 32-bit integer to model a number between 0 and 100.
</p>
<p>
Now that I write this text, I realize that I could have added a Guard Clause to the <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code> constructor to enforce that precondition, but as you can tell, I didn't think of doing that. This omission, however, doesn't change the conclusion, because the problems that we'll run into stems from another source.
</p>
<p>
In any case, just inheriting from <code><span style="color:#2b91af;">Collection</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>></code> isn't enough to guarantee the invariant that the sum of priorities must be 100. An invariant must always hold, even for a newly initialized object. Thus, we need something like this ensure that this is the case:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>> : <span style="color:#2b91af;">Collection</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>>
{
<span style="color:blue;">public</span> <span style="color:#2b91af;">PriorityCollection</span>(<span style="color:blue;">params</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>[] <span style="font-weight:bold;color:#1f377f;">priorities</span>)
: <span style="color:blue;">base</span>(<span style="font-weight:bold;color:#1f377f;">priorities</span>)
{
<span style="font-weight:bold;color:#74531f;">AssertSumIsOneHundred</span>();
}
<span style="color:blue;">private</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">AssertSumIsOneHundred</span>()
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="color:blue;">this</span>.<span style="font-weight:bold;color:#74531f;">Sum</span>(<span style="font-weight:bold;color:#1f377f;">p</span> => <span style="font-weight:bold;color:#1f377f;">p</span>.Priority) != 100)
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">InvalidOperationException</span>(
<span style="color:#a31515;">"The sum of all priorities must be 100."</span>);
}
}</pre>
</p>
<p>
So far, there's no real need to have a separate <code>AssertSumIsOneHundred</code> helper method; I could have kept that check in the constructor, and that would have been simpler. I did, however, anticipate that I'd need the helper method in other parts of the code base. As it turned out, I did, but not without having to change it.
</p>
<h3 id="1326a8ef64124d138a084c4511f3899a">
Protecting overrides <a href="#1326a8ef64124d138a084c4511f3899a">#</a>
</h3>
<p>
The <code>Collection<T></code> base class offers normal collection methods like <a href="https://learn.microsoft.com/dotnet/api/system.collections.objectmodel.collection-1.add">Add</a>, <a href="https://learn.microsoft.com/dotnet/api/system.collections.objectmodel.collection-1.insert">Insert</a>, <a href="https://learn.microsoft.com/dotnet/api/system.collections.objectmodel.collection-1.remove">Remove</a> and so on. The default implementation allows client code to make arbitrary changes to the collection, including <a href="https://learn.microsoft.com/dotnet/api/system.collections.objectmodel.collection-1.clear">clearing it</a>. The <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> class can't allow that, because such edits could easily violate the invariants.
</p>
<p>
<code>Collection<T></code> is explicitly designed to be a base class, so it offers various <code>virtual</code> methods that inheritors can override to change the behaviour. In this case, this is necessary.
</p>
<p>
As it turned out, I quickly realized that I had to change my assertion helper method to check the invariant in various cases:
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">static</span> <span style="color:blue;">void</span> <span style="color:#74531f;">AssertSumIsOneHundred</span>(<span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>> <span style="font-weight:bold;color:#1f377f;">priorities</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">priorities</span>.<span style="font-weight:bold;color:#74531f;">Sum</span>(<span style="font-weight:bold;color:#1f377f;">p</span> => <span style="font-weight:bold;color:#1f377f;">p</span>.Priority) != 100)
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">InvalidOperationException</span>(
<span style="color:#a31515;">"The sum of all priorities must be 100."</span>);
}</pre>
</p>
<p>
By taking the sequence of <code>priorities</code> as an input argument, this enables me to simulate what would happen if I make a change to the actual collection, for example when adding an item to the collection:
</p>
<p>
<pre><span style="color:blue;">protected</span> <span style="color:blue;">override</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">InsertItem</span>(<span style="color:blue;">int</span> <span style="font-weight:bold;color:#1f377f;">index</span>, <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">item</span>)
{
<span style="color:#74531f;">AssertSumIsOneHundred</span>(<span style="color:blue;">this</span>.<span style="font-weight:bold;color:#74531f;">Append</span>(<span style="font-weight:bold;color:#1f377f;">item</span>));
<span style="color:blue;">base</span>.<span style="font-weight:bold;color:#74531f;">InsertItem</span>(<span style="font-weight:bold;color:#1f377f;">index</span>, <span style="font-weight:bold;color:#1f377f;">item</span>);
}</pre>
</p>
<p>
By using <a href="https://learn.microsoft.com/dotnet/api/system.linq.enumerable.append">Append</a>, the <code>InsertItem</code> method creates a sequence of values that simulates what the collection would look like if we add the candidate <code>item</code>. The <code>Append</code> function returns a new collection, so this operation doesn't change the actual <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code>. This only happens if we get past the assertion and call <code>InsertItem</code>.
</p>
<p>
Likewise, I can protect the invariant in the other overrides:
</p>
<p>
<pre><span style="color:blue;">protected</span> <span style="color:blue;">override</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">RemoveItem</span>(<span style="color:blue;">int</span> <span style="font-weight:bold;color:#1f377f;">index</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">l</span> = <span style="color:blue;">this</span>.ToList();
<span style="font-weight:bold;color:#1f377f;">l</span>.RemoveAt(<span style="font-weight:bold;color:#1f377f;">index</span>);
<span style="color:#74531f;">AssertSumIsOneHundred</span>(<span style="font-weight:bold;color:#1f377f;">l</span>);
<span style="color:blue;">base</span>.<span style="font-weight:bold;color:#74531f;">RemoveItem</span>(<span style="font-weight:bold;color:#1f377f;">index</span>);
}
<span style="color:blue;">protected</span> <span style="color:blue;">override</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">SetItem</span>(<span style="color:blue;">int</span> <span style="font-weight:bold;color:#1f377f;">index</span>, Prioritized<<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">item</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">l</span> = <span style="color:blue;">this</span>.ToList();
<span style="font-weight:bold;color:#1f377f;">l</span>[<span style="font-weight:bold;color:#1f377f;">index</span>] = <span style="font-weight:bold;color:#1f377f;">item</span>;
<span style="color:#74531f;">AssertSumIsOneHundred</span>(<span style="font-weight:bold;color:#1f377f;">l</span>);
<span style="color:blue;">base</span>.<span style="font-weight:bold;color:#74531f;">SetItem</span>(<span style="font-weight:bold;color:#1f377f;">index</span>, <span style="font-weight:bold;color:#1f377f;">item</span>);
}</pre>
</p>
<p>
I can even use it in the implementation of <code>ClearItems</code>, although that may seem a tad redundant:
</p>
<p>
<pre><span style="color:blue;">protected</span> <span style="color:blue;">override</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">ClearItems</span>()
{
<span style="color:#74531f;">AssertSumIsOneHundred</span>([]);
}</pre>
</p>
<p>
I could also just have thrown an exception directly from this method, since it's never okay to clear the collection. This would violate the invariant, because the sum of an empty collection of priorities is zero.
</p>
<p>
As far as I recall, the entire API of <code>Collection<T></code> is (transitively) based on those four <code>virtual</code> methods, so now that I've protected the invariant in all four, the <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> class maintains the invariant, right?
</p>
<p>
Not yet. See if you can spot the problem.
</p>
<p>
There are, in fact, at least two remaining problems. One that we can recover from, and one that is insurmountable with this design. I'll get back to the serious problem later, but see if you can spot it already.
</p>
<h3 id="0179acb780534b558c947b35c7f9c137">
Leaf mutation <a href="#0179acb780534b558c947b35c7f9c137">#</a>
</h3>
<p>
In the <a href="/2024/06/12/simpler-encapsulation-with-immutability">introductory article</a> I wrote:
</p>
<blockquote>
<p>
"If the mutation happens on a leaf node in an object graph, the leaf may have to notify its parent, so that the parent can recheck the invariants."
</p>
</blockquote>
<p>
I realize that this may sound abstract, but the current code presents a simple example. What happens if you change the <code>Priority</code> of an item after you've initialized the collection?
</p>
<p>
Consider the following example. For various reasons, I wrote the examples (that is, the unit tests) for this exercise in <a href="https://fsharp.org/">F#</a>, but even if you're not an F# developer, you can probably understand what's going on. First, we create a <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">string</span>></code> object and use it to initialize a <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">string</span>></code> object <a href="/2020/11/30/name-by-role">named sut</a>:
</p>
<p>
<pre><span style="color:blue;">let</span> <span style="font-weight:bold;color:#1f377f;">item</span> = <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">string</span>> (<span style="color:#a31515;">"foo"</span>, 40uy)
<span style="color:blue;">let</span> <span style="color:#1f377f;">sut</span> = <span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">string</span>> (<span style="font-weight:bold;color:#1f377f;">item</span>, <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">string</span>> (<span style="color:#a31515;">"bar"</span>, 60uy))</pre>
</p>
<p>
The <code>item</code> has a priority of <code>40</code> (the <code>uy</code> suffix is <a href="https://learn.microsoft.com/dotnet/fsharp/language-reference/literals">the F# way of stating that the literal is a <code>byte</code></a>), and the other unnamed value has a priority of <code>60</code>, so all is good so far; the sum is 100.
</p>
<p>
Since, however, <code>item</code> is a mutable object, we can now change its <code>Priority</code>:
</p>
<p>
<pre><span style="font-weight:bold;color:#1f377f;">item</span>.Priority <span style="color:blue;"><-</span> 50uy</pre>
</p>
<p>
This changes <code>item.Priority</code> to 50, but since none of the four <code>virtual</code> base class methods of <code>Collection<T></code> are involved, the <code>sut</code> never notices, the assertion never runs, and the object is now in an invalid state.
</p>
<p>
That's what I meant when I discussed mutations in leaf nodes. You can think of a collection as a rather flat and boring <a href="https://en.wikipedia.org/wiki/Tree_(data_structure)">tree</a>. The collection object itself is the root, and each of the items are leaves, and no further nesting is allowed.
</p>
<p>
When you edit a leaf, the root isn't automatically aware of such an event. You explicitly have to wire the object graph up so that this happens.
</p>
<h3 id="2edbce9f883448e89d118233bfceefef">
Event propagation <a href="#2edbce9f883448e89d118233bfceefef">#</a>
</h3>
<p>
One possible way to address this issue is to take advantage of .NET's event system. If you're reading along, but you normally write in another language, you can also use the <a href="https://en.wikipedia.org/wiki/Observer_pattern">Observer pattern</a>, or even <a href="https://reactivex.io/">ReactiveX</a>.
</p>
<p>
We need to have <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code> raise events, and one option is to let it implement <a href="https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanging">INotifyPropertyChanging</a>:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">sealed</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>> : <span style="color:#2b91af;">INotifyPropertyChanging</span></pre>
</p>
<p>
A <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code> object can now raise its <code>PropertyChanging</code> event before accepting an edit:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">byte</span> Priority
{
<span style="color:blue;">get</span> => priority;
<span style="color:blue;">set</span>
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (PropertyChanging <span style="color:blue;">is</span> { })
PropertyChanging(
<span style="color:blue;">this</span>,
<span style="color:blue;">new</span> <span style="color:#2b91af;">PriorityChangingEventArgs</span>(<span style="color:blue;">value</span>));
priority = <span style="color:blue;">value</span>;
}
}</pre>
</p>
<p>
where <code>PriorityChangingEventArgs</code> is a little helper class that carries the proposed <code>value</code> around:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">PriorityChangingEventArgs</span>(<span style="color:blue;">byte</span> <span style="font-weight:bold;color:#1f377f;">proposal</span>)
: <span style="color:#2b91af;">PropertyChangingEventArgs</span>(<span style="color:blue;">nameof</span>(Priority))
{
<span style="color:blue;">public</span> <span style="color:blue;">byte</span> Proposal { <span style="color:blue;">get</span>; } = <span style="font-weight:bold;color:#1f377f;">proposal</span>;
}</pre>
</p>
<p>
A <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> object can now subscribe to that event on each of the values it keeps track of, so that it can protect the invariant against leaf node mutations.
</p>
<p>
<pre><span style="color:blue;">private</span> <span style="color:blue;">void</span> <span style="font-weight:bold;color:#74531f;">Priority_PropertyChanging</span>(<span style="color:blue;">object</span>? <span style="font-weight:bold;color:#1f377f;">sender</span>, <span style="color:#2b91af;">PropertyChangingEventArgs</span> <span style="font-weight:bold;color:#1f377f;">e</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (<span style="font-weight:bold;color:#1f377f;">sender</span> <span style="color:blue;">is</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>> <span style="font-weight:bold;color:#1f377f;">p</span> &&
<span style="font-weight:bold;color:#1f377f;">e</span> <span style="color:blue;">is</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>.<span style="color:#2b91af;">PriorityChangingEventArgs</span> <span style="font-weight:bold;color:#1f377f;">pcea</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">l</span> = <span style="color:blue;">this</span>.<span style="font-weight:bold;color:#74531f;">ToList</span>();
<span style="font-weight:bold;color:#1f377f;">l</span>[<span style="font-weight:bold;color:#1f377f;">l</span>.<span style="font-weight:bold;color:#74531f;">IndexOf</span>(<span style="font-weight:bold;color:#1f377f;">p</span>)] = <span style="color:blue;">new</span> <span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>>(<span style="font-weight:bold;color:#1f377f;">p</span>.Item, <span style="font-weight:bold;color:#1f377f;">pcea</span>.Proposal);
<span style="color:#74531f;">AssertSumIsOneHundred</span>(<span style="font-weight:bold;color:#1f377f;">l</span>);
}
}</pre>
</p>
<p>
Such a solution comes with its own built-in complexity, because the <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> class must be careful to subscribe to the <code>PropertyChanging</code> event in various different places. A new <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code> object may be added to the collection during initialization, or via the <code>InsertItem</code> or <code>SetItem</code> methods. Furthermore, the collection should make sure to unsubscribe from the event if an item is removed from the collection.
</p>
<p>
To be honest, I didn't bother to implement these extra checks, because the point is moot anyway.
</p>
<h3 id="bebd0dc43a03466e9709a551bbd563ba">
Fatal flaw <a href="#bebd0dc43a03466e9709a551bbd563ba">#</a>
</h3>
<p>
The design shown here comes with a fatal flaw. Can you tell what it is?
</p>
<p>
Since the invariant is that the priorities must always sum to exactly 100, it's impossible to add, remove, or change any items after initialization.
</p>
<p>
Or, rather, you can add new <code><span style="color:#2b91af;">Prioritized</span><<span style="color:#2b91af;">T</span>></code> objects as long as their <code>Priority</code> is 0. Any other value breaks the invariant.
</p>
<p>
Likewise, the only item you can remove is one with a <code>Priority</code> of 0. Again, if you remove an item with any other <code>Priority</code>, you'd be violating the invariant.
</p>
<p>
A similar situation arises with editing an existing item. While you can change the <code>Priority</code> of an item, you can only 'change' it to the same value. So you can change 0 to 0, 42 to 42, or 100 to 100, but that's it.
</p>
<p>
<em>But</em>, I can hear you say, <em>I'll only change 60 to 40 because I intend to add a new item with a 20 priority! In the end, the sum will be 100!</em>
</p>
<p>
Yes, but this design doesn't know that, and you have no way of telling it.
</p>
<p>
While we may be able to rectify the situation, I consider this design so compromised that I think it better to start afresh with this realization. Thus, I'll abandon this version of <code><span style="color:#2b91af;">PriorityCollection</span><<span style="color:#2b91af;">T</span>></code> in favour of a fresh start in the next article.
</p>
<h3 id="6f81f5d6efb5476b9072f9d8e5b01031">
Conclusion <a href="#6f81f5d6efb5476b9072f9d8e5b01031">#</a>
</h3>
<p>
While I've titled this article "A failed attempt", the actual purpose was to demonstrate how 'aggregate' requirements make it difficult to maintain class invariants.
</p>
<p>
I've seen many code bases with poor encapsulation. As far as I can tell, a major reason for that is that the usual 'small-scale' object-oriented design techniques like Guard Clauses fall short when an invariant involves the interplay of multiple objects. And in real business logic, that's the rule rather than the exception.
</p>
<p>
Not all is lost, however. In the next article, I'll develop an alternative object-oriented solution to the priority collection problem.
</p>
<p>
<strong>Next:</strong> <a href="/2024/06/24/a-mutable-priority-collection">A mutable priority collection</a>.
</p>
</div>
<div id="comments">
<hr>
<h2 id="comments-header">
Comments
</h2>
<div class="comment" id="b86cf94255c34db29d0a6275787f18d8">
<div class="comment-author">Daniel Frost <a href="#b86cf94255c34db29d0a6275787f18d8">#</a></div>
<div class="comment-content">
<p>
2 things.
</p>
<p>
I had a difficult time getting this to work with as a mutable type and the only two things I could come with (i spent some hours on it, it was in fact hard!) was
<br><br>
1. To throw an exception when the items in the collection didn't sum up to the budget. That violates the variant because you can add and remove items all you want.
<br>
2. Another try, which I didn't finish, is to add some kind of result-object that could tell about the validity of the collection and not expose the collection items before the result is valid.
I haven't tried this and it doesn't resemble a collection but it could perhaps be a way to go.
<br>
I am also leaning towards a wrapper around the item type, making it immutable, so the items cannot change afterwards. Cheating ?
<br>
I tried with the events approach but it is as you put yourself not a very friendly type you end up with.
</p>
</div>
<div class="comment-date">2024-06-18 11:54 UTC</div>
</div>
<div class="comment" id="e9143a083d5449448e3bd69bfb8fde85">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#e9143a083d5449448e3bd69bfb8fde85">#</a></div>
<div class="comment-content">
<p>
Daniel, thank you for writing. You'll be interested in the next articles in the series, then.
</p>
</div>
<div class="comment-date">2024-06-18 13:55 UTC</div>
</div>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Simpler encapsulation with immutabilityhttps://blog.ploeh.dk/2024/06/12/simpler-encapsulation-with-immutability2024-06-12T15:33:00+00:00Mark Seemann
<div id="post">
<p>
<em>A worked example.</em>
</p>
<p>
I've noticed that many software organizations struggle with <a href="/encapsulation-and-solid">encapsulation</a> with 'bigger' problems. It may be understandable and easily applicable to <a href="/2022/08/22/can-types-replace-validation">define a NaturalNumber type</a> or ensure that a minimum value is less than a maximum value, and so on. How do you, however, guarantee invariants once the scope of the problem becomes bigger and more complex?
</p>
<p>
In this series of articles, I'll attempt to illustrate how and why this worthy design goal seems elusive, and what you can do to achieve it.
</p>
<h3 id="ff18a3c70d46435f9c301f20ce6bb830">
Contracts <a href="#ff18a3c70d46435f9c301f20ce6bb830">#</a>
</h3>
<p>
As usual, when I discuss <em>encapsulation</em>, I first need to establish what I mean by the term. It is, after all, one of the most misunderstood concepts in software development. As regular readers will know, I follow the lead of <a href="/ref/oosc">Object-Oriented Software Construction</a>. In that perspective, encapsulation is the appropriate modelling and application of <em>preconditions</em>, <em>invariants</em>, and <em>postconditions</em>.
</p>
<p>
Particularly when it comes to invariants, things seem to fall apart as the problem being modelled grows in complexity. Teams eventually give up guaranteeing any invariants, leaving client developers with no recourse but <a href="/2013/07/08/defensive-coding">defensive coding</a>, which again leads to code duplication, bugs, and maintenance problems.
</p>
<p>
If you need a reminder, an <em>invariant</em> is an assertion about an object that is always true. The more invariants an object has, the better guarantees it gives, and the more you can trust it. The more you can trust it, the less defensive coding you have to write. You don't have to check if return values are null, strings empty, numbers negative, collections empty, or so on.
</p>
<p>
<img src="/content/binary/contract-pre-post-invariant.png" alt="The three sets of preconditions, postconditions, and invariants, embedded in their common superset labeled contract.">
</p>
<p>
All together, I usually denote the collection of invariants, pre-, and postconditions as a type's <em>contract</em>.
</p>
<p>
For a simple example like modelling a natural number, or <a href="/2024/01/01/variations-of-the-range-kata">a range</a>, or a user name, most people are able to produce sensible and coherent designs. Once, however, the problem becomes more complex, and the invariants involve multiple interacting values, maintaining the contract becomes harder.
</p>
<h3 id="8d70ef6ac6054c87b920c972cf26b3a5">
Immutability to the rescue <a href="#8d70ef6ac6054c87b920c972cf26b3a5">#</a>
</h3>
<p>
I'm not going to bury the lede any longer. It strikes me that <em>mutation</em> is a major source of complexity. It's not that hard to check a set of conditions when you create a value (or object or record). What makes it hard to maintain invariants is when objects are allowed to change. This implies that for every possible change to the object, it needs to examine its current state in order to decide whether or not it should allow the operation.
</p>
<p>
If the mutation happens on a leaf node in an object graph, the leaf may have to notify its parent, so that the parent can recheck the invariants. If the <a href="https://en.wikipedia.org/wiki/Directed_graph">graph</a> has cycles it becomes more complicated still, and if you want to make the problem truly formidable, try making the object thread-safe.
</p>
<p>
Making the object immutable makes most of these problems go away. You don't have to worry about thread-safety, because immutable values are automatically thread-safe; there's no state for any thread to change.
</p>
<p>
Even better, though, is that an immutable object's contract is smaller and simpler. It still has preconditions, because there are rules that govern what has to be true before you can create such an object. Furthermore, there may also be rules that stipulate what must be true before you can call a method on it.
</p>
<p>
Likewise, postconditions are still relevant. If you call a method on the object, it may give you guarantees about what it returns.
</p>
<p>
There are, however, no independent invariants.
</p>
<p>
<img src="/content/binary/contract-pre-post.png" alt="The two sets of preconditions and postconditions, embedded in their common superset labeled contract.">
</p>
<p>
Or rather, the invariants for an immutable object entirely coincide with its preconditions. If it was valid at creation, it remains valid.
</p>
<h3 id="d281ea9242574c65bf85399178b2ce28">
Priority collection <a href="#d281ea9242574c65bf85399178b2ce28">#</a>
</h3>
<p>
As promised, I'll work through a problem to demonstrate what I mean. I'll first showcase how mutation makes the problem hard, and then how trivial it becomes with an immutable design.
</p>
<p>
The problem is this: Design and implement a class (or just a <em>data structure</em> if you don't want to do Object-Oriented programming) that models a priority list (not a <a href="https://en.wikipedia.org/wiki/Priority_queue">Priority Queue</a>) as you sometimes run into in surveys. You know, one of these survey questions that asks you to distribute 100 points on various different options:
</p>
<ul>
<li>Option F: 30%</li>
<li>Option A: 25%</li>
<li>Option C: 25%</li>
<li>Option E: 20%</li>
<li>Option B: 0%</li>
<li>Option D: 0%</li>
</ul>
<p>
If you have the time, I suggest that you <a href="/2020/01/13/on-doing-katas">treat this problem as a kata</a>. Try to do the exercise before reading the next articles in this series. You can assume the following, which is what I did.
</p>
<ul>
<li>The budget is 100. (You could make it configurable, but the problem is gnarly enough even with a hard-coded value.)</li>
<li>You don't need to include items with priority value 0, but you should allow it.</li>
<li>The sum of priorities must be exactly 100. This is the invariant.</li>
</ul>
<p>
The difficult part is that last invariant. Let me stress this requirement: At any time, the object should be in a consistent state; i.e. at any time should the sum of priorities be exactly 100. Not 101 or 99, but 100. Good luck with that.
</p>
<p>
The object should also be valid at initialization.
</p>
<p>
Of course, having read this far, you understand that all you have to do is to make the object immutable, but just for the sake of argument, try designing a mutable object with this invariant. Once you've tried your hand with that, read on.
</p>
<h3 id="e891a12040df4d81957d50b9110a6957">
Attempts <a href="#e891a12040df4d81957d50b9110a6957">#</a>
</h3>
<p>
There's educational value going through even failed attempts. When I thought of this example, I fairly quickly outlined in my head one approach that was unlikely to ever work, one that could work, and the nice immutable solution that trivially works.
</p>
<p>
I'll cover each in turn:
</p>
<ul>
<li><a href="/2024/06/17/a-failed-attempt-at-priority-collection-with-inheritance">A failed attempt at priority collection with inheritance</a></li>
<li><a href="/2024/06/24/a-mutable-priority-collection">A mutable priority collection</a></li>
<li><a href="/2024/07/01/an-immutable-priority-collection">An immutable priority collection</a></li>
</ul>
<p>
It's surprising how hard even a simple exercise like this one turns out to be, if you try to do it the object-oriented way.
</p>
<p>
In reality, business rules are much more involved than what's on display here. For only a taste of how bad it might get, read <a href="https://buttondown.email/hillelwayne/archive/making-illegal-states-unrepresentable/">Hillel Wayne's suggestions regarding a similar kind of problem</a>.
</p>
<h3 id="01740af0c0cc4afcac2cb2361689e209">
Conclusion <a href="#01740af0c0cc4afcac2cb2361689e209">#</a>
</h3>
<p>
If you've lived all your programming life with mutation as an ever-present possibility, you may not realize how much easier immutability makes everything. This includes invariants.
</p>
<p>
When you have immutable data, object graphs tend to be simpler. You can't easily define cyclic graphs (although <a href="https://www.haskell.org/">Haskell</a>, due to its laziness, surprisingly does enable this), and invariants essentially coincide with preconditions.
</p>
<p>
In the following articles, I'll show how mutability makes even simple invariants difficult to implement, and how immutability easily addresses the issue.
</p>
<p>
<strong>Next:</strong> <a href="/2024/06/17/a-failed-attempt-at-priority-collection-with-inheritance">A failed attempt at priority collection with inheritance</a>.
</p>
</div>
<div id="comments">
<hr>
<h2 id="comments-header">
Comments
</h2>
<div class="comment" id="667d3faaebff4009beefcd15612280ac">
<div class="comment-author">Marken Foo <a href="#667d3faaebff4009beefcd15612280ac">#</a></div>
<div class="comment-content">
<p>
I've been enjoying going through your articles in the past couple months, and I really like the very pedagogic treatment of functional programming and adjacent topics.
</p>
<p>
The kata here is an interesting one, but I don't think I'd link it with the concept of immutability/mutability. My immediate thought was a naïve struct that can represent illegal values and whose validity is managed through functions containing some tricky logic, but that didn't seem promising whether it was done immutably or not.
</p>
<p>
Instead, the phrase "distribute 100 points" triggered an association with the <a href="https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)">stars and bars</a> method for similar problems. The idea is that we have N=100 points in a row, and inserting dividers to break it into (numOptions) groups. Concretely, our data structure is (dividers: int array), which is a sorted array of length (numOptions + 1) where the first element is 0 and the last element is N=100. The priorities are then exactly the differences between adjacent elements of the array. The example in the kata (A=25, B=0, C=25, D=0, E=20, F=30) is then represented by the array [| 0; 25; 25; 50; 50; 70; 100|].
</p>
<p>
This solution seems to respect the invariant, has a configurable budget, can work with other numerical types, and works well whether immutable or not (if mutable, just ensure the array remains sorted, has min 0, and max N). The invariant is encoded in the representation of the data, which seems to me to be the more relevant point than mutability.
</p>
<p>
And a somewhat disjoint thought, the kata reminded me of a WinForms TableLayoutPanel (or MS Word table) whose column widths all must fit within the container's width...
</p>
</div>
<div class="comment-date">2024-06-13 13:55 UTC</div>
</div>
<div class="comment" id="3b2e1954394849c4970a1ab30f692192">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#3b2e1954394849c4970a1ab30f692192">#</a></div>
<div class="comment-content">
<p>
Thank you for writing. The danger of writing these article series is always that as soon as I've published the first one, someone comes by and puts a big hole through my premise. Well, I write this blog for a couple of independent reasons, and one of them is to learn.
</p>
<p>
And you just taught me something. Thank you. That is, at least, an elegant implementation.
</p>
<p>
How would you design the API encapsulating that implementation?
</p>
<p>
Clearly, arrays already have APIs, so you could obviously define an array-like API that performs the appropriate boundary checks. That, however, doesn't seem to model the given problem. Rather, it reveals the implementation, and forces a client developer to think in terms of the data structure, rather the problem (s)he has to solve.
</p>
<p>
Ideally, again channelling Bertrand Meyer, an object should present as an Abstract Data Structure (ADT) that doesn't require client developers to understand the implementation details. I'm curious what such an API would look like.
</p>
<p>
You've already surprised me once, and please do so once again. I'm always happy to learn something new, and that little stars-and-bars concept I've now added to my tool belt.
</p>
<p>
All that said, this article makes a more general claim, although its possible that the example it showcases is a tad too simple and naive to be a truly revealing one. The claim is that this kind of 'aggregate constraint' often causes so much trouble in the face of arbitrary state mutation that most programmers give up on encapsulation.
</p>
<p>
What happens if we instead expand the requirements a bit? Let's say that we will require the user to spend at least 90% of the budget, but no more than 100%. Also, there must be at least three prioritized items, and no individual item can receive more than a third of the budget.
</p>
</div>
<div class="comment-date">2024-06-14 14:22 UTC</div>
</div>
<div class="comment" id="7c5c157868fe46f3aae343e5e145a5eb">
<div class="comment-author">Marken Foo <a href="#7c5c157868fe46f3aae343e5e145a5eb">#</a></div>
<div class="comment-content">
<p>
Thank you for the response. Here's my thoughts - it's a bit of a wall of text, I might be wrong in any of the following, and the conclusion may be disappointing. When you ask how I'd design the API, I'd say it depends on how the priority list is going to be used. The implementation trick with stars and bars might just be a one-off trick that happens to work here, but it doesn't (shouldn't) affect the contract with the outside world.
</p>
<p>
If we're considering survey questions or budgets, the interest is in the priority values. So I think the problem then <em>is</em> about a list of priorities with an aggregate constraint. So I would define... an array-like API that performs the appropriate boundary checks (wow), but for the item priorities. My approach would be to go for "private data, public functions", and rely on a legal starting state and preserving the legality through the public API. In pseudocode:
</p>
<pre>
type PriorityList = { budget: int; dividers: int list }
create :: numItems: int -> budget: int -> PriorityList
// Returns priorities.
getAll :: plist: PriorityList -> int list
get :: itemIdx: int -> plist: PriorityList -> int
// *Sets the priority for an item (taking the priority from other items, starting from the back).
set :: itemIdx: int -> priority: int -> plist: PriorityList -> PriorityList
// *Adds a new item to (the end of) the PriorityList (with priority zero).
addItem :: plist: PriorityList -> PriorityList
// *Removes an item from the PriorityList (and assigns its priority to the last item).
removeItem :: itemIdx: int -> plist PriorityList -> PriorityList
// Utility functions: see text
_toPriorities :: dividers: int list -> int list
_toDividers :: priorities: int list -> int list
</pre>
<p>
Crucially: since <code>set</code>, <code>addItem</code>, and <code>removeItem</code> must maintain the invariants, they must have "side effects" of altering other priorities. I think this is unavoidable here because we have aggregate/global constraints, rather than just elementwise/local constraints. (Is this why resizing rows and columns in WinForms tableLayoutPanels and MS Word tables is so tedious?) This will manifest in the API - the client needs to know what "side effects" there are (suggested behaviour in parentheses in the pseudocode comments above). See <a href="https://gist.github.com/Marken-Foo/d1e1a32afa91790f84f151c429c042cd">my crude attempt at implementation</a>.
</p>
<p>
You may already see where this is going. If I accept that boundary checks are needed, then my secondary goal in encapsulation is to express the constraints as clearly as possible, and hopefully not spread the checking logic all over the code.
</p>
<p>
Whence the utility functions: it turned out to be useful to convert from a list of dividers to priorities, and vice versa. This is because the elementwise operations/invariants like the individual priority values are easier to express in terms of raw priorities, while the aggregate ones like the total budget are easier in terms of "dividers" (the <em>cumulative</em> priorities). There is a runtime cost to the conversion, but the code becomes clearer. This smells similar to feature envy...
</p>
<p>
So why not just have the underlying implementation hold a list of priorities in the first place?! Almost everything in the implementation needs translation back to that anyway. D'oh! I refactored myself back to the naïve approach. The original representation seemed elegant, but I couldn't find a way to manipulate it that clients would find intuitive and useful in the given problem.
</p>
<p>
But... if I approach the design from the angle "what advantages does the cumulative priority model offer?", I might come up with the following candidate API functions, which could be implemented cleanly in the "divider" space:
</p>
<pre>
// (same type, create, get, getAll, addItem as above)
// Removes the item and merges its priority with the item before it.
merge :: ItemIdx: int -> PriorityList
// Sets the priority of an item to zero and gives it to the item after it.
collapse :: itemIdx: int -> PriorityList
// Swaps the priority of an item and the one after it (e.g. to "bubble" a priority value forwards or backwards, although this is easier in the "priority" space)
swap :: itemIdx: int -> PriorityList
// Sets (alternative: adds to) the priority of an item, taking the priority from the items after it in sequence ("consuming" them in the forward direction)
consume :: itemIdx: int -> priority: int -> PriorityList
// Splits the item into 2 smaller items each with half the priority (could be generalised to n items)
split :: ItemIdx: int -> PriorityList
// etc.
</pre>
<p>
And this seems like a more fitting API for that table column width example I keep bringing up. What's interesting to me is that despite the data structures of the budget/survey question and the table column widths being isomorphic, we can come up with rather different APIs depending on which view we consider. I think this is my main takeaway from this exploration, actually.
</p>
<p>
As for the additional requirements, individually each constraint is easy to handle, but their composition is tricky. If it's easy to transform an illegal PriorityList to make it respect the invariants, we can just apply the transformation after every create/set/add/remove. Something like:
</p>
<pre>
type PriorityList =
{ budget: int
dividers: int list
budgetCondition: int -> bool
maxPriority: int
minChoices: int }
let _enforceBudget (predicate: int -> bool) (defaultBudget: int) (dividers: int list) : int list =
if (List.last dividers |> predicate) then
dividers
else
List.take (dividers.Length - 1) dividers @ [ defaultBudget ]
let _enforceMaxPriority (maxPriority: int) (dividers: int list) : int list =
_toPriorities dividers |> List.map (fun p -> min p maxPriority) |> _toDividers
</pre>
<p>
The problem is those transforms may not preserve each others' invariant. Life would be easy if we could write a single transform to preserve everything (I haven't found one - notice that the two above are operating on different int lists so it's tricky). Otherwise, we could write validations instead of transformations, then let create/set/add/remove fail by returning Option.None (explicitly fail) or the original list (silently fail). This comes at the cost of making the API less friendly.
</p>
<p>
Ultimately with this approach I can't see a way to make all illegal states unrepresentable without sprinkling ad-hoc checks everywhere in the code. The advantages of the "cumulative priorities" representation I can think of are (a) it makes the total budget invariant obvious, and (b) it maps nicely to a UI where you click and drag segments around. Since you might have gone down a different path in the series, I'm curious to see how that shapes up.
</p>
</div>
<div class="comment-date">2024-06-15 14:48 UTC</div>
</div>
<div class="comment" id="595bcdcf19e446c7a23531b93b6d5a1c">
<div class="comment-author">Aliaksei Saladukhin <a href="#595bcdcf19e446c7a23531b93b6d5a1c">#</a></div>
<div class="comment-content">
<p>
Hello and thank you for your blog. It is really informative and provides great food for thought.
</p>
<p>
What if it will be impossible to compile and run program which would lead to illegal (list) state?
</p>
<p>
I've tried to implement priority collection in Rust, and what I've ended up with is a heterogenous priority list with compile-time priority validation.
Idea behind this implementation is simple: you declare recursive generic struct, which holds current element and tail (another list or unit type).
</p>
<pre>
struct PriorityList<const B: usize, const P: usize, H, T> {
head: H,
tail: T,
}
</pre>
<p>
If, for example, we need list of two Strings with budget 100, and 30/70 priority split, it will have the following type:
<code>PriorityList<100, 30, String, PriorityList<100, 70, String, ()>></code>
Note that information about list budget and current element priority is contained in generic arguments B and P respectively.
These are compile-time "variables", and will be replaced be their values in compiled program.
</p>
<p>
Since each element of such list is a list itself, and budget is the same for each element, all elements except the first are invalid priority lists.
So, in order to make it possible to create lists other than containing one element, or only one element with >0 priority, validity check should be targeted and deferred.
In order to target invariant validation on the first element of the list, I've included validation into list methods (except set_priority method).
Every time list method is called, compiler does recursive computation of priority sum, and compares it with list budget, giving compile-time error if there is mismatch.
Consider the following example, which will compile and run:
</p>
<pre>
let list = ListBuilder::new::<10, 10>("Hello");
let list = list.set_priority::<5>();
</pre>
<p>
Seems like invariants have been violated and sum of priorities is less than the budget.
But if we try to manipulate this list in any other way except to add element or change priority, program won't compile
</p>
<pre>
// Won't compile
let _ = list.pop();
// Won't compile
let list = list.push::<4>("Hi");
// Will do
let list = list.push::<5>("Hello there");
</pre>
<p>
This implementation may not be as practical as it could be due to verbose compilation error messages, but is a good showcase and exercise
I've also uploaded full source code at GitLab: https://gitlab.com/studiedlist/priority-collection
</p>
</div>
<div class="comment-date">2024-06-18 08:47 UTC</div>
</div>
<div class="comment" id="7f2ed4d386144b378cae2206e8269a6d">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#7f2ed4d386144b378cae2206e8269a6d">#</a></div>
<div class="comment-content">
<p>
Marken, thank you for writing. It's always interesting to learn new techniques, and, as I previously mentioned, the array-based implementation certainly seems to <a href="https://blog.janestreet.com/effective-ml-video/">make illegal states unrepresentable</a>. And then, as we'll see in the last (yet unpublished) article in this little series, if we also make the data structure immutable, we'll have a truly simple and easy-to-understand API to work with.
</p>
<p>
I've tried experimenting with the <a href="https://fsharp.org/">F#</a> script you linked, but I must admit that I'm having trouble understanding how to use it. You did write that it was a crude attempt, so I'm not complaining, but on the other hand, it doesn't work well as an example of good encapsulation. The following may seem as though I'm moving the goalpost, so apologies for that in advance.
</p>
<p>
Usually, when I consult development organizations about software architecture, the failure to maintain invariants is so fundamental that I usually have to start with that problem. That's the reason that this article series is so narrow-mindedly focused on contract, and seemingly not much else. We must not, though, lose sight of what ultimately motivates us to consider encapsulation beneficial. This is what I've tried to outline in <a href="/2021/06/14/new-book-code-that-fits-in-your-head">Code That Fits in Your Head</a>: That the human brain is ill-suited to keep all implementation details in mind at the same time. One way we may attempt to address this problem is to hide implementation details behind an API which, additionally, comes with some guarantees. Thus (and this is where you may, reasonably, accuse me of moving the goal post), not only should an object fulfil its contract, it should also be possible to interact with its API without understanding implementation details.
</p>
<p>
The API you propose seem to have problems, some of which may be rectifiable:
</p>
<ul>
<li>At a fundamental level, it's not really clear to me how to use the various functions in the script file.</li>
<li>The API doesn't keep track of <em>what</em> is being prioritized. This could probably be fixed.</li>
<li>It's not clear whether it's possible to transition from one arbitrary valid distribution to another arbitrary valid distribution.</li>
</ul>
<p>
I'll briefly expand on each.
</p>
<p>
As an example of the API being less that clear to me, I can't say that I understand what's going on here:
</p>
<p>
<pre>> create 1 100 |> set 1 50 |> addItem |> set 1 30;;
val it: PriorityList = { budget = 100
dividers = [0; 50; 100] }</pre>
</p>
<p>
As for what's being prioritized, you could probably mend that shortcoming by letting the array be an array of tuples.
</p>
<p>
The last part I'm not sure of, but you write:
</p>
<blockquote>
<p>
"Crucially: since <code>set</code>, <code>addItem</code>, and <code>removeItem</code> must maintain the invariants, they must have "side effects" of altering other priorities."
</p>
</blockquote>
<p>
As <a href="/2024/06/24/a-mutable-priority-collection">the most recent article in this series demonstrates</a>, this isn't an overall limitation imposed by the invariant, but rather by your chosen API design. Specifically, assuming that you initially have a <em>23, 31, 46</em> distribution, how do you transition to a <em>19, 29, 43, 7, 2</em> distribution?
</p>
</div>
<div class="comment-date">2024-06-27 6:42 UTC</div>
</div>
<div class="comment" id="388933ccbe5a4c71ba0b443a223e08ca">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#388933ccbe5a4c71ba0b443a223e08ca">#</a></div>
<div class="comment-content">
<p>
Aliaksei, thank you for writing. I've never programmed in Rust, so I didn't know it had that capability. At first I though it was dependent typing, but after reading up on it, it seems as though it's not quite that.
</p>
<p>
An exercise like the one in this article series is useful because it can help shed light on options and their various combinations of benefits and drawbacks. Thus, there are no entirely right or wrong solutions to such an exercise.
</p>
<p>
Since I don't know Rust, I can't easily distinguish what might be possible drawbacks here. I usually regard making illegal states unrepresentable as a benefit, but we must always be careful not to go too far in that direction. One thing is to reject invalid states, but can we still represent all valid states? What if priority distributions are run-time values?
</p>
</div>
<div class="comment-date">2024-06-28 7:21 UTC</div>
</div>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.You'll regret using natural keyshttps://blog.ploeh.dk/2024/06/03/youll-regret-using-natural-keys2024-06-03T19:46:00+00:00Mark Seemann
<div id="post">
<p>
<em>Beating another dead horse.</em>
</p>
<p>
Although I live in Copenhagen and mostly walk or ride my bicycle in order to get around town, I do own an old car for getting around the rest of the country. In Denmark, cars go through mandatory official inspection every other year, and I've been through a few of these in my life. A few years ago, the mechanic doing the inspection informed me that my car's <a href="https://en.wikipedia.org/wiki/Vehicle_identification_number">chassis number</a> was incorrect.
</p>
<p>
This did make me a bit nervous, because I'd bought the car used, and I was suddenly concerned that things weren't really as I thought. Had I unwittingly bought a stolen car?
</p>
<p>
But the mechanic just walked over to his computer in order to correct the error. That's when a different kind of unease hit me. When you've programmed for some decades, you learn to foresee various typical failure modes. Since a chassis number is an obvious candidate for a <a href="https://en.wikipedia.org/wiki/Natural_key">natural key</a>, I already predicted that changing the number would prove to be either impossible, or have all sorts of cascading effects, ultimately terminating in official records no longer recognizing that the car is mine.
</p>
<p>
As it turned out, though, whoever made that piece of software knew what they were doing, because the mechanic just changed the chassis number, and that was that. This is now five or six years ago, and I still own the same car, and I've never had any problems with the official ownership records.
</p>
<h3 id="8a38dcbfae1146f8868fe8a408ffe5d8">
Uniqueness <a href="#8a38dcbfae1146f8868fe8a408ffe5d8">#</a>
</h3>
<p>
The reason I related this story is that I'm currently following an undergraduate course in databases and information systems. Since this course is aimed at students with no real-world experience, it wisely moves forward in a pedagogical progression. In order to teach database keys, it starts with natural keys. From a didactic perspective, this makes sense, but the result, so far, is that the young people I work with now propose database designs with natural keys.
</p>
<p>
I'm not blaming anyone. You have to learn to crawl before you can walk.
</p>
<p>
Still, this situation made me reflect on the following question: <em>Are natural keys ever a good idea?</em>
</p>
<p>
Let's consider an example. For a little project we're doing, we've created a database of <a href="https://www.theworlds50best.com/">the World's 50 best restaurants</a>. My fellow students suggest a table design like this:
</p>
<p>
<pre><span style="color:blue;">CREATE</span> <span style="color:blue;">TABLE</span> Restaurants<span style="color:blue;"> </span><span style="color:gray;">(</span>
<span style="color:magenta;">year</span> <span style="color:blue;">TEXT</span> <span style="color:gray;">NOT</span> <span style="color:gray;">NULL,</span>
<span style="color:magenta;">rank</span> <span style="color:blue;">TEXT</span> <span style="color:gray;">NOT</span> <span style="color:gray;">NULL,</span>
restaurantName <span style="color:blue;">TEXT</span> <span style="color:gray;">NOT</span> <span style="color:gray;">NULL,</span>
cityName <span style="color:blue;">TEXT</span> <span style="color:gray;">NOT</span> <span style="color:gray;">NULL</span>
<span style="color:gray;">);</span></pre>
</p>
<p>
Granted, at this point, this table definition defines no key at all. I'm not complaining about that. After all, a month ago, the students probably hadn't seen a database table.
</p>
<p>
From following the course curriculum, it'd be natural, however, to define a key for the <code>Restaurants</code> table as the combination of <code>restaurantName</code>, <code>cityName</code>, and <code>year</code>. The assumption is that name and city uniquely identifies a restaurant.
</p>
<p>
In this particular example, this assumption may actually turn out to hold. So far. After all, the data set isn't that big, and it's important for restaurants in that league to have recognizable names. If I had to guess, I'd say that there's probably only one <a href="https://www.nobelhartundschmutzig.com/">Nobelhart & Schmutzig</a> in the world.
</p>
<p>
Still, a good software architect should challenge the underlying assumptions. Is name and city a <em>natural</em> key? It's easy to imagine that it's not. What if we expand the key to include the country as well? Okay, but what if we had a restaurant named <em>China Wok</em> in Springfield, USA? Hardly unique. Add the state, you say? Probably still not unique.
</p>
<h3 id="778bd217e62d4ffca25f487a39d34c1a">
Identity <a href="#778bd217e62d4ffca25f487a39d34c1a">#</a>
</h3>
<p>
Ensuring uniqueness is only the first of many problems with natural keys. You may quickly reach the conclusion that for a restaurant database, a <a href="https://en.wikipedia.org/wiki/Surrogate_key">synthetic key</a> is probably the best choice.
</p>
<p>
But what about 'natural' natural keys, so to speak? An example may be a car's chassis number. This is already an opaque number, and it probably originates from a database somewhere. Or how about a personal identification number? In Denmark we have the <a href="https://en.wikipedia.org/wiki/Personal_identification_number_(Denmark)">CPR number</a>, and I understand that the US <a href="https://en.wikipedia.org/wiki/Social_Security_number">Social Security Number</a> is vaguely analogous.
</p>
<p>
If you're designing a database that already includes such a personal identification number, you might be tempted to use it as a natural key. After all, it's already a key somewhere else, so it's guaranteed to be unique, right?
</p>
<p>
Yes, the number may uniquely identify a person, but the converse may not be true. A person may have more than one identification number. At least when time is a factor.
</p>
<p>
As an example, for technical-historical reasons, the Danish CPR number carries information (which keys shouldn't do), such as a person's date of birth and sex. Since 2014 a new law enables transsexual citizens to get a new CPR number that reflects their perceived gender. The consequence is that the same person may have more than one CPR number. Perhaps not more than one at the same time, but definitely two during a lifetime.
</p>
<p>
Even if existing keys are guaranteed to be unique, you can't assume that the uniqueness gives rise to a <a href="https://en.wikipedia.org/wiki/Bijection">bijection</a>. If you use an external unique key, you may lose track of the entities that you're trying to keep track of.
</p>
<p>
This is true not only for people, but cars, bicycles (which also have chassis numbers), network cards, etc.
</p>
<h3 id="93d43ca6c76a4c6c83e9542bb671f39c">
Clerical errors <a href="#93d43ca6c76a4c6c83e9542bb671f39c">#</a>
</h3>
<p>
Finally, even if you've found a natural key that is guaranteed to be unique <em>and</em> track the actual entity that you want to keep track of, there's a final argument against using an externally defined key in your system: Data-entry errors.
</p>
<p>
Take the story about my car's chassis number. The mechanic who spotted the discrepancy clearly interpreted it as a clerical error.
</p>
<p>
After a few decades of programming, I've learned that sooner or later, there <em>will</em> be errors in your data. Either it's a clerical error, or the end-user mistyped, or there was a data conversion error when importing from an external system. Or even data conversion errors within the <em>same</em> system, as it goes through upgrades and migrations.
</p>
<p>
Your system should be designed to allow corrections to data. This includes corrections of external keys, such as chassis numbers, government IDs, etc. This means that you can't use such keys as database keys in your own system.
</p>
<h3 id="ca9efd721698452f856b089fc3f69ad1">
Heuristic <a href="#ca9efd721698452f856b089fc3f69ad1">#</a>
</h3>
<p>
Many were the times, earlier in my career, when I decided to use a 'natural key' as a key in my own database. As far as I recall, I've regretted it every single time.
</p>
<p>
These days I follow a hard heuristic: Always use synthetic keys for database tables.
</p>
<h3 id="c174062e2ad14b6a9ff4056b1de80a0f">
Conclusion <a href="#c174062e2ad14b6a9ff4056b1de80a0f">#</a>
</h3>
<p>
Is it ever a good idea to use natural keys in a database design? My experience tells me that it's not. Ultimately, regardless of how certain you can be that the natural key is stable and correctly tracks the entity that it's supposed to keep track of, data errors will occur. This includes errors in those natural keys.
</p>
<p>
You should be able to correct such errors without losing track of the involved entities. You'll regret using natural keys. Use synthetic keys.
</p>
</div>
<div id="comments">
<hr>
<h2 id="comments-header">
Comments
</h2>
<div class="comment" id="63e21d2f538e4d67a30094e33ff507a7">
<div class="comment-author"><a href="http:/snape.me">James Snape</a> <a href="#63e21d2f538e4d67a30094e33ff507a7">#</a></div>
<div class="comment-content">
<p>
There are lots of different types of keys. I agree that using natural keys as physical primary keys is a bad idea but you really should be modelling your data logically with natural keys.
Thinking about uniqueness and identity is a part of your data design. Natural keys often end up as constraints, indexes and query plans.
When natural keys are not unique enough then you need to consider additional attributes in your design to ensure access to a specific record.
</p>
<p>
Considering natural keys during design can help elicit additional requirements and business rules. "Does a social security number uniquely identify a person? If not why?"
In the UK they recycle them so the natural key is a combination of national insurance number and birth year. You have to ask questions.
</p>
</div>
<div class="comment-date">2024-06-04 15:43 UTC</div>
</div>
<div class="comment" id="82ee5d39a4d34539899ddaf13d1336a9">
<div class="comment-author"><a href="https://thomascastiglione.com">Thomas Castiglione</a> <a href="#82ee5d39a4d34539899ddaf13d1336a9">#</a></div>
<div class="comment-content">
<img src="/content/binary/you-will-regret-this.png" border="0">
</div>
<div class="comment-date">2024-06-05 9:33 UTC</div>
</div>
<div class="comment" id="92ee5d39a4d34539899ddaf13d1336b7">
<div class="comment-author"><a href="https://processdecision.com">Nicholas Peterson</a> <a href="#92ee5d39a4d34539899ddaf13d1336b7">#</a></div>
<div class="comment-content">
<p>
I largely agree with James Snape, but wanted to throw in a few other thoughts on top.
Surrogates don't defend you from duplicate data, in fact they facilitate it, because the routine generating the surrogate key isn't influenced by any of the other data in the record.
The concept of being unable to correct a natural key is also odd, why can't you? Start a transaction, insert a new record with the correct key, update the related records to point to the new record, then delete the old record, done.
Want some crucial information about a related record but only have the surrogate to it? I guess you have to join it every time in order to get the columns the user actually wants to see.
A foreign key that uses a natural key often often prevents the join entirely, because it tells the user what they wanted to know.
</p>
<p>
I find the problem with natural keys usually comes from another source entirely.
Developers write code and don't tend to prefer using SQL.
They typically interact with databases through ORM libraries.
ORMs are complicated and rely on conventions to uniformly deal with data.
It's not uncommon for ORMs to dictate the structure of tables to some degree, or what datatypes to prefer.
It's usually easier in an ORM to have a single datatype for keys (BIGINT?) and use it uniformly across all the tables.
</p>
</div>
<div class="comment-date">2024-06-05 12:42 UTC</div>
</div>
<div class="comment" id="2960b65bbaec4db8ade70f551e3f5062">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#2960b65bbaec4db8ade70f551e3f5062">#</a></div>
<div class="comment-content">
<p>
James, Nicholas, thank you for writing. I realize that there are some unstated assumptions and implied concerns that I should have made more explicit. I certainly have no problem with adding constraints and other rules to model data. For the Danish CPR number, for example, while I wouldn't make it a primary key (for the reasons outlined in the article), I'd definitely put a <code>UNIQUE</code> constraint on it.
</p>
<p>
Another unspoken context that I had in mind is that systems often exist in a wider context where ACID guarantees fall apart. I suppose it's true that if you look at a database in isolation, you may be able to update a foreign key with the help of some cascading changes rippling through the database, but if you've ever shared the old key outside of the database, you now have orphaned data.
</p>
<p>
A simple example could be sending out an email with a link that embeds the old key. If you change the key after sending out the email, but before the user clicks, the link no longer works.
</p>
<p>
That's just a simple and easy-to-explain example. The more integration (particularly system-to-system integration) you have, the worse this kind of problem becomes. I briefly discussed the CPR number example with my doctor wife, and she immediately confirmed that this is a real problem in the Danish health sector, where many independent software systems need to exchange patient data.
</p>
<p>
You can probably work around such problems in various ways, but if you had avoided using natural keys, you wouldn't have had to change the key in the first place.
</p>
</div>
<div class="comment-date">2024-06-06 6:56 UTC</div>
</div>
<div class="comment" id="f7d04f04aade40d1b668c94a56c7c189">
<div class="comment-author"><a href="https://github.com/bantling">Greg Hall</a> <a href="#f7d04f04aade40d1b668c94a56c7c189">#</a></div>
<div class="comment-content">
<p>
I think it is best to have two separate generated keys for each row:
</p>
<ul>
<li>A key used only for relationships between tables. I like to call this relid, and make it serialised, so it
is just an increasing number. This key is the primary key and should never be exposed outside the database.
</li>
<li>A key used only outside the database as a unique reference to which row to update. I like to call this id,
and make it a uuid, since it is well accepted to uniquely identify rows by a uuid, and to expose them to
the outside world - many public APIs do this. Theoretically, the same uuid should never be generated twice,
so this key doesn't necessarily have to be declared as unique.
</li>
</ul>
<p>
The relid can be used in simple foreign keys, and in bridging/join tables - tables that contain primary keys of
multiple tables. Generally speaking, the relid is far more readable than a uuid - it is easier to hold in your head
a simple integer, which usually is not that large, than a 36 character sequence that looks similar to other 36
character sequences. UUIDs generally look like a jumble.
</p>
<p>
A relid can be 32-bits for tables you're confident will never need more than 2.1 billion rows, which really is
99.99% of all tables ever created by 99.99% of applications. If this turns out to be wrong, it is possible to
upgrade the relids to 64-bit for a given table. It's a bit of a pain, especially if there are lots of references to
it, but it can be done.
</p>
<p>
The relid doesn't always have to be a serialised value, and you don't always have to call the column relid. Since
the primary key is never exposed publicly, it doesn't matter if different column types or names are used for different
use cases. For example, code tables might use one of the codes as the primary key.
</p>
<p>
I don't think it makes sense to be religious on key usage; just like everything else, there are valid reasons for
periodically varying how they work. I'm sure somebody has a valid case where a single key is better than two.
I just think it generally makes sense to have a pair of internal and external keys for most cases.
</p>
</div>
<div class="comment-date">2024-06-07 3:31 UTC</div>
</div>
<div class="comment" id="7a1067a9e6fb4b6293777a1408518429">
<div class="comment-author"><a href="http://snape.me">James Snape</a> <a href="#7a1067a9e6fb4b6293777a1408518429">#</a></div>
<div class="comment-content">
<p>
The thing with databases keys is you really need to be precise on what you mean by a key. Any combination of attributes is a candidate key. There are also logical and physical representations of keys. For example, a SQL Server primary key is a physical record locator but logically a unique key constraint. Yes, these behave poorly when you use natural keys as the primary key for all the reasons you mention. They are a complete implementation detail. Users should never see these attributes though and you shouldn't share the values outside of your implementation. Sharing integer surrogate keys in urls is a classic issue allowing enumeration attacks on your data if not secured properly.
</p>
<p>
Foreign keys are another logical and physical dual use concept. In SQL Server a physical foreign key constrain must reference the primary key from a parent table but logically that doesn't need to happen for relational theory to work.
</p>
<p>
Alternate keys are combinations of attributes that identify a record (or many records); these are often the natural keys you use in your user interface and where clauses etc. Alternate keys are also how systems communicate. Take your CPR number example, you cannot exchange patient data unless both systems agree on a common key. This can't be an internally generated surrogate value.
</p>
<p>
Natural keys also serve another purpose in parent-child relationships. By sharing natural key attributes with a parent you can ensure a child is not accidentally moved to a new parent plus you can query a child table without needing to join to the parent table.
</p>
<p>There isn't a one-size-fits all when it comes to databases and keys. <a href="https://en.wikipedia.org/wiki/Joe_Celko">Joe Celko</a> has written extensively on the subject so maybe its better to read the following than my small commentary:
<ul>
<li><a href="https://www.informationweek.com/it-sectors/celko-on-sql-natural-artificial-and-surrogate-keys-explained">Celko on SQL: Natural, Artificial and Surrogate Keys Explained</a></li>
<li><a href="https://www.informationweek.com/data-management/celko-on-sql-identifiers-and-the-properties-of-relational-keys">Celko On SQL: Identifiers and the Properties of Relational Keys</a></li>
</ul>
</p>
</div>
<div class="comment-date">2024-06-07 09:57 UTC</div>
</div>
<div class="comment" id="3ef814a896f34b5485aeeea739766fa9">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#3ef814a896f34b5485aeeea739766fa9">#</a></div>
<div class="comment-content">
<p>
Greg, thank you for writing. I agree with everything you wrote, and I've been using that kind of design for... wow, at least a decade, it looks! <a href="/2014/08/11/cqs-versus-server-generated-ids">for a slightly different reason</a>. This kind of design seems, even if motivated by a different concern, congruent with what you describe.
</p>
<p>
Like you also imply, only a sith speaks in absolutes. The irony of the article is that I originally intended it to be more open-ended, in the sense that I was curious if there were genuinely good reasons to use natural keys. As I wrote, the article turned out more unconditional than I originally had in mind.
</p>
<p>
I am, in reality, quite ready to consider arguments to the contrary. But really, I was curious: <em>Is it ever a good idea to use natural keys as primary keys?</em> It sounds like a rhetorical question, but I don't mind if someone furnishes a counter-example.
</p>
<p>
As <a href="#92ee5d39a4d34539899ddaf13d1336b7">Nicholas Peterson intimated</a>, it's probably not a real problem if those keys never 'leave' the database. What I failed to make explicit in this article is that the problems I've consistently run into occur when a system has shared keys with external systems or users.
</p>
</div>
<div class="comment-date">2024-06-14 11:26 UTC</div>
</div>
<div class="comment" id="7f7d8205e5174c61b1b5e3d19482c0ab">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#7f7d8205e5174c61b1b5e3d19482c0ab">#</a></div>
<div class="comment-content">
<p>
James, thank you for writing. I think we're discussing issues at different levels of abstraction. This just underscores how difficult technical writing is. I should have made my context and assumptions more explicit. The error is mine.
</p>
<p>
Everything you write sounds correct to me. I <em>am</em> aware of both relational calculus and relational algebra, so I'm familiar with the claims you make, and I don't dispute them.
</p>
<p>
My focus is rather on systems architecture. Even an 'internal' system may actually be composed from multiple independent systems, and my concern is that using natural keys to exchange data between such systems ultimately turns out to make things more difficult than they could have been. The only statement of yours with which I think I disagree is that you can't exchange data between systems unless you use natural keys. You definitely can, although you need to appoint one of the systems to be a 'master key issuer'.
</p>
<p>
In practice, <a href="#f7d04f04aade40d1b668c94a56c7c189">like Greg Hall</a>, I'd prefer using GUIDs for that purpose, rather than sequential numbers. That also addresses the concern about enumeration attacks. (Somewhat tangentially, I also <a href="/2020/10/26/fit-urls">recommend signing URLs with a private key</a> in order to prevent reverse-engineering, or 'URL-hacking'.)
</p>
</div>
<div class="comment-date">2024-06-14 11:55 UTC</div>
</div>
<div class="comment" id="5b3ac2db5a7a4b8697528e757652e6af">
<div class="comment-author"><a href="http://snape.me">James Snape</a> <a href="#5b3ac2db5a7a4b8697528e757652e6af">#</a></div>
<div class="comment-content">
<p>I think we are basically agreeing here because I would never use natural keys nor externally visible synthetic keys for <em>physical</em> primary keys. (I think this statement is even more restrictive than the article's main premise). Well, with a rule exception for configurable enum type tables because the overhead of joining to resolve a single column value is inefficient. I would however always use a natural key for a <em>logical</em> primary key.</p>
<p>The only reason why I'm slightly pedantic about this is due the the number of clients why have used surrogate keys in a logical model and then gone on to create databases where the concept of entity identity doesn't exist. This creates many of the issues <a href="https://processdecision.com">Nicholas Peterson</a> mentioned above: duplicates, historical change tracking, etc. Frankly, it doesn't help that lots of code examples for ORMs just start with an entity that has an ID attribute.</p>
<p>One final comment on sharing data based on a golden master synthetic key. The moment you do I would argue that you have now committed to maintaining that key through all types of data mergers and acquisitions. It must never collide, and always point to exactly the same record and only that record. Since users can use it to refer to an entity and it makes up part of your external API, it now meets the definition of a natural key. Whether you agree or not on my stretching the definition a little, you still should not use this attribute as the physical primary key (record locator) because we should not expose implementation details in our APIs. The first Celko article I linked to explains some of the difficulties for externally visible synthetic keys.</p>
</div>
<div class="comment-date">2024-06-14 13:45 UTC</div>
</div>
<div class="comment" id="fee47871b1494293b039b67d21187e6b">
<div class="comment-author">Julius H <a href="#fee47871b1494293b039b67d21187e6b">#</a></div>
<div class="comment-content">
<p>I'd like to comment with an example where using a synthetic key came back to bite me. My system had posts and users with synthetic IDs. Now I wanted to track an unread state across them. Naively, I designed just another entity:</p>
<pre>
public int ID { get; set; }
public int PostID { get; set; }
public int UserID { get; set; }
</pre>
<p>And it worked flawlessly for years. One day, however, a user complained that he always got an exception "Sequence contains more than one element". Of course I used SingleOrDefault() in application code because I expected 0 or 1 record per user and post.
The quick solution was deleting the spurious table row. As a permanant solution I removed the ID field (and column) so the unread state had its natural key as primary key (both columns). So if it happens again in the future, the app will error on insertin rather than querying.</p>
<p>Since my application is in control of the IDs and it's just a very simple join table I think it was the best solution. If the future requirements hold different kinds of unread state, I can always add the key again.</p>
</div>
<div class="comment-date">2024-07-22 14:40 UTC</div>
</div>
<div class="comment" id="c573d77b80904d64b697418a7d4440cd">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#c573d77b80904d64b697418a7d4440cd">#</a></div>
<div class="comment-content">
<p>
Julius, thank you for writing. I see what you mean, and would also tend to model this as just a table with two foreign keys. From the perspective of <a href="https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model">entity-relationship modelling</a>, such a table isn't even an entity, but rather a relationship. For that reason, it doesn't need its own key; not because the combination is 'natural', but rather because it's not really an independent 'thing'.
</p>
</div>
<div class="comment-date">2024-07-29 14:39 UTC</div>
</div>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Continuous delivery without a CI serverhttps://blog.ploeh.dk/2024/05/27/continuous-delivery-without-a-ci-server2024-05-27T13:34:00+00:00Mark Seemann
<div id="post">
<p>
<em>An illustrative example.</em>
</p>
<p>
More than a decade ago, I worked on a small project. It was a small <a href="https://en.wikipedia.org/wiki/Single-page_application">single-page application</a> (SPA) with a <a href="https://en.wikipedia.org/wiki/REST">REST</a> API backend, deployed to <a href="https://azure.microsoft.com/">Azure</a>. As far as I recall, the REST API used <a href="https://en.wikipedia.org/wiki/Object_storage">blob storage</a>, so all in all it wasn't a complex system.
</p>
<p>
We were two developers, and although we wanted to do <a href="https://en.wikipedia.org/wiki/Continuous_delivery">continuous delivery</a> (CD), we didn't have much development infrastructure. This was a little startup, and back then, there weren't a lot of free build services available. We were using <a href="https://github.com/">GitHub</a>, but it was before it had any free services to compile your code and run tests.
</p>
<p>
Given those constraints, we figured out a simple way to do CD, even though we didn't have a <a href="https://en.wikipedia.org/wiki/Continuous_integration">continuous integration</a> (CI) server.
</p>
<p>
I'll tell you how we did this.
</p>
<h3 id="d4bf05ee06c64650a15e5dae86a6efbd">
Shining an extraordinary light on the mundane <a href="#d4bf05ee06c64650a15e5dae86a6efbd">#</a>
</h3>
<p>
The reason I'm relating this little story isn't to convince you that you, too, should do it that way. Rather, it's a didactic device. By doing something extreme, we can sometimes learn about the ordinary.
</p>
<blockquote>
<p>
You can only be pragmatic if you know how to be dogmatic.
</p>
<footer><cite><a href="/2018/11/12/what-to-test-and-not-to-test">What to test and not to test</a></cite>, me</footer>
</blockquote>
<p>
From what I hear and read, it seems that there's a lot of organizations that believe that they're doing CI (or perhaps even CD) because they have a CI server. What the following tale will hopefully highlight is that, while build servers are useful, they aren't a requirement for CI or CD.
</p>
<h3 id="08dc5521141f4907bc44d43852716196">
Distributed CD <a href="#08dc5521141f4907bc44d43852716196">#</a>
</h3>
<p>
Dramatis personae: My colleague and me. Scene: One small SPA project with a REST API and blob storage, to be deployed to Azure. Code base in GitHub. Two laptops. Remote work.
</p>
<p>
One of us (let's say me) would start on implementing a feature, or fixing a bug. I'd use test-driven development (TDD) to get feedback on API ideas, as well as to accumulate a suite of regression tests. After a few hours of effective work, I'd send a pull request to my colleague.
</p>
<p>
Since we were only two people on the team, the responsibility was clear. It was the other person's job to review the pull request. It was also clear that the longer the reviewer dawdled, the less efficient the process would be. For that reason, we'd typically have <a href="/2021/06/21/agile-pull-requests">agile pull requests</a> with a good turnaround time.
</p>
<p>
While we were taking advantage of GitHub as a central coordination hub for pull requests, <a href="https://git-scm.com/">Git</a> itself is famously distributed. Thus, we wondered whether it'd be possible to make the CD process distributed as well.
</p>
<p>
Yes, apart from GitHub, what we did was already distributed.
</p>
<h3 id="77a1cae8e41349f8b8092aec8fa512d3">
A little more automation <a href="#77a1cae8e41349f8b8092aec8fa512d3">#</a>
</h3>
<p>
Since we were both doing TDD, we already had automated tests. Due to the simple setup of the system, we'd already automated more than 80% of our process. It wasn't much of a stretch to automate whatever else needed automation. Such as deployment.
</p>
<p>
We agreed on a few simple rules:
</p>
<ul>
<li>Every part of our process should be automated.</li>
<li>Reviewing a pull request included running all tests.</li>
</ul>
<p>
When people review pull requests, they often just go to GitHub and look around before issuing an LGTM.
</p>
<p>
But, you <em>do</em> realize that this is Git, right? You can pull down the proposed changes and <em>run them</em>.
</p>
<p>
What if you're already in the middle of something, working on the same code base? Stash your changes and pull down the code.
</p>
<p>
The consequence of this process was that every time a pull request was accepted, we already knew that it passed all automated tests on two physical machines. We actually didn't need a server to run the tests a third time.
</p>
<p>
<img src="/content/binary/distributed-cd.png" alt="Two laptops, a box indicating GitHub, and another box indicating a production system.">
</p>
<p>
After a merge, the final part of the development process mandated that the original author should deploy to production. We had <a href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)">Bash</a> script that did that.
</p>
<h3 id="cabd161b2cb34fe79caf3172bb339948">
Simplicity <a href="#cabd161b2cb34fe79caf3172bb339948">#</a>
</h3>
<p>
This process came with some built-in advantages. First of all, it was <em>simple</em>. There wasn't a lot of moving parts, so there weren't many steps that could break.
</p>
<p>
Have you ever had the pleasure of troubleshooting a build? The code works on your machine, but not on the build server.
</p>
<p>
It sometimes turns out that there's a configuration mismatch with the compiler or test tools. Thus, the problem with the build server doesn't mean that you prevented a dangerous defect from being deployed to production. No, the code just didn't compile on the build server, but would actually have run fine on the production system.
</p>
<p>
It's much easier troubleshooting issues on your own machine than on some remote server.
</p>
<p>
I've also seen build servers that were set up to run tests, but along the way, something had failed and the tests didn't run. And no-one was looking at logs or warning emails from the build system because that system would already be sending hundreds of warnings a day.
</p>
<p>
By agreeing to manually(!) run the automated tests as part of the review process, we were sure that they were exercised.
</p>
<p>
Finally, by keeping the process simple, we could focus on what mattered: Delivering value to our customer. We didn't have to waste time learning how a proprietary build system worked.
</p>
<h3 id="2a427dee73f44fb4ab6753cf5246cc52">
Does it scale? <a href="#2a427dee73f44fb4ab6753cf5246cc52">#</a>
</h3>
<p>
I know what you're going to say: This may have worked because the overall requirements were so simple. This will never work in a 'real' development organization, with a 'real' code base.
</p>
<p>
I understand. I never claimed that it would.
</p>
<p>
The point of this story is to highlight what CI and CD is. It's a way of working where you <em>continuously</em> integrate your code with everyone else's code, and where you <em>continuously</em> deploy changes to production.
</p>
<p>
In reality, having a dedicated build system for that can be useful. These days, such systems tend to be services that integrate with GitHub or other sites, rather than an actual server that you have to care for. Even so, having such a system doesn't mean that your organization makes use of CI or CD.
</p>
<p>
(Oh, and for the mathematically inclined: In this context <em>continuous</em> doesn't mean actually continuous. It just means <em>arbitrarily often</em>.)
</p>
<h3 id="097bd9130bb144c79ee3e75b0652a99f">
Conclusion <a href="#097bd9130bb144c79ee3e75b0652a99f">#</a>
</h3>
<p>
CI and CD are processes that describe how we work with code, and how we work together.
</p>
<p>
Continuous integration means that you often integrate your code with everyone else's code. How often? More than once a day.
</p>
<p>
Continuous deployment means that you often deploy code changes to production. How often? Every time new code is integrated.
</p>
<p>
A build system can be convenient to help along such processes, but it's strictly speaking not required.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Fundamentalshttps://blog.ploeh.dk/2024/05/20/fundamentals2024-05-20T07:04:00+00:00Mark Seemann
<div id="post">
<p>
<em>How to stay current with technology progress.</em>
</p>
<p>
A long time ago, I landed my dream job. My new employer was a consulting company, and my role was to be the resident <a href="https://en.wikipedia.org/wiki/Microsoft_Azure">Azure</a> expert. Cloud computing was still in its infancy, and there was a good chance that I might be able to establish myself as a leading regional authority on the topic.
</p>
<p>
As part of the role, I was supposed to write articles and give presentations showing how to solve various problems with Azure. I dug in with fervour, writing sample code bases and even <a href="http://msdn.microsoft.com/en-us/magazine/gg983487.aspx">an MSDN Magazine article</a>. To my surprise, after half a year I realized that I was bored.
</p>
<p>
At that time I'd already spent more than a decade learning new technology, and I knew that I was good at it. For instance, I worked five years for Microsoft Consulting Services, and a dirty little secret of that kind of role is that, although you're sold as an expert in some new technology, you're often only a few weeks ahead of your customer. For example, I was once engaged as a <a href="https://en.wikipedia.org/wiki/Windows_Workflow_Foundation">Windows Workflow Foundation</a> expert at a time when it was still in beta. No-one had years of experience with that technology, but I was still expected to know much more about it than my customer.
</p>
<p>
I had lots of engagements like that, and they usually went well. I've always been good at cramming, and as a consultant you're also unencumbered by all the daily responsibilities and politics that often occupy the time and energy of regular employees. The point being that while I'm decent at learning new stuff, the role of being a consultant also facilitates that sort of activity.
</p>
<p>
After more then a decade of learning new frameworks, new software libraries, new programming languages, new tools, new online services, it turned out that I was ready for something else. After spending a few months learning Azure, I realized that I'd lost interest in that kind of learning. When investigating a new Azure SDK, I'd quickly come to the conclusion that, <em>oh, this is just another object-oriented library</em>. There are these objects, and you call this method to do that, etc. That's not to say that learning a specific technology is a trivial undertaking. The worse the design, the more difficult it is to learn.
</p>
<p>
Still, after years of learning new technologies, I'd started recognizing certain patterns. Perhaps, I thought, well-designed technologies are based on some fundamental ideas that may be worth learning instead.
</p>
<h3 id="ac37913a2b8248e6b51d4506c2da0481">
Staying current <a href="#ac37913a2b8248e6b51d4506c2da0481">#</a>
</h3>
<p>
A common lament among software developers is that the pace of technology is so overwhelming that they can't keep up. This is true. You can't keep up.
</p>
<p>
There will always be something that you don't know. In fact, most things you don't know. This isn't a condition isolated only to technology. The sum total of all human knowledge is so vast that you can't know it all. What you will learn, even after a lifetime of diligent study, will be a nanoscopic fraction of all human knowledge - even of everything related to software development. You can't stay current. Get used to it.
</p>
<p>
A more appropriate question is: <em>How do I keep my skill set relevant?</em>
</p>
<p>
Assuming that you wish to stay employable in some capacity, it's natural to be concerned with how your mad <a href="https://en.wikipedia.org/wiki/Adobe_Flash">Flash</a> skillz will land you the next gig.
</p>
<p>
Trying to keep abreast of all new technologies in your field is likely to lead to burnout. Rather, put yourself in a position so that you can quickly learn necessary skills, just in time.
</p>
<h3 id="c529c0131b284fe1bca42bec0663fc8e">
Study fundamentals, rather than specifics <a href="#c529c0131b284fe1bca42bec0663fc8e">#</a>
</h3>
<p>
Those many years ago, I realized that it'd be a better investment of my time to study fundamentals. Often, once you have some foundational knowledge, you can apply it in many circumstances. Your general knowledge will enable you to get quickly up to speed with specific technologies.
</p>
<p>
Success isn't guaranteed, but knowing fundamentals increases your chances.
</p>
<p>
This may still seem too abstract. Which fundamentals should you learn?
</p>
<p>
In the remainder of this article, I'll give you some examples. The following collection of general programmer knowledge spans software engineering, computer science, broad ideas, but also specific tools. I only intend this set of examples to serve as inspiration. The list isn't complete, nor does it constitute a minimum of what you should learn.
</p>
<p>
If you have other interests, you may put together your own research programme. What follows here are just some examples of fundamentals that I've found useful during my career.
</p>
<p>
A criterion, however, for constituting foundational knowledge is that you should be able to apply that knowledge in a wide variety of contexts. The fundamental should not be tied to a particular programming language, platform, or operating system.
</p>
<h3 id="4f474189809f4d53b447b4005cef1bfd">
Design patterns <a href="#4f474189809f4d53b447b4005cef1bfd">#</a>
</h3>
<p>
Perhaps the first foundational notion that I personally encountered was that of <em>design patterns</em>. As the Gang of Four (GoF) wrote in <a href="https://en.wikipedia.org/wiki/Design_Patterns">the book</a>, a design pattern is an abstract description of a solution that has been observed 'in the wild', more than once, independently evolved.
</p>
<p>
Please pay attention to the causality. A design pattern isn't prescriptive, but descriptive. It's an observation that a particular code organisation tends to solve a particular problem.
</p>
<p>
There are lots of misconceptions related to design patterns. One of them is that the 'library of patterns' is finite, and more or less constrained to the patterns included in the original book.
</p>
<p>
There are, however, many more patterns. To illustrate how much wider this area is, here's a list of some patterns books in my personal library:
</p>
<ul>
<li><a href="/ref/dp">Design Patterns</a></li>
<li><a href="/ref/plopd3">Pattern Languages of Program Design 3</a></li>
<li><a href="/ref/peaa">Patterns of Enterprise Application Architecture</a></li>
<li><a href="/ref/eip">Enterprise Integration Patterns</a></li>
<li><a href="/ref/xunit-patterns">xUnit Test Patterns</a></li>
<li><a href="/ref/service-design-patterns">Service Design Patterns</a></li>
<li><a href="/ref/implementation-patterns">Implementation Patterns</a></li>
<li><a href="/ref/rest-cookbook">RESTful Web Services Cookbook</a></li>
<li><a href="/ref/antipatterns">AntiPatterns</a></li>
</ul>
<p>
In addition to these, there are many more books in my library that are patterns-adjacent, including <a href="/dippp">one of my own</a>. The point is that software design patterns is a vast topic, and it pays to know at least the most important ones.
</p>
<p>
A design pattern fits the criterion that you can apply the knowledge independently of technology. The original GoF book has examples in <a href="https://en.wikipedia.org/wiki/C%2B%2B">C++</a> and <a href="https://en.wikipedia.org/wiki/Smalltalk">Smalltalk</a>, but I've found that they apply well to C#. Other people employ them in their <a href="https://www.java.com/">Java</a> code.
</p>
<p>
Knowing design patterns not only helps you design solutions. That knowledge also enables you to recognize patterns in existing libraries and frameworks. It's this fundamental knowledge that makes it easier to learn new technologies.
</p>
<p>
Often (although not always) successful software libraries and frameworks tend to follow known patterns, so if you're aware of these patterns, it becomes easier to learn such technologies. Again, be aware of the causality involved. I'm not claiming that successful libraries are explicitly designed according to published design patterns. Rather, some libraries become successful because they offer good solutions to certain problems. It's not surprising if such a good solution falls into a pattern that other people have already observed and recorded. It's like <a href="https://en.wikipedia.org/wiki/Parallel_evolution">parallel evolution</a>.
</p>
<p>
This was my experience when I started to learn the details of Azure. Many of those SDKs and APIs manifested various design patterns, and once I'd recognized a pattern it became much easier to learn the rest.
</p>
<p>
The idea of design patterns, particularly object-oriented design patterns, have its detractors, too. Let's visit that as the next set of fundamental ideas.
</p>
<h3 id="c44e7624ea3e4cef9485522146d17a6d">
Functional programming abstractions <a href="#c44e7624ea3e4cef9485522146d17a6d">#</a>
</h3>
<p>
As I'm writing this, yet another Twitter thread pokes fun at object-oriented design (OOD) patterns as being nothing but a published collection of workarounds for the shortcomings of object orientation. The people who most zealously pursue that agenda tends to be functional programmers.
</p>
<p>
Well, I certainly like functional programming (FP) better than OOD too, but rather than poking fun at OOD, I'm more interested in <a href="/2018/03/05/some-design-patterns-as-universal-abstractions">how design patterns relate to universal abstractions</a>. I also believe that FP has shortcomings of its own, but I'll have more to say about that in a future article.
</p>
<p>
Should you learn about <a href="/2017/10/06/monoids">monoids</a>, <a href="/2018/03/22/functors">functors</a>, <a href="/2022/03/28/monads">monads</a>, <a href="/2019/04/29/catamorphisms">catamorphisms</a>, and so on?
</p>
<p>
Yes you should, because these ideas also fit the criterion that the knowledge is technology-independent. I've used my knowledge of these topics in <a href="https://www.haskell.org/">Haskell</a> (hardly surprising) and <a href="https://fsharp.org/">F#</a>, but also in C# and <a href="https://www.python.org/">Python</a>. The various <a href="https://en.wikipedia.org/wiki/Language_Integrated_Query">LINQ</a> methods are really just well-known APIs associated with, you guessed it, functors, monads, monoids, and catamorphisms.
</p>
<p>
Once you've learned these fundamental ideas, it becomes easier to learn new technologies. This has happened to me multiple times, for example in contexts as diverse as property-based testing and asynchronous message-passing architectures. Once I realize that an API gives rise to a monad, say, I know that certain functions must be available. I also know how I should best compose larger code blocks from smaller ones.
</p>
<p>
Must you know all of these concepts before learning, say, F#? No, not at all. Rather, a language like F# is a great vehicle for learning such fundamentals. There's a first time for learning anything, and you need to start somewhere. Rather, the point is that once you know these concepts, it becomes easier to learn the next thing.
</p>
<p>
If, for example, you already know what a monad is when learning F#, picking up the idea behind <a href="https://learn.microsoft.com/dotnet/fsharp/language-reference/computation-expressions">computation expressions</a> is easy once you realize that it's just a compiler-specific way to enable syntactic sugaring of monadic expressions. You can learn how computation expressions work without that knowledge, too; it's just harder.
</p>
<p>
This is a recurring theme with many of these examples. You can learn a particular technology without knowing the fundamentals, but you'll have to put in more time to do that.
</p>
<p>
On to the next example.
</p>
<h3 id="02c8fb3f6fe74fb9bffda719122c60a9">
SQL <a href="#02c8fb3f6fe74fb9bffda719122c60a9">#</a>
</h3>
<p>
Which <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">object-relational mapper</a> (ORM) should you learn? <a href="https://hibernate.org/orm/">Hibernate</a>? <a href="https://learn.microsoft.com/ef/">Entity Framework</a>?
</p>
<p>
How about learning <a href="https://en.wikipedia.org/wiki/SQL">SQL</a>? I learned SQL in 1999, I believe, and it's served me well ever since. I <a href="/2023/09/18/do-orms-reduce-the-need-for-mapping">consider raw SQL to be more productive than using an ORM</a>. Once more, SQL is largely technology-independent. While each database typically has its own SQL dialect, the fundamentals are the same. I'm most well-versed in the <a href="https://en.wikipedia.org/wiki/Microsoft_SQL_Server">SQL Server</a> dialect, but I've also used my SQL knowledge to interact with <a href="https://www.oracle.com/database/">Oracle</a> and <a href="https://www.postgresql.org/">PostgreSQL</a>. Once you know one SQL dialect, you can quickly solve data problems in one of the other dialects.
</p>
<p>
It doesn't matter much whether you're interacting with a database from .NET, Haskell, Python, <a href="https://www.ruby-lang.org/">Ruby</a>, or another language. SQL is not only universal, the core of the language is stable. What I learned in 1999 is still useful today. Can you say the same about your current ORM?
</p>
<p>
Most programmers prefer learning the newest, most cutting-edge technology, but that's a risky gamble. Once upon a time <a href="https://en.wikipedia.org/wiki/Microsoft_Silverlight">Silverlight</a> was a cutting-edge technology, and more than one of my contemporaries went all-in on it.
</p>
<p>
On the contrary, most programmers find old stuff boring. It turns out, though, that it may be worthwhile learning some old technologies like SQL. Be aware of the <a href="https://en.wikipedia.org/wiki/Lindy_effect">Lindy effect</a>. If it's been around for a long time, it's likely to still be around for a long time. This is true for the next example as well.
</p>
<h3 id="e4a7c033c0964420a0abbf83a0bbb773">
HTTP <a href="#e4a7c033c0964420a0abbf83a0bbb773">#</a>
</h3>
<p>
The <a href="https://en.wikipedia.org/wiki/HTTP">HTTP protocol</a> has been around since 1991. It's an effectively text-based protocol, and you can easily engage with a web server on a near-protocol level. This is true for other older protocols as well.
</p>
<p>
In my first IT job in the late 1990s, one of my tasks was to set up and maintain <a href="https://en.wikipedia.org/wiki/Microsoft_Exchange_Server">Exchange Servers</a>. It was also my responsibility to make sure that email could flow not only within the organization, but that we could exchange email with the rest of the internet. In order to test my mail servers, I would often just <a href="https://en.wikipedia.org/wiki/Telnet">telnet</a> into them on port 25 and type in the correct, <a href="https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol">text-based instructions to send a test email</a>.
</p>
<p>
Granted, it's not that easy to telnet into a modern web server on port 80, but a ubiquitous tool like <a href="https://curl.se/">curl</a> accomplishes the same goal. I recently wrote how <a href="/2024/05/13/gratification">knowing curl is better</a> than knowing <a href="https://www.postman.com/">Postman</a>. While this wasn't meant as an attack on Postman specifically, neither was it meant as a facile claim that curl is the only tool useful for ad-hoc interaction with HTTP-based APIs. Sometimes you only realize an underlying truth when you write about a thing and then <a href="/2024/05/13/gratification#9efea1cadb8c4e388bfba1a2064dd59a">other people find fault with your argument</a>. The underlying truth, I think, is that it pays to understand HTTP and being able to engage with an HTTP-based web service at that level of abstraction.
</p>
<p>
Preferably in an automatable way.
</p>
<h3 id="e3a250b707b243dabc6609134e864aee">
Shells and scripting <a href="#e3a250b707b243dabc6609134e864aee">#</a>
</h3>
<p>
The reason I favour curl over other tools to interact with HTTP is that I already spend quite a bit of time at the command line. I typically have a little handful of terminal windows open on my laptop. If I need to test an HTTP server, curl is already available.
</p>
<p>
Many years ago, an employer introduced me to <a href="https://git-scm.com/">Git</a>. Back then, there were no good graphical tools to interact with Git, so I had to learn to use it from the command line. I'm eternally grateful that it turned out that way. I still use Git from the command line.
</p>
<p>
When you install Git, by default you also install Git Bash. Since I was already using that shell to interact with Git, it began to dawn on me that it's a full-fledged shell, and that I could do all sorts of other things with it. It also struck me that learning <a href="https://www.gnu.org/software/bash/">Bash</a> would be a better investment of my time than learning <a href="https://learn.microsoft.com/powershell/">PowerShell</a>. At the time, there was no indication that PowerShell would ever be relevant outside of Windows, while Bash was already available on most systems. Even today, knowing Bash strikes me as more useful than knowing PowerShell.
</p>
<p>
It's not that I do much Bash-scripting, but I could. Since I'm a programmer, if I need to automate something, I naturally reach for something more robust than shell scripting. Still, it gives me confidence to know that, since I already know Bash, Git, curl, etc., I <em>could</em> automate some tasks if I needed to.
</p>
<p>
Many a reader will probably complain that the Git CLI has horrible <a href="/2024/05/13/gratification">developer experience</a>, but I will, again, postulate that it's not that bad. It helps if you understand some fundamentals.
</p>
<h3 id="a511cfd8d9bf4bbda433dbf70184284a">
Algorithms and data structures <a href="#a511cfd8d9bf4bbda433dbf70184284a">#</a>
</h3>
<p>
Git really isn't that difficult to understand once you realize that a Git repository is just a <a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph">directed acyclic graph</a> (DAG), and that branches are just labels that point to nodes in the graph. There are basic data structures that it's just useful to know. DAGs, <a href="https://en.wikipedia.org/wiki/Tree_(graph_theory)">trees</a>, <a href="https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)">graphs</a> in general, <a href="https://en.wikipedia.org/wiki/Adjacency_list">adjacency lists</a> or <a href="https://en.wikipedia.org/wiki/Adjacency_matrix">adjacency matrices</a>.
</p>
<p>
Knowing that such data structures exist is, however, not that useful if you don't know what you can <em>do</em> with them. If you have a graph, you can find a <a href="https://en.wikipedia.org/wiki/Minimum_spanning_tree">minimum spanning tree</a> or a <a href="https://en.wikipedia.org/wiki/Shortest-path_tree">shortest-path tree</a>, which sometimes turn out to be useful. Adjacency lists or matrices give you ways to represent graphs in code, which is why they are useful.
</p>
<p>
Contrary to certain infamous interview practices, you don't need to know these algorithms by heart. It's usually enough to know that they exist. I can't remember <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra's algorithm</a> off the top of my head, but if I encounter a problem where I need to find the shortest path, I can look it up.
</p>
<p>
Or, if presented with the problem of constructing current state from an Event Store, you may realize that it's just a left <a href="https://en.wikipedia.org/wiki/Fold_(higher-order_function)">fold</a> over a <a href="https://en.wikipedia.org/wiki/Linked_list">linked list</a>. (This isn't my own realization; I first heard it from <a href="https://gotocon.com/cph-2011/presentation/Behavior!">Greg Young in 2011</a>.)
</p>
<p>
Now we're back at one of the first examples, that of FP knowledge. A <a href="/2019/05/27/list-catamorphism">list fold is its catamorphism</a>. Again, these things are much easier to learn if you already know some fundamentals.
</p>
<h3 id="f109425f27014cd5bd395a74e9575355">
What to learn <a href="#f109425f27014cd5bd395a74e9575355">#</a>
</h3>
<p>
These examples may seems overwhelming. Do you really need to know all of that before things become easier?
</p>
<p>
No, that's not the point. I didn't start out knowing all these things, and some of them, I'm still not very good at. The point is rather that if you're wondering how to invest your limited time so that you can remain up to date, consider pursuing general-purpose knowledge rather than learning a specific technology.
</p>
<p>
Of course, if your employer asks you to use a particular library or programming language, you need to study <em>that</em>, if you're not already good at it. If, on the other hand, you decide to better yourself, you can choose what to learn next.
</p>
<p>
Ultimately, if your're learning for your own sake, the most important criterion may be: Choose something that interests you. If no-one forces you to study, it's too easy to give up if you lose interest.
</p>
<p>
If, however, you have the choice between learning <a href="https://mjvl.github.io/Noun.js/">Noun.js</a> or design patterns, may I suggest the latter?
</p>
<h3 id="94c3f380b556403d82dd9f3cd0c1d1e9">
For life <a href="#94c3f380b556403d82dd9f3cd0c1d1e9">#</a>
</h3>
<p>
When are you done, you ask?
</p>
<p>
Never. There's more stuff than you can learn in a lifetime. I've met a lot of programmers who finally give up on the grind to keep up, and instead become managers.
</p>
<p>
As if there's nothing to learn when you're a manager. I'm fortunate that, before <a href="/2011/11/08/Independency">I went solo</a>, I mainly had good managers. I'm under no illusion that they automatically became good managers. All I've heard said about management is that there's a lot to learn in that field, too. Really, it'd be surprising if that wasn't the case.
</p>
<p>
I can understand, however, how just keep learning the next library, the next framework, the next tool becomes tiring. As I've already outlined, I hit that wall more than a decade ago.
</p>
<p>
On the other hand, there are so many wonderful fundamentals that you can learn. You can do self-study, or you can enrol in a more formal programme if you have the opportunity. I'm currently following a course on compiler design. It's not that I expect to pivot to writing compilers for the rest of my career, but rather,
</p>
<blockquote>
<ol type="a">
<li>"It is considered a topic that you should know in order to be "well-cultured" in computer science.</li>
<li>"A good craftsman should know his tools, and compilers are important tools for programmers and computer scientists.</li>
<li>"The techniques used for constructing a compiler are useful for other purposes as well.</li>
<li>"There is a good chance that a programmer or computer scientist will need to write a compiler or interpreter for a domain-specific language."</li>
</ol>
<footer><cite><a href="/ref/introduction-to-compiler-design">Introduction to Compiler Design</a></cite> (from the introduction), Torben Ægidius Mogensen</footer>
</blockquote>
<p>
That's good enough for me, and so far, I'm enjoying the course (although it's also hard work).
</p>
<p>
You may not find this particular topic interesting, but then hopefully you can find something else that you fancy. 3D rendering? Machine learning? Distributed systems architecture?
</p>
<h3 id="7519e9b6147d49379f545c69871c381a">
Conclusion <a href="#7519e9b6147d49379f545c69871c381a">#</a>
</h3>
<p>
Technology moves at a pace with which it's impossible to keep up. It's not just you who's falling behind. Everyone is. Even the best-paid <a href="https://en.wikipedia.org/wiki/Big_Tech">GAMMA</a> programmer knows next to nothing of all there is to know in the field. They may have superior skills in certain areas, but there will be so much other stuff that they don't know.
</p>
<p>
You may think of me as a <a href="https://x.com/hillelogram/status/1445435617047990273">thought leader</a> if you will. If nothing else, I tend to be a prolific writer. Perhaps you even think I'm a good programmer. I should hope so. Who fancies themselves bad at something?
</p>
<p>
You should, however, have seen me struggle with <a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a> programming during a course on computer systems programming. There's a thing I'm happy if I never have to revisit.
</p>
<p>
You can't know it all. You can't keep up. But you can focus on learning the fundamentals. That tends to make it easier to learn specific technologies that build on those foundations.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Gratificationhttps://blog.ploeh.dk/2024/05/13/gratification2024-05-13T06:27:00+00:00Mark Seemann
<div id="post">
<p>
<em>Some thoughts on developer experience.</em>
</p>
<p>
Years ago, I was introduced to a concept called <em>developer ergonomics</em>. Despite the name, it's not about good chairs, standing desks, or multiple monitors. Rather, the concept was related to how easy it'd be for a developer to achieve a certain outcome. How easy is it to set up a new code base in a particular language? How much work is required to save a row in a database? How hard is it to read rows from a database and display the data on a web page? And so on.
</p>
<p>
These days, we tend to discuss <em>developer experience</em> rather than ergonomics, and that's probably a good thing. This term more immediately conveys what it's about.
</p>
<p>
I've recently had some discussions about developer experience (DevEx, DX) with one of my customers, and this has lead me to reflect more explicitly on this topic than previously. Most of what I'm going to write here are opinions and beliefs that go back a long time, but apparently, it's only recently that these notions have congealed in my mind under the category name <em>developer experience</em>.
</p>
<p>
This article may look like your usual old-man-yells-at-cloud article, but I hope that I can avoid that. It's not the case that I yearn for some lost past where 'we' wrote <a href="https://en.wikipedia.org/wiki/Plankalk%C3%BCl">Plankalkül</a> in <a href="https://en.wikipedia.org/wiki/Edlin">Edlin</a>. That, in fact, sounds like a horrible developer experience.
</p>
<p>
The point, rather, is that most attractive things come with consequences. For anyone who have been reading this blog even once in a while, this should come as no surprise.
</p>
<h3 id="cbc9752f754e40cc94267689f5dd87bf">
Instant gratification <a href="#cbc9752f754e40cc94267689f5dd87bf">#</a>
</h3>
<p>
Fat foods, cakes, and wine can be wonderful, but can be detrimental to your health if you overindulge. It can, however, be hard to resist a piece of chocolate, and even if we think that we shouldn't, we often fail to restrain ourselves. The temptation of instant gratification is simply too great.
</p>
<p>
There are other examples like this. The most obvious are the use of narcotics, lack of exercise, smoking, and dropping out of school. It may feel good in the moment, but can have long-term consequences.
</p>
<p>
Small children are notoriously bad at delaying gratification, and we often associate the ability to delay gratification with maturity. We all, however, fall in from time to time. Food and wine are my weak spots, while I don't do drugs, and I didn't drop out of school.
</p>
<p>
It strikes me that we often talk about ideas related to developer experience in a way where we treat developers as children. To be fair, many developers also act like children. I don't know how many times I've <ins datetime="2024-06-17T08:26Z">heard</ins> something like, <em>"I don't want to write tests/go through a code review/refactor! I just want to ship working code now!"</em>
</p>
<p>
Fine, so do I.
</p>
<p>
Even if wine is bad for me, it makes life worth living. As the saying goes, even if you don't smoke, don't drink, exercise rigorously, eat healthily, don't do drugs, and don't engage in dangerous activities, you're not guaranteed to live until ninety, but you're guaranteed that it's going to <em>feel</em> that long.
</p>
<p>
Likewise, I'm aware that doing everything right can sometimes take so long that by the time we've deployed the software, it's too late. The point isn't to always or never do certain things, but rather to be aware of the consequences of our choices.
</p>
<h3 id="ac2969093f264da092186fa0cb7196e5">
Developer experience <a href="#ac2969093f264da092186fa0cb7196e5">#</a>
</h3>
<p>
I've no problem with aiming to make the experience of writing software as good as possible. Some developer-experience thought leaders talk about the importance of documentation, predictability, and timeliness. Neither do I mind that a development environment looks good, completes my words, or helps me refactor.
</p>
<p>
To return to the analogy of human vices, not everything that feels good is ultimately bad for you. While I do like wine and chocolate, I also love <a href="https://en.wikipedia.org/wiki/Sushi">sushi</a>, white <a href="https://en.wikipedia.org/wiki/Asparagus">asparagus</a>, <a href="https://en.wikipedia.org/wiki/Turbot">turbot</a>, <a href="https://en.wikipedia.org/wiki/Chanterelle">chanterelles</a>, <a href="https://en.wikipedia.org/wiki/Cyclopterus">lumpfish</a> roe <a href="https://en.wikipedia.org/wiki/Caviar">caviar</a>, <a href="https://en.wikipedia.org/wiki/Morchella">true morels</a>, <a href="https://en.wikipedia.org/wiki/Nephrops_norvegicus">Norway lobster</a>, and various other foods that tend to be categorized as healthy.
</p>
<p>
A good <a href="https://en.wikipedia.org/wiki/Integrated_development_environment">IDE</a> with refactoring support, statement completion, type information, test runner, etc. is certainly preferable to writing all code in <a href="https://en.wikipedia.org/wiki/Windows_Notepad">Notepad</a>.
</p>
<p>
That said, there's a certain kind of developer tooling and language features that strikes me as more akin to candy. These are typically tools and technologies that tend to demo well. Recent examples include <a href="https://www.openapis.org/">OpenAPI</a>, <a href="https://github.com/features/copilot">GitHub Copilot</a>, <a href="https://learn.microsoft.com/dotnet/csharp/fundamentals/program-structure/top-level-statements">C# top-level statements</a>, code generation, and <a href="https://www.postman.com/">Postman</a>. Not all of these are unequivocally bad, but they strike me as mostly aiming at immature developers.
</p>
<p>
The point of this article isn't to single out these particular products, standards, or language features, but on the other hand, in order to make a point, I do have to at least outline why I find them problematic. They're just examples, and I hope that by explaining what is on my mind, you can see the pattern and apply it elsewhere.
</p>
<h3 id="f7f676bf5a334b189b3c2baab18b1e6a">
OpenAPI <a href="#f7f676bf5a334b189b3c2baab18b1e6a">#</a>
</h3>
<p>
A standard like OpenAPI, for example, looks attractive because it automates or standardizes much work related to developing and maintaining <a href="https://en.wikipedia.org/wiki/REST">REST APIs</a>. Frameworks and tools that leverage that standard automatically creates machine-readable <a href="/2024/04/15/services-share-schema-and-contract-not-class">schema and contract</a>, which can be used to generate client code. Furthermore, an OpenAPI-aware framework can also autogenerate an entire web-based graphical user interface, which developers can use for ad-hoc testing.
</p>
<p>
I've worked with clients who also published these OpenAPI user interfaces to their customers, so that it was easy to get started with the APIs. Easy onboarding.
</p>
<p>
Instant gratification.
</p>
<p>
What's the problem with this? There are clearly enough apparent benefits that I usually have a hard time talking my clients out of pursuing this strategy. What are the disadvantages? Essentially, OpenAPI locks you into <a href="https://martinfowler.com/articles/richardsonMaturityModel.html">level 2</a> APIs. No hypermedia controls, no <a href="/2015/06/22/rest-implies-content-negotiation">smooth conneg-based versioning</a>, no <a href="https://en.wikipedia.org/wiki/HATEOAS">HATEOAS</a>. In fact, most of what makes REST flexible is lost. What remains is an ad-hoc, informally-specified, bug-ridden, slow implementation of half of <a href="https://en.wikipedia.org/wiki/SOAP">SOAP</a>.
</p>
<p>
I've <a href="/2022/12/05/github-copilot-preliminary-experience-report">previously described my misgivings about Copilot</a>, and while I actually still use it, I don't want to repeat all of that here. Let's move on to another example.
</p>
<h3 id="f56e835825464650a86c557c7253f095">
Top-level statements <a href="#f56e835825464650a86c557c7253f095">#</a>
</h3>
<p>
Among many other language features, C# 9 got <em>top-level-statements</em>. This means that you don't need to write a <code>Main</code> method in a static class. Rather, you can have a single C# code file where you can immediately start executing code.
</p>
<p>
It's not that I consider this language feature particularly harmful, but it also solves what seems to me a non-problem. It demos well, though. If I understand the motivation right, the feature exists because 'modern' developers are used to languages like <a href="https://www.python.org/">Python</a> where you can, indeed, just create a <code>.py</code> file and start adding code statements.
</p>
<p>
In an attempt to make C# more attractive to such an audience, it, too, got that kind of developer experience enabled.
</p>
<p>
You may argue that this is a bid to remove some of the ceremony from the language, but I'm not convinced that this moves that needle much. The <a href="/2019/12/16/zone-of-ceremony">level of ceremony that a language like C# has is much deeper than that</a>. That's not to target C# in particular. <a href="https://www.java.com/">Java</a> is similar, and don't even get me started on <a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a> or <a href="https://en.wikipedia.org/wiki/C%2B%2B">C++</a>! Did anyone say <em>header files?</em>
</p>
<p>
Do 'modern' developers choose Python over C# because they can't be arsed to write a <code>Main</code> method? If that's the <em>only</em> reason, it strikes me as incredibly immature. <em>I want instant gratification, and writing a <code>Main</code> method is just too much trouble!</em>
</p>
<p>
If developers do, indeed, choose Python or JavaScript over C# and Java, I hope and believe that it's for other reasons.
</p>
<p>
This particular C# feature doesn't bother me, but I find it symptomatic of a kind of 'innovation' where language designers target instant gratification.
</p>
<h3 id="b9ce02aa90074838bd7b8e2cec0189e2">
Postman <a href="#b9ce02aa90074838bd7b8e2cec0189e2">#</a>
</h3>
<p>
Let's consider one more example. You may think that I'm now attacking a company that, for all I know, makes a decent product. I don't really care about that, though. What I do care about is the developer mentality that makes a particular tool so ubiquitous.
</p>
<p>
I've met web service developers who would be unable to interact with the HTTP APIs that they are themselves developing if they didn't have Postman. Likewise, there are innumerable questions on <a href="https://stackoverflow.com/">Stack Overflow</a> where people ask questions about HTTP APIs and post screen shots of Postman sessions.
</p>
<p>
It's okay if you don't know how to interact with an HTTP API. After all, there's a first time for everything, and there was a time when I didn't know how to do this either. Apparently, however, it's easier to install an application with a graphical user interface than it is to use <a href="https://curl.se/">curl</a>.
</p>
<p>
Do yourself a favour and learn curl instead of using Postman. Curl is a command-line tool, which means that you can use it for both ad-hoc experimentation and automation. It takes five to ten minutes to learn the basics. It's also free.
</p>
<p>
It still seems to me that many people are of a mind that it's easier to use Postman than to learn curl. Ultimately, I'd wager that for any task you do with some regularity, it's more productive to learn the text-based tool than the point-and-click tool. In a situation like this, I'd suggest that delayed gratification beats instant gratification.
</p>
<h3 id="50ed56effb784c95a6f6de4967e883ef">
CV-driven development <a href="#50ed56effb784c95a6f6de4967e883ef">#</a>
</h3>
<p>
It is, perhaps, easy to get the wrong impression from the above examples. I'm not pointing fingers at just any 'cool' new technology. There are techniques, languages, frameworks, and so on, which people pick up because they're exciting for other reasons. Often, such technologies solve real problems in their niches, but are then applied for the sole reason that people want to get on the bandwagon. Examples include <a href="https://kubernetes.io/">Kubernetes</a>, mocks, <a href="/2012/11/06/WhentouseaDIContainer">DI Containers</a>, <a href="/2023/12/04/serialization-with-and-without-reflection">reflection</a>, <a href="https://en.wikipedia.org/wiki/Aspect-oriented_programming">AOP</a>, and <a href="https://en.wikipedia.org/wiki/Microservices">microservices</a>. All of these have legitimate applications, but we also hear about many examples where people use them just to use them.
</p>
<p>
That's a different problem from the one I'm discussing in this article. Usually, learning about such advanced techniques requires delaying gratification. There's nothing wrong with learning new skills, but part of that process is also gaining the understanding of when to apply the skill, and when not to. That's a different discussion.
</p>
<h3 id="10cc039f39ba4c2caab34f66f17f90b2">
Innovation is fine <a href="#10cc039f39ba4c2caab34f66f17f90b2">#</a>
</h3>
<p>
The point of this article isn't that every innovation is bad. Contrary to <a href="https://www.charlespetzold.com/">Charles Petzold</a>, I don't really believe that Visual Studio rots the mind, although I once did publish <a href="/2013/02/04/BewareofProductivityTools">an article</a> that navigated the same waters.
</p>
<p>
Despite my misgivings, I haven't uninstalled GitHub Copilot, and I do enjoy many of the features in both Visual Studio (VS) and Visual Studio Code (VS Code). I also welcome and use many new language features in various languages.
</p>
<p>
I can certainly appreciate how an IDE makes many things easier. Every time I have to begin a new <a href="https://www.haskell.org/">Haskell</a> code base, I long for the hand-holding offered by Visual Studio when creating a new C# project.
</p>
<p>
And although I don't use the debugger much, the built-in debuggers in VS and VS Code sure beat <a href="https://en.wikipedia.org/wiki/GNU_Debugger">GDB</a>. It even works in Python!
</p>
<p>
There's even tooling that <a href="https://developercommunity.visualstudio.com/t/Test-Explorer:-Better-support-for-TDD-wo/701822">I wish for</a>, but apparently never will get.
</p>
<h3 id="675450a5c0cf441fa433b928251de8a5">
Simple made easy <a href="#675450a5c0cf441fa433b928251de8a5">#</a>
</h3>
<p>
In <a href="https://www.infoq.com/presentations/Simple-Made-Easy/">Simple Made Easy</a> Rich Hickey follows his usual look-up-a-word-in-the-dictionary-and-build-a-talk-around-the-definition style to contrast <em>simple</em> with <em>easy</em>. I find his distinction useful. A tool or technique that's <em>close at hand</em> is <em>easy</em>. This certainly includes many of the above instant-gratification examples.
</p>
<p>
An <em>easy</em> technique is not, however, necessarily <em>simple</em>. It may or may not be. <a href="https://en.wikipedia.org/wiki/Rich_Hickey">Rich Hickey</a> defines <em>simple</em> as the opposite of <em>complex</em>. Something that is complex is assembled from parts, whereas a simple thing is, ideally, single and undivisible. In practice, truly simple ideas and tools may not be available, and instead we may have to settle with things that are less complex than their alternatives.
</p>
<p>
Once you start looking for things that make simple things easy, you see them in many places. A big category that I personally favour contains all the language features and tools that make functional programming (FP) easier. FP tends to be simpler than object-oriented or procedural programming, because it <a href="/2018/11/19/functional-architecture-a-definition">explicitly distinguishes between and separates</a> predictable code from unpredictable code. This does, however, in itself tend to make some programming tasks harder. How do you generate a random number? Look up the system time? Write a record to a database?
</p>
<p>
Several FP languages have special features that make even those difficult tasks easy. <a href="https://fsharp.org/">F#</a> has <a href="https://learn.microsoft.com/dotnet/fsharp/language-reference/computation-expressions">computation expressions</a> and <a href="https://www.haskell.org/">Haskell</a> has <a href="https://en.wikibooks.org/wiki/Haskell/do_notation">do notation</a>.
</p>
<p>
Let's say you want to call a function that consumes a random number generator. In Haskell (as in .NET) random number generators are actually deterministic, as long as you give them the same seed. Generating a random seed, on the other hand, is non-deterministic, so has to happen in <a href="/2020/06/08/the-io-container">IO</a>.
</p>
<p>
Without <code>do</code> notation, you could write the action like this:
</p>
<p>
<pre><span style="color:#2b91af;">rndSelect</span> <span style="color:blue;">::</span> <span style="color:blue;">Integral</span> i <span style="color:blue;">=></span> [a] <span style="color:blue;">-></span> i <span style="color:blue;">-></span> <span style="color:#2b91af;">IO</span> [a]
rndSelect xs count = (\rnd -> rndGenSelect rnd xs count) <$> newStdGen</pre>
</p>
<p>
(The type annotation is optional.) While terse, this is hardly readable, and the developer experience also leaves something to be desired. Fortunately, however, you can <a href="/2018/07/09/typing-and-testing-problem-23">rewrite this action</a> with <code>do</code> notation, like this:
</p>
<p>
<pre><span style="color:#2b91af;">rndSelect</span> :: <span style="color:blue;">Integral</span> i <span style="color:blue;">=></span> [a] <span style="color:blue;">-></span> i <span style="color:blue;">-></span> <span style="color:#2b91af;">IO</span> [a]
rndSelect xs count = <span style="color:blue;">do</span>
rnd <- newStdGen
<span style="color:blue;">return</span> $ rndGenSelect rnd xs count
</pre>
</p>
<p>
Now we can clearly see that the action first creates the <code>rnd</code> random number generator and then passes it to <code>rndGenSelect</code>. That's what happened before, but it was buried in a lambda expression and Haskell's right-to-left causality. Most people would find the first version (without <code>do</code> notation) less readable, and more difficult to write.
</p>
<p>
Related to <em>developer ergonomics</em>, though, <code>do</code> notation makes the simple code (i.e. code that separates predictable code from unpredictable code) easy (that is; <em>at hand</em>).
</p>
<p>
F# computation expressions offer the same kind of syntactic sugar, making it easy to write simple code.
</p>
<h3 id="86e9a9bd6cfc4408bedace8acd330f64">
Delay gratification <a href="#86e9a9bd6cfc4408bedace8acd330f64">#</a>
</h3>
<p>
While it's possible to set up a development context in such a way that it nudges you to work in a way that's ultimately good for you, temptation is everywhere.
</p>
<p>
Not only may new language features, IDE functionality, or frameworks entice you to do something that may be disadvantageous in the long run. There may also be actions you don't take because it just feels better to move on.
</p>
<p>
Do you take the time to write good commit messages? Not just a single-line heading, but <a href="https://github.com/GreanTech/AtomEventStore/commit/615cdee2c4d675d412e6669bcc0678655376c4d1">a proper message that explains your context and reasoning</a>?
</p>
<p>
Most people I've observed working with source control 'just want to move on', and can't be bothered to write a useful commit message.
</p>
<p>
I hear about the same mindset when it comes to code reviews, particularly pull request reviews. Everyone 'just wants to write code', and no-one want to review other people's code. Yet, in a shared code base, you have to live with the code that other people write. Why not review it so that you have a chance to decide what that shared code base should look like?
</p>
<p>
Delay your own gratification a bit, and reap the awards later.
</p>
<h3 id="630055ed606d43289d71232dd1ef1c25">
Conclusion <a href="#630055ed606d43289d71232dd1ef1c25">#</a>
</h3>
<p>
The only goal I have with this article is to make you think about the consequences of new and innovative tools and frameworks. Particularly if they are immediately compelling, they may be empty calories. Consider if there may be disadvantages to adopting a new way of doing things.
</p>
<p>
Some tools and technologies give you instant gratification, but may be unhealthy in the long run. This is, like most other things, context-dependent. <a href="/2023/01/16/in-the-long-run">In the long run</a> your company may no longer be around. Sometimes, it pays to deliberately do something that you know is bad, in order to reach a goal before your competition. That was the original <em>technical debt</em> metaphor.
</p>
<p>
Often, however, it pays to delay gratification. Learn curl instead of Postman. Learn to design proper REST APIs instead of relying on OpenAI. If you need to write ad-hoc scripts, <a href="/2024/02/05/statically-and-dynamically-typed-scripts">use a language suitable for that</a>.
</p>
</div>
<div id="comments">
<hr>
<h2 id="comments-header">
Comments
</h2>
<div class="comment" id="9efea1cadb8c4e388bfba1a2064dd59a">
<div class="comment-author"><a href="https://thomaslevesque.com">Thomas Levesque</a> <a href="#9efea1cadb8c4e388bfba1a2064dd59a">#</a></div>
<div class="comment-content">
<p>
Regarding Postman vs. curl, I have to disagree. Sure, curl is pretty easy to use. But while it's good for one-off tests, it sucks when you need to maintain a collection of requests that you can re-execute whevenever you want.
In a testing session, you either need to re-type whole command, or reuse a previous command from the shell's history. Or have a file with all your commands and copy-paste to the shell. Either way, it's not a good experience.
</p>
<p>
That being said, I'm not very fond of Postman either. It's too heavyweight for what it does, IMHO, and the import/export mechanism is terrible for sharing collections with the team. These days, I tend to use VSCode extensions
like <a href="https://github.com/AnWeber/vscode-httpyac">httpYac</a> or <a href="https://github.com/Huachao/vscode-restclient">REST Client</a>, or the equivalent that is now built into Visual Studio and Rider. It's much easier
to work with than Postman (it's just text), while still being interactive. And since it's just a text file, you can just add it to the Git to share it with the team.
</p>
</div>
<div class="comment-date">2024-05-14 02:38 UTC</div>
</div>
<div class="comment" id="9efea1cadb8c4e388bfba1a2064dd59b">
<div class="comment-author"><a href="https://majiehong.com/">Jiehong</a> <a href="#9efea1cadb8c4e388bfba1a2064dd59b">#</a></div>
<div class="comment-content">
<p>
@Thomas Levesque: I agree with you, yet VSCode or Rider's extensions lock you into an editor quite quickly.
</p>
<p>
But you can have the best of both worlds: a cli tool first, with editor extensions.
Just like <a href="https://github.com/Orange-OpenSource/hurl">Hurl</a>.
</p>
<p>
Note that you can run a <a href="https://everything.curl.dev/cmdline/configfile.html#urls">curl command from a file with</a> <code>curl --config [curl_request.file]</code>,
it makes chaining requests (like with login and secrets) rather cumbersome very quickly.
</p>
</div>
<div class="comment-date">2024-05-16 13:57 UTC</div>
</div>
<div class="comment" id="2a6dd3839e2e4bf9b06071221b330356">
<div class="comment-author"><a href="/">Mark Seemann</a> <a href="#2a6dd3839e2e4bf9b06071221b330356">#</a></div>
<div class="comment-content">
<p>
Thank you, both, for writing. In the end, it's up to every team to settle on technical solutions that work for them, in that context. Likewise, it's up to each developer to identify methodology and tools that work for her or him, as long as it doesn't impact the rest of the team.
</p>
<p>
The reason I suggest curl over other alternatives is that not only is it free, it also tends to be ubiquitous. Most systems come with curl baked in - perhaps not a consumer installation of Windows, but if you have developer tools installed, it's highly likely that you have curl on your machine. It's <a href="/2024/05/20/fundamentals">a fundamental skill that may serve you well if you know it</a>.
</p>
<p>
In addition to that, since curl is a CLI you can always script it if you need a kind of semi-automation. What prevents you from maintaining a collection of script files? They could even take command-line arguments, if you'd like.
</p>
<p>
That said, personally, if I realize that I need to maintain a collection of requests that I can re-execute whenever I want, I'd prefer writing a 'real' program. On the other hand, I find a tool like curl useful for ad-hoc testing.
</p>
</div>
<div class="comment-date">2024-05-21 5:36 UTC</div>
</div>
<div class="comment" id="be53c7b6d29a43e0aa0fdac3fcce835d">
<div class="comment-author">Johannes Egger <a href="#be53c7b6d29a43e0aa0fdac3fcce835d">#</a></div>
<div class="comment-content">
<blockquote>
... maintain a collection of requests that you can re-execute whevenever you want.
</blockquote>
<p>@Thomas Levesque: that sounds like a proper collection of automatically executable tests would be a better fit. But yeah, it's just easier to write those simple commands than to set up a test project - instant gratification 😉</p>
</div>
<div class="comment-date">2024-05-28 17:02 UTC</div>
</div>
</div>
<hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Conservative codomain conjecturehttps://blog.ploeh.dk/2024/05/06/conservative-codomain-conjecture2024-05-06T06:35:00+00:00Mark Seemann
<div id="post">
<p>
<em>An API design heuristic.</em>
</p>
<p>
For a while now, I've been wondering whether, in the language of <a href="https://en.wikipedia.org/wiki/Robustness_principle">Postel's law</a>, one should favour being liberal in what one accepts over being conservative in what one sends. Yes, according to the design principle, a protocol or API should do both, but sometimes, you can't do that. Instead, you'll have to choose. I've recently reached the tentative conclusion that it may be a good idea favouring being conservative in what one sends.
</p>
<p>
Good API design explicitly considers <em>contracts</em>. What are the preconditions for invoking an operation? What are the postconditions? Are there any invariants? These questions are relevant far beyond object-oriented design. They are <a href="/2022/10/24/encapsulation-in-functional-programming">equally important in Functional Programming</a>, as well as <a href="/2024/04/15/services-share-schema-and-contract-not-class">in service-oriented design</a>.
</p>
<p>
If you have a type system at your disposal, you can often model pre- and postconditions as types. In practice, however, it frequently turns out that there's more than one way of doing that. You can model an additional precondition with an input type, but you can also model potential errors as a return type. Which option is best?
</p>
<p>
That's what this article is about, and my conjecture is that constraining the input type may be preferable, thus being conservative about what is returned.
</p>
<h3 id="7ef0610940fb4670b7cf12a21bdd725f">
An average example <a href="#7ef0610940fb4670b7cf12a21bdd725f">#</a>
</h3>
<p>
That's all quite abstract, so for the rest of this article, I'll discuss this kind of problem in the context of an example. We'll revisit the <a href="/2020/02/03/non-exceptional-averages">good old example of calculating an average value</a>. This example, however, is only a placeholder for any kind of API design problem. This article is only superficially about designing an API for calculating an <a href="https://en.wikipedia.org/wiki/Average">average</a>. More generally, this is about API design. I like the <em>average</em> example because it's easy to follow, and it does exhibit some characteristics that you can hopefully extrapolate from.
</p>
<p>
In short, what is the contract of the following method?
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">TimeSpan</span> <span style="color:#74531f;">Average</span>(<span style="color:blue;">this</span> <span style="color:#2b91af;">IEnumerable</span><<span style="color:#2b91af;">TimeSpan</span>> <span style="font-weight:bold;color:#1f377f;">timeSpans</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sum</span> = <span style="color:#2b91af;">TimeSpan</span>.Zero;
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">count</span> = 0;
<span style="font-weight:bold;color:#8f08c4;">foreach</span> (<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">ts</span> <span style="font-weight:bold;color:#8f08c4;">in</span> <span style="font-weight:bold;color:#1f377f;">timeSpans</span>)
{
<span style="font-weight:bold;color:#1f377f;">sum</span> <span style="font-weight:bold;color:#74531f;">+=</span> <span style="font-weight:bold;color:#1f377f;">ts</span>;
<span style="font-weight:bold;color:#1f377f;">count</span>++;
}
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">sum</span> <span style="font-weight:bold;color:#74531f;">/</span> <span style="font-weight:bold;color:#1f377f;">count</span>;
}</pre>
</p>
<p>
What are the preconditions? What are the postconditions? Are there any invariants?
</p>
<p>
Before I answer these questions, I'll offer equivalent code in two other languages. Here it is in <a href="https://fsharp.org/">F#</a>:
</p>
<p>
<pre>let average (timeSpans : TimeSpan seq) =
timeSpans
|> Seq.averageBy (_.Ticks >> double)
|> int64
|> TimeSpan.FromTicks</pre>
</p>
<p>
And in <a href="https://www.haskell.org/">Haskell</a>:
</p>
<p>
<pre><span style="color:#2b91af;">average</span> <span style="color:blue;">::</span> (<span style="color:blue;">Fractional</span> a, <span style="color:blue;">Foldable</span> t) <span style="color:blue;">=></span> t a <span style="color:blue;">-></span> a
average xs = <span style="color:blue;">sum</span> xs / <span style="color:blue;">fromIntegral</span> (<span style="color:blue;">length</span> xs)</pre>
</p>
<p>
These three examples have somewhat different implementations, but the same externally observable behaviour. What is the contract?
</p>
<p>
It seems straightforward: If you input a sequence of values, you get the average of all of those values. Are there any preconditions? Yes, the sequence can't be empty. Given an empty sequence, all three implementations throw an exception. (The Haskell version is a little more nuanced than that, but given an empty list of <a href="https://hackage.haskell.org/package/time/docs/Data-Time-Clock.html#t:NominalDiffTime">NominalDiffTime</a>, it does throw an exception.)
</p>
<p>
Any other preconditions? At least one more: The sequence must be finite. All three functions allow infinite streams as input, but if given one, they will fail to return an average.
</p>
<p>
Are there any postconditions? I can only think of a statement that relates to the preconditions: <em>If</em> the preconditions are fulfilled, the functions will return the correct average value (within the precision allowed by floating-point calculations).
</p>
<p>
All of this, however, is just warming up. We've <a href="/2020/02/03/non-exceptional-averages">been over this ground before</a>.
</p>
<h3 id="7922b269c9924877abe993cb282440a8">
Modelling contracts <a href="#7922b269c9924877abe993cb282440a8">#</a>
</h3>
<p>
Keep in mind that this <em>average</em> function is just an example. Think of it as a stand-in for a procedure that's much more complicated. Think of the most complicated operation in your code base.
</p>
<p>
Not only do real code bases have many complicated operations. Each comes with its own contract, different from the other operations, and if the team isn't explicitly thinking in terms of contracts, these contracts may change over time, as the team adds new features and fixes bugs.
</p>
<p>
It's difficult work to keep track of all those contracts. As I argue in <a href="/2021/06/14/new-book-code-that-fits-in-your-head">Code That Fits in Your Head</a>, it helps if you can automate away some of that work. One way is having good test coverage. Another is to leverage a static type system, if you're fortunate enough to work in a language that has one. As I've <em>also</em> already covered, <a href="/2022/08/22/can-types-replace-validation">you can't replace all rules with types</a>, but it doesn't mean that using the type system is ineffectual. Quite the contrary. Every part of a contract that you can offload to the type system frees up your brain to think about something else - something more important, hopefully.
</p>
<p>
Sometimes there's no good way to to model a precondition with a type, or <a href="https://buttondown.email/hillelwayne/archive/making-illegal-states-unrepresentable/">perhaps it's just too awkward</a>. At other times, there's really only a single way to address a concern. When it comes to the precondition that you can't pass an infinite sequence to the <em>average</em> function, <a href="/2020/02/03/non-exceptional-averages">change the type so that it takes some finite collection</a> instead. That's not what this article is about, though.
</p>
<p>
Assuming that you've already dealt with the infinite-sequence issue, how do you address the other precondition?
</p>
<h3 id="03c13848cbd54058a3dfed204bc85878">
Error-handling <a href="#03c13848cbd54058a3dfed204bc85878">#</a>
</h3>
<p>
A typical object-oriented move is to introduce a Guard Clause:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">TimeSpan</span> <span style="color:#74531f;">Average</span>(<span style="color:blue;">this</span> <span style="color:#2b91af;">IReadOnlyCollection</span><<span style="color:#2b91af;">TimeSpan</span>> <span style="font-weight:bold;color:#1f377f;">timeSpans</span>)
{
<span style="font-weight:bold;color:#8f08c4;">if</span> (!<span style="font-weight:bold;color:#1f377f;">timeSpans</span>.<span style="font-weight:bold;color:#74531f;">Any</span>())
<span style="font-weight:bold;color:#8f08c4;">throw</span> <span style="color:blue;">new</span> <span style="color:#2b91af;">ArgumentOutOfRangeException</span>(
<span style="color:blue;">nameof</span>(<span style="font-weight:bold;color:#1f377f;">timeSpans</span>),
<span style="color:#a31515;">"Can't calculate the average of an empty collection."</span>);
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sum</span> = <span style="color:#2b91af;">TimeSpan</span>.Zero;
<span style="font-weight:bold;color:#8f08c4;">foreach</span> (<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">ts</span> <span style="font-weight:bold;color:#8f08c4;">in</span> <span style="font-weight:bold;color:#1f377f;">timeSpans</span>)
<span style="font-weight:bold;color:#1f377f;">sum</span> <span style="font-weight:bold;color:#74531f;">+=</span> <span style="font-weight:bold;color:#1f377f;">ts</span>;
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">sum</span> <span style="font-weight:bold;color:#74531f;">/</span> <span style="font-weight:bold;color:#1f377f;">timeSpans</span>.Count;
}</pre>
</p>
<p>
You could do the same in F#:
</p>
<p>
<pre>let average (timeSpans : TimeSpan seq) =
if Seq.isEmpty timeSpans then
raise (
ArgumentOutOfRangeException(
nameof timeSpans,
"Can't calculate the average of an empty collection."))
timeSpans
|> Seq.averageBy (_.Ticks >> double)
|> int64
|> TimeSpan.FromTicks</pre>
</p>
<p>
You <em>could</em> also replicate such behaviour in Haskell, but it'd be highly unidiomatic. Instead, I'd rather discuss one <a href="/2015/08/03/idiomatic-or-idiosyncratic">idiomatic</a> solution in Haskell, and then back-port it.
</p>
<p>
While you can throw exceptions in Haskell, you typically handle <a href="/2024/01/29/error-categories-and-category-errors">predictable errors</a> with a <a href="https://en.wikipedia.org/wiki/Tagged_union">sum type</a>. Here's a version of the Haskell function equivalent to the above C# code:
</p>
<p>
<pre><span style="color:#2b91af;">average</span> <span style="color:blue;">::</span> (<span style="color:blue;">Foldable</span> t, <span style="color:blue;">Fractional</span> a) <span style="color:blue;">=></span> t a <span style="color:blue;">-></span> <span style="color:#2b91af;">Either</span> <span style="color:#2b91af;">String</span> a
average xs =
<span style="color:blue;">if</span> <span style="color:blue;">null</span> xs
<span style="color:blue;">then</span> Left <span style="color:#a31515;">"Can't calculate the average of an empty collection."</span>
<span style="color:blue;">else</span> Right $ <span style="color:blue;">sum</span> xs / <span style="color:blue;">fromIntegral</span> (<span style="color:blue;">length</span> xs)
</pre>
</p>
<p>
For the readers that don't know the Haskell <a href="https://hackage.haskell.org/package/base">base</a> library by heart, <a href="https://hackage.haskell.org/package/base/docs/Data-List.html#v:null">null</a> is a predicate that checks whether or not a collection is empty. It has nothing to do with <a href="https://en.wikipedia.org/wiki/Null_pointer">null pointers</a>.
</p>
<p>
This variation returns an <a href="/2018/06/11/church-encoded-either">Either</a> value. In practice you shouldn't just return a <code>String</code> as the error value, but rather a strongly-typed value that other code can deal with in a robust manner.
</p>
<p>
On the other hand, in this particular example, there's really only one error condition that the function is able to detect, so you often see a variation where instead of a single error message, such a function just doesn't return anything:
</p>
<p>
<pre><span style="color:#2b91af;">average</span> <span style="color:blue;">::</span> (<span style="color:blue;">Foldable</span> t, <span style="color:blue;">Fractional</span> a) <span style="color:blue;">=></span> t a <span style="color:blue;">-></span> <span style="color:#2b91af;">Maybe</span> a
average xs = <span style="color:blue;">if</span> <span style="color:blue;">null</span> xs <span style="color:blue;">then</span> Nothing <span style="color:blue;">else</span> Just $ <span style="color:blue;">sum</span> xs / <span style="color:blue;">fromIntegral</span> (<span style="color:blue;">length</span> xs)
</pre>
</p>
<p>
This iteration of the function returns a <a href="/2018/03/26/the-maybe-functor">Maybe</a> value, indicating that a return value may or may not be present.
</p>
<h3 id="ccc6a2a1804740a8942feee3b637db90">
Liberal domain <a href="#ccc6a2a1804740a8942feee3b637db90">#</a>
</h3>
<p>
We can back-port this design to F#, where I'd also consider it idiomatic:
</p>
<p>
<pre>let average (timeSpans : IReadOnlyCollection<TimeSpan>) =
if timeSpans.Count = 0 then None else
timeSpans
|> Seq.averageBy (_.Ticks >> double)
|> int64
|> TimeSpan.FromTicks
|> Some</pre>
</p>
<p>
This version returns a <code>TimeSpan option</code> rather than just a <code>TimeSpan</code>. While this may seem to put the burden of error-handling on the caller, nothing has really changed. The fundamental situation is the same. Now the function is just being more <a href="https://peps.python.org/pep-0020/">explicit</a> (more honest, you could say) about the pre- and postconditions. The type system also now insists that you deal with the possibility of error, rather than just hoping that the problem doesn't occur.
</p>
<p>
In C# you can <a href="/2024/01/29/error-categories-and-category-errors">expand the codomain by returning a nullable TimeSpan value</a>, but such an option may not always be available at the language level. Keep in mind that the <code>Average</code> method is just an example standing in for something that may be more complicated. If the original return type is a <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/reference-types">reference type</a> rather than a <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/value-types">value type</a>, only recent versions of C# allows statically-checked <a href="https://learn.microsoft.com/dotnet/csharp/nullable-references">nullable reference types</a>. What if you're working in an older version of C#, or another language that doesn't have that feature?
</p>
<p>
In that case, you may need to introduce an explicit <a href="/2018/03/26/the-maybe-functor">Maybe</a> class and return that:
</p>
<p>
<pre>public static Maybe<TimeSpan> Average(this IReadOnlyCollection<TimeSpan> timeSpans)
{
if (timeSpans.Count == 0)
return new Maybe<TimeSpan>();
var sum = TimeSpan.Zero;
foreach (var ts in timeSpans)
sum += ts;
return new Maybe<TimeSpan>(sum / timeSpans.Count);
}</pre>
</p>
<p>
Two things are going on here; one is obvious while the other is more subtle. Clearly, all of these alternatives change the static type of the function in order to make the pre- and postconditions more explicit. So far, they've all been loosening the <a href="https://en.wikipedia.org/wiki/Codomain">codomain</a> (the return <a href="/2021/11/15/types-as-sets">type</a>). This suggests a connection with <a href="https://en.wikipedia.org/wiki/Robustness_principle">Postel's law</a>: <em>be conservative in what you send, be liberal in what you accept</em>. These variations are all liberal in what they accept, but it seems that the API design pays the price by also having to widen the set of possible return values. In other words, such designs aren't conservative in what they send.
</p>
<p>
Do we have other options?
</p>
<h3 id="4fb2cc5775c44f80965cacbc37825f27">
Conservative codomain <a href="#4fb2cc5775c44f80965cacbc37825f27">#</a>
</h3>
<p>
Is it possible to instead design the API in such a way that it's conservative in what it returns? Ideally, we'd like it to guarantee that it returns a number. This is possible by making the preconditions even more explicit. I've also <a href="/2020/02/03/non-exceptional-averages">covered that alternative already</a>, so I'm just going to repeat the C# code here without further comments:
</p>
<p>
<pre><span style="color:blue;">public</span> <span style="color:blue;">static</span> <span style="color:#2b91af;">TimeSpan</span> <span style="color:#74531f;">Average</span>(<span style="color:blue;">this</span> <span style="color:#2b91af;">NotEmptyCollection</span><<span style="color:#2b91af;">TimeSpan</span>> <span style="font-weight:bold;color:#1f377f;">timeSpans</span>)
{
<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">sum</span> = <span style="font-weight:bold;color:#1f377f;">timeSpans</span>.Head;
<span style="font-weight:bold;color:#8f08c4;">foreach</span> (<span style="color:blue;">var</span> <span style="font-weight:bold;color:#1f377f;">ts</span> <span style="font-weight:bold;color:#8f08c4;">in</span> <span style="font-weight:bold;color:#1f377f;">timeSpans</span>.Tail)
<span style="font-weight:bold;color:#1f377f;">sum</span> <span style="font-weight:bold;color:#74531f;">+=</span> <span style="font-weight:bold;color:#1f377f;">ts</span>;
<span style="font-weight:bold;color:#8f08c4;">return</span> <span style="font-weight:bold;color:#1f377f;">sum</span> <span style="font-weight:bold;color:#74531f;">/</span> <span style="font-weight:bold;color:#1f377f;">timeSpans</span>.Count;
}</pre>
</p>
<p>
This variation promotes another precondition to a type. The precondition that the input collection mustn't be empty can be explicitly modelled with a type. This enables us to be conservative about the codomain. The method now guarantees that it will return a value.
</p>
<p>
This idea is also easily ported to F#:
</p>
<p>
<pre>type NonEmpty<'a> = { Head : 'a; Tail : IReadOnlyCollection<'a> }
let average (timeSpans : NonEmpty<TimeSpan>) =
[ timeSpans.Head ] @ List.ofSeq timeSpans.Tail
|> List.averageBy (_.Ticks >> double)
|> int64
|> TimeSpan.FromTicks</pre>
</p>
<p>
The <code>average</code> function now takes a <code>NonEmpty</code> collection as input, and always returns a proper <code>TimeSpan</code> value.
</p>
<p>
Haskell already comes with a built-in <a href="https://hackage.haskell.org/package/base/docs/Data-List-NonEmpty.html">NonEmpty</a> collection type, and while it oddly doesn't come with an <code>average</code> function, it's easy enough to write:
</p>
<p>
<pre><span style="color:blue;">import</span> <span style="color:blue;">qualified</span> Data.List.NonEmpty <span style="color:blue;">as</span> NE
<span style="color:#2b91af;">average</span> <span style="color:blue;">::</span> <span style="color:blue;">Fractional</span> a <span style="color:blue;">=></span> <span style="color:blue;">NE</span>.<span style="color:blue;">NonEmpty</span> a <span style="color:blue;">-></span> a
average xs = <span style="color:blue;">sum</span> xs / <span style="color:blue;">fromIntegral</span> (NE.<span style="color:blue;">length</span> xs)
</pre>
</p>
<p>
You can find a recent example of using a variation of that function <a href="/2024/04/08/extracting-curve-coordinates-from-a-bitmap">here</a>.
</p>
<h3 id="6f42a53e7c5f4ddb994e85c9d15ec37a">
Choosing between the two alternatives <a href="#6f42a53e7c5f4ddb994e85c9d15ec37a">#</a>
</h3>
<p>
While Postel's law recommends having liberal domains and conservative codomains, in the case of the <em>average</em> API, we can't have both. If we design the API with a liberal input type, the output type has to be liberal as well. If we design with a restrictive input type, the output can be guaranteed. In my experience, you'll often find yourself in such a conundrum. The <em>average</em> API examined in this article is just an example, while the problem occurs often.
</p>
<p>
Given such a choice, what should you choose? Is it even possible to give general guidance on this sort of problem?
</p>
<p>
For decades, I considered such a choice a toss-up. After all, these solutions seem to be equivalent. Perhaps even isomorphic?
</p>
<p>
When I recently began to explore this isomorphism more closely, it dawned on me that there's a small asymmetry in the isomorphism that favours the <em>conservative codomain</em> option.
</p>
<h3 id="976ac8645de44d51a5796be7481b1c12">
Isomorphism <a href="#976ac8645de44d51a5796be7481b1c12">#</a>
</h3>
<p>
An <a href="https://en.wikipedia.org/wiki/Isomorphism">isomorphism</a> is a two-way translation between two representations. You can go back and forth between the two alternatives without loss of information.
</p>
<p>
Is this possible with the two alternatives outlined above? For example, if you have the conservative version, can create the liberal alternative? Yes, you can:
</p>
<p>
<pre><span style="color:#2b91af;">average'</span> <span style="color:blue;">::</span> <span style="color:blue;">Fractional</span> a <span style="color:blue;">=></span> [a] <span style="color:blue;">-></span> <span style="color:#2b91af;">Maybe</span> a
average' = <span style="color:blue;">fmap</span> average . NE.nonEmpty</pre>
</p>
<p>
Not surprisingly, this is trivial in Haskell. If you have the conservative version, you can just map it over a more liberal input.
</p>
<p>
In F# it looks like this:
</p>
<p>
<pre>module NonEmpty =
let tryOfSeq xs =
if Seq.isEmpty xs then None
else Some { Head = Seq.head xs; Tail = Seq.tail xs |> List.ofSeq }
let average' (timeSpans : IReadOnlyCollection<TimeSpan>) =
NonEmpty.tryOfSeq timeSpans |> Option.map average</pre>
</p>
<p>
In C# we can create a liberal overload that calls the conservative method:
</p>
<p>
<pre>public static TimeSpan? Average(this IReadOnlyCollection<TimeSpan> timeSpans)
{
if (timeSpans.Count == 0)
return null;
var arr = timeSpans.ToArray();
return new NotEmptyCollection<TimeSpan>(arr[0], arr[1..]).Average();
}</pre>
</p>
<p>
Here I just used a Guard Clause and explicit construction of the <code>NotEmptyCollection</code>. I could also have added a <code>NotEmptyCollection.TryCreate</code> method, like in the F# and Haskell examples, but I chose the above slightly more imperative style in order to demonstrate that my point isn't tightly coupled to the concept of <a href="/2018/03/22/functors">functors</a>, mapping, and other Functional Programming trappings.
</p>
<p>
These examples highlight how you can trivially make a conservative API look like a liberal API. Is it possible to go the other way? Can you make a liberal API look like a conservative API?
</p>
<p>
Yes and no.
</p>
<p>
Consider the liberal Haskell version of <code>average</code>, shown above; that's the one that returns <code>Maybe a</code>. Can you make a conservative function based on that?
</p>
<p>
<pre><span style="color:#2b91af;">average'</span> <span style="color:blue;">::</span> <span style="color:blue;">Fractional</span> a <span style="color:blue;">=></span> <span style="color:blue;">NE</span>.<span style="color:blue;">NonEmpty</span> a <span style="color:blue;">-></span> a
average' xs = fromJust $ average xs</pre>
</p>
<p>
Yes, this is possible, but only by resorting to the <a href="https://wiki.haskell.org/Partial_functions">partial function</a> <a href="https://hackage.haskell.org/package/base/docs/Data-Maybe.html#v:fromJust">fromJust</a>. I'll explain why that is a problem once we've covered examples in the two other languages, such as F#:
</p>
<p>
<pre>let average' (timeSpans : NonEmpty<TimeSpan>) =
[ timeSpans.Head ] @ List.ofSeq timeSpans.Tail |> average |> Option.get</pre>
</p>
<p>
In this variation, <code>average</code> is the liberal version shown above; the one that returns a <code>TimeSpan option</code>. In order to make a conservative version, the <code>average'</code> function can call the liberal <code>average</code> function, but has to resort to the partial function <code>Option.get</code>.
</p>
<p>
The same issue repeats a third time in C#:
</p>
<p>
<pre>public static TimeSpan Average(this NotEmptyCollection<TimeSpan> timeSpans)
{
return timeSpans.ToList().Average().Value;
}</pre>
</p>
<p>
This time, the partial function is the unsafe <a href="https://learn.microsoft.com/dotnet/api/system.nullable-1.value">Value</a> property, which throws an <code>InvalidOperationException</code> if there's no value.
</p>
<p>
This even violates Microsoft's own design guidelines:
</p>
<blockquote>
<p>
"AVOID throwing exceptions from property getters."
</p>
<footer><cite><a href="https://learn.microsoft.com/dotnet/standard/design-guidelines/property">Krzystof Cwalina and Brad Abrams</a></cite></footer>
</blockquote>
<p>
I've cited Cwalina and Abrams as the authors, since this rule can be found in my 2006 edition of <a href="/ref/fdg">Framework Design Guidelines</a>. This isn't a new insight.
</p>
<p>
While the two alternatives are 'isomorphic enough' that we can translate both ways, the translations are asymmetric in the sense that one is safe, while the other has to resort to an inherently unsafe operation to make it work.
</p>
<h3 id="e10b4b0269b74efa9d89275644c88d8e">
Encapsulation <a href="#e10b4b0269b74efa9d89275644c88d8e">#</a>
</h3>
<p>
I've called the operations <code>fromJust</code>, <code>Option.get</code>, and <code>Value</code> <em>partial</em>, and only just now used the word <em>unsafe</em>. You may protest that neither of the three examples are unsafe in practice, since we know that the input is never empty. Thus, we know that the liberal function will always return a value, and therefore it's safe to call a partial function, even though these operations are unsafe in the general case.
</p>
<p>
While that's true, consider how the burden shifts. When you want to promote a conservative variant to a liberal variant, you can rely on all the operations being total. On the other hand, if you want to make a liberal variant look conservative, the onus is on you. None of the three type systems on display here can perform that analysis for you.
</p>
<p>
This may not be so bad when the example is as simple as taking the average of a collection of numbers, but does it scale? What if the operation you're invoking is much more complicated? Can you still be sure that you safely invoke a partial function on the return value?
</p>
<p>
As <a href="/ctfiyh">Code That Fits in Your Head</a> argues, procedures quickly become so complicated that they no longer fit in your head. If you don't have well-described and patrolled contracts, you don't know what the postconditions are. You can't trust the return values from method calls, or even the state of the objects you passed as arguments. This tend to lead to <a href="/2013/07/08/defensive-coding">defensive coding</a>, where you write code that checks the state of everything all too often.
</p>
<p>
The remedy is, as always, good old <a href="/encapsulation-and-solid">encapsulation</a>. In this case, check the preconditions at the beginning, and capture the result of that check in an object or type that is guaranteed to be always valid. This goes beyond <a href="https://blog.janestreet.com/effective-ml-video/">making illegal states unrepresentable</a> because it also works with <a href="https://www.hillelwayne.com/post/constructive/">predicative</a> types. Once you're past the Guard Clauses, you don't have to check the preconditions <em>again</em>.
</p>
<p>
This kind of thinking illustrates why you need a multidimensional view on API design. As useful as Postel's law sometimes is, it doesn't address all problems. In fact, it turned out to be unhelpful in this context, while another perspective proves more fruitful. Encapsulation is the art and craft of designing APIs in such a way that they suggest or even compels correct interactions. The more I think of this, the more it strikes me that a <em>ranking</em> is implied: Preconditions are more important than postconditions, because if the preconditions are unfulfilled, you can't trust the postconditions, either.
</p>
<h3 id="35bb4abc87b8402da82c82c5baa71235">
Mapping <a href="#35bb4abc87b8402da82c82c5baa71235">#</a>
</h3>
<p>
What's going on here? One perspective is to view <a href="/2021/11/15/types-as-sets">types as sets</a>. In the <em>average</em> example, the function maps from one set to another:
</p>
<p>
<img src="/content/binary/mapping-from-collections-to-reals.png" alt="Mapping from the set of collections to the set of real numbers.">
</p>
<p>
Which sets are they? We can think of the <em>average</em> function as a mapping from the set of non-empty collections of numbers to the set of <a href="https://en.wikipedia.org/wiki/Real_number">real numbers</a>. In programming, we can't represent real numbers, so instead, the left set is going to be the set of all the non-empty collections the computer or the language can represent and hold in (virtual) memory, and the right-hand set is the set of all the possible numbers of whichever type you'd like (32-bit signed integers, <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">64-bit floating-point numbers</a>, 8-bit unsigned integers, etc.).
</p>
<p>
In reality, the left-hand set is much larger than the set to the right.
</p>
<p>
Drawing all those arrows quickly becomes awkward , so instead, we may <a href="/2021/11/22/functions-as-pipes">draw each mapping as a pipe</a>. Such a pipe also corresponds to a function. Here's an intermediate step in such a representation:
</p>
<p>
<img src="/content/binary/mapping-from-collections-to-reals-transparent-pipe.png" alt="Mapping from one set to the other, drawn inside a transparent pipe.">
</p>
<p>
One common element is, however, missing from the left set. Which one?
</p>
<h3 id="8920c8df3b9f4f978a5c560d5c9cdcb4">
Pipes <a href="#8920c8df3b9f4f978a5c560d5c9cdcb4">#</a>
</h3>
<p>
The above mapping corresponds to the conservative variation of the function. It's a total function that maps all values in the domain to a value in the codomain. It accomplishes this trick by explicitly constraining the domain to only those elements on which it's defined. Due to the preconditions, that excludes the empty collection, which is therefore absent from the left set.
</p>
<p>
What if we also want to allow the empty collection to be a valid input?
</p>
<p>
Unless we find ourselves in some special context where it makes sense to define a 'default average value', we can't map an empty collection to any meaningful number. Rather, we'll have to map it to some special value, such as <code>Nothing</code>, <code>None</code>, or <code>null</code>:
</p>
<p>
<img src="/content/binary/mapping-with-none-channel-transparent-pipe.png" alt="Mapping the empty collection to null in a pipe separate, but on top of, the proper function pipe.">
</p>
<p>
This extra pipe is free, because it's supplied by the <a href="/2018/03/26/the-maybe-functor">Maybe functor</a>'s mapping (<code>Select</code>, <code>map</code>, <code>fmap</code>).
</p>
<p>
What happens if we need to go the other way? If the function is the liberal variant that also maps the empty collection to a special element that indicates a missing value?
</p>
<p>
<img src="/content/binary/mapping-from-all-collections-to-reals-transparent-pipe.png" alt="Mapping all collections, including the empty collection, to the set of real numbers.">
</p>
<p>
In this case, it's much harder to disentangle the mappings. If you imagine that a liquid flows through the pipes, we can try to be careful and avoid 'filling up' the pipe.
</p>
<p>
<img src="/content/binary/pipe-partially-filled-with-liquid.png" alt="Pipe partially filled with liquid.">
</p>
<p>
The liquid represents the data that we <em>do</em> want to transmit through the pipe. As this illustration suggests, we now have to be careful that nothing goes wrong. In order to catch just the right outputs on the right side, you need to know how high the liquid may go, and attach a an 'flat-top' pipe to it:
</p>
<p>
<img src="/content/binary/pipe-composed-with-open-top-pipe.png" alt="Pipe composed with open-top pipe.">
</p>
<p>
As this illustration tries to get across, this kind of composition is awkward and error-prone. What's worse is that you need to know how high the liquid is going to get on the right side. This depends on what actually goes on inside the pipe, and what kind of input goes into the left-hand side.
</p>
<p>
This is a metaphor. The longer the pipe is, the more difficult it gets to keep track of that knowledge. The stubby little pipe in these illustrations may correspond to the <em>average</em> function, which is an operation that easily fits in our heads. It's not too hard to keep track of the preconditions, and how they map to postconditions.
</p>
<p>
Thus, turning such a small liberal function into a conservative function is possible, but already awkward. If the operation is complicated, you can no longer keep track of all the details of how the inputs relate to the outputs.
</p>
<h3 id="18b682600e5a4d1baf542b0cd1dcda7f">
Additive extensibility <a href="#18b682600e5a4d1baf542b0cd1dcda7f">#</a>
</h3>
<p>
This really shouldn't surprise us. Most programming languages come with all sorts of facilities that enable <em>extensibility</em>: The ability to <em>add</em> more functionality, more behaviour, more capabilities, to existing building blocks. Conversely, few languages come with <em>removability</em> facilities. You can't, commonly, declare that an object is an instance of a class, <em>except</em> one method, or that a function is just like another function, <em>except</em> that it doesn't accept a particular subset of input.
</p>
<p>
This explains why we can safely make a conservative function liberal, but why it's difficult to make a liberal function conservative. This is because making a conservative function liberal <em>adds</em> functionality, while making a liberal function conservative attempts to remove functionality.
</p>
<h3 id="6545430a4e1f47a38e121aee1a342b40">
Conjecture <a href="#6545430a4e1f47a38e121aee1a342b40">#</a>
</h3>
<p>
All this leads me to the following conjecture: When faced with a choice between two versions of an API, where one has a liberal domain, and the other a conservative codomain, choose the design with the conservative codomain.
</p>
<p>
If you need the liberal version, you can create it from the conservative operation. The converse need not be true.
</p>
<h3 id="312f8f4df0c44390a43f4f0f92d2c9d6">
Conclusion <a href="#312f8f4df0c44390a43f4f0f92d2c9d6">#</a>
</h3>
<p>
Postel's law encourages us to be liberal with what we accept, but conservative with what we return. This is a good design heuristic, but sometimes you're faced with mutually exclusive alternatives. If you're liberal with what you accept, you'll also need to be too loose with what you return, because there are input values that you can't handle. On the other hand, sometimes the only way to be conservative with the output is to also be restrictive when it comes to input.
</p>
<p>
Given two such alternatives, which one should you choose?
</p>
<p>
This article conjectures that you should choose the conservative alternative. This isn't a political statement, but simply a result of the conservative design being the smaller building block. From a small building block, you can compose something bigger, whereas from a bigger unit, you can't easily extract something smaller that's still robust and useful.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Service compatibility is determined based on policyhttps://blog.ploeh.dk/2024/04/29/service-compatibility-is-determined-based-on-policy2024-04-29T11:12:00+00:00Mark Seemann
<div id="post">
<p>
<em>A reading of the fourth Don Box tenet, with some commentary.</em>
</p>
<p>
This article is part of a series titled <a href="/2024/03/04/the-four-tenets-of-soa-revisited">The four tenets of SOA revisited</a>. In each of these articles, I'll pull one of <a href="https://en.wikipedia.org/wiki/Don_Box">Don Box</a>'s <em>four tenets of service-oriented architecture</em> (SOA) out of the <a href="https://learn.microsoft.com/en-us/archive/msdn-magazine/2004/january/a-guide-to-developing-and-running-connected-systems-with-indigo">original MSDN Magazine article</a> and add some of my own commentary. If you're curious why I do that, I cover that in the introductory article.
</p>
<p>
In this article, I'll go over the fourth tenet, quoting from the MSDN Magazine article unless otherwise indicated.
</p>
<h3 id="57382e74449c40409a7d73d91bc5fd14">
Service compatibility is determined based on policy <a href="#57382e74449c40409a7d73d91bc5fd14">#</a>
</h3>
<p>
The fourth tenet is the forgotten one. I could rarely remember exactly what it included, but it does give me an opportunity to bring up a few points about compatibility. The articles said:
</p>
<blockquote>
<p>
Object-oriented designs often confuse structural compatibility with semantic compatibility. Service-orientation deals with these two axes separately. Structural compatibility is based on contract and schema and can be validated (if not enforced) by machine-based techniques (such as packet-sniffing, validating firewalls). Semantic compatibility is based on explicit statements of capabilities and requirements in the form of policy.
</p>
<p>
Every service advertises its capabilities and requirements in the form of a machine-readable policy expression. Policy expressions indicate which conditions and guarantees (called assertions) must hold true to enable the normal operation of the service. Policy assertions are identified by a stable and globally unique name whose meaning is consistent in time and space no matter which service the assertion is applied to. Policy assertions may also have parameters that qualify the exact interpretation of the assertion. Individual policy assertions are opaque to the system at large, which enables implementations to apply simple propositional logic to determine service compatibility.
</p>
</blockquote>
<p>
As you can tell, this description is the shortest of the four. This is also the point where I begin to suspect that my reading of <a href="/2024/04/15/services-share-schema-and-contract-not-class">the third tenet</a> may deviate from what Don Box originally had in mind.
</p>
<p>
This tenet is also the most baffling to me. As I understand it, the motivation behind the four tenets was to describe assumptions about the kind of systems that people would develop with <a href="https://en.wikipedia.org/wiki/Windows_Communication_Foundation">Windows Communication Foundation</a> (WCF), or <a href="https://en.wikipedia.org/wiki/SOAP">SOAP</a> in general.
</p>
<p>
While I worked with WCF for a decade, the above description doesn't ring a bell. Reading it now, the description of <em>policy</em> sounds more like a system such as <a href="https://clojure.org/about/spec">clojure.spec</a>, although that's not something I know much about either. I don't recall WCF ever having a machine-readable policy subsystem, and if it had, I never encountered it.
</p>
<p>
It does seem, however, as though what I interpret as <em>contract</em>, Don Box called <em>policy</em>.
</p>
<p>
Despite my confusion, the word <em>compatibility</em> is worth discussing, regardless of whether that was what Don Box meant. A well-designed service is one where you've explicitly considered forwards and backwards compatibility.
</p>
<h3 id="77bf7878d5304ba08f686cbfbc6cb941">
Versioning <a href="#77bf7878d5304ba08f686cbfbc6cb941">#</a>
</h3>
<p>
Planning for forwards and backwards compatibility does <em>not</em> imply that you're expected to be able to predict the future. It's fine if you have so much experience developing and maintaining online systems that you may have enough foresight to plan for certain likely changes that you may have to make in the future, but that's not what I have in mind.
</p>
<p>
Rather, what you <em>should</em> do is to have a system that enables you to detect breaking changes before you deploy them. Furthermore you should have a strategy for how to deal with the perceived necessity to introduce breaking changes.
</p>
<p>
The most effective strategy that I know of is to employ explicit versioning, particularly <em>message versioning</em>. You <em>can</em> version an entire service as one indivisible block, but I often find it more useful to version at the message level. If you're designing a <a href="https://en.wikipedia.org/wiki/REST">REST</a> API, for example, you can <a href="/2015/06/22/rest-implies-content-negotiation">take advantage of Content Negotiation</a>.
</p>
<p>
If you like, you can use <a href="https://semver.org/">Semantic Versioning</a> as a versioning scheme, but for services, the thing that mostly matters is the major version. Thus, you may simply label your messages with the version numbers <em>1</em>, <em>2</em>, etc.
</p>
<p>
If you already have a published service without explicit message version information, then you can still retrofit versioning afterwards. <a href="/2023/12/04/serialization-with-and-without-reflection">Imagine that your existing data looks like this</a>:
</p>
<p>
<pre>{
<span style="color:#2e75b6;">"singleTable"</span>: {
<span style="color:#2e75b6;">"capacity"</span>: 16,
<span style="color:#2e75b6;">"minimalReservation"</span>: 10
}
}</pre>
</p>
<p>
This <a href="https://json.org/">JSON</a> document has no explicit version information, but you can interpret that as implying that the document has the 'default' version, which is always <em>1:</em>
</p>
<p>
<pre>{
<span style="color:#2e75b6;">"singleTable"</span>: {
<span style="color:#2e75b6;">"version"</span>: 1,
<span style="color:#2e75b6;">"capacity"</span>: 16,
<span style="color:#2e75b6;">"minimalReservation"</span>: 10
}
}</pre>
</p>
<p>
If you later realize that you need to make a breaking change, you can do that by increasing the (major) version:
</p>
<p>
<pre>{
<span style="color:#2e75b6;">"singleTable"</span>: {
<span style="color:#2e75b6;">"version"</span>: 2,
<span style="color:#2e75b6;">"id"</span>: 12,
<span style="color:#2e75b6;">"capacity"</span>: 16,
<span style="color:#2e75b6;">"minimalReservation"</span>: 10
}
}</pre>
</p>
<p>
Recipients can now look for the <code>version</code> property to learn how to interpret the rest of the message, and failing to find it, infer that this is version <em>1</em>.
</p>
<p>
As Don Box wrote, in a service-oriented system, you can't just update all systems in a single coordinated release. Therefore, you must never break compatibility. Versioning enables you to move forward in a way that does break with the past, but without breaking existing clients.
</p>
<p>
Ultimately, you <a href="/2020/06/01/retiring-old-service-versions">may attempt to retire old service versions</a>, but be ready to keep them around for a long time.
</p>
<p>
For more of my thoughts about backwards compatibility, see <a href="/2021/12/13/backwards-compatibility-as-a-profunctor">Backwards compatibility as a profunctor</a>.
</p>
<h3 id="ad9cec4f54c243d08fc71d38ff13ac17">
Conclusion <a href="#ad9cec4f54c243d08fc71d38ff13ac17">#</a>
</h3>
<p>
The fourth tenet is the most nebulous, and I wonder if it was ever implemented. If it was, I'm not aware of it. Even so, compatibility is an important component of service design, so I took the opportunity to write about that. In most cases, it pays to think explicitly about message versioning.
</p>
<p>
I have the impression that Don Box had something in mind more akin to what I call <em>contract</em>. Whether you call it one thing or another, it stands to reason that you often need to attach extra rules to simple types. The <em>schema</em> may define an input value as a number, but the service does require that this particular number is a natural number. Or that a string is really a <a href="https://en.wikipedia.org/wiki/ISO_8601">proper encoding</a> of a date. Perhaps you call that <em>policy</em>. I call it <em>contract</em>. In any case, clearly communicating such expectations is important for systems to be compatible.
</p>
</div><hr>
This blog is totally free, but if you like it, please consider <a href="https://blog.ploeh.dk/support">supporting it</a>.Fitting a polynomial to a set of pointshttps://blog.ploeh.dk/2024/04/22/fitting-a-polynomial-to-a-set-of-points2024-04-22T05:35:00+00:00Mark Seemann
<div id="post">
<p>
<em>The story of a fiasco.</em>
</p>
<p>
This is the second in a small series of articles titled <a href="/2024/04/01/trying-to-fit-the-hype-cycle">Trying to fit the hype cycle</a>. In the introduction, I've described the exercise I had in mind: Determining a formula, or at least a <a href="https://en.wikipedia.org/wiki/Piecewise">piecewise</a> <a href="https://en.wikipedia.org/wiki/Function_(mathematics)">function</a>, for the <a href="https://en.wikipedia.org/wiki/Gartner_hype_cycle">Gartner hype cycle</a>. This, to be clear, is an entirely frivolous exercise with little practical application.
</p>
<p>
In the previous article, I <a href="/2024/04/08/extracting-curve-coordinates-from-a-bitmap">extracted a set of <em>(x, y)</em> coordinates from a bitmap</a>. In this article, I'll showcase my failed attempt at fitting the data to a <a href="https://en.wikipedia.org/wiki/Polynomial">polynomial</a>.
</p>
<h3 id="36f71204d90b44a8b39a7d8103f46cca">
Failure <a href="#36f71204d90b44a8b39a7d8103f46cca">#</a>
</h3>
<p>
I've already revealed that I failed to accomplish what I set out to do. Why should you read on, then?
</p>
<p>
You don't have to, and I can't predict the many reasons my readers have for occasionally swinging by. Therefore, I can't tell you why <em>you</em> should keep reading, but I <em>can</em> tell you why I'm writing this article.
</p>
<p>
This blog is a mix of articles that I write because readers ask me interesting questions, and partly, it's my personal research-and-development log. In that mode, I write about things that I've learned, and I write in order to learn. One can learn from failure as well as from success.
</p>
<p>
I'm not <em>that</em> connected to 'the' research community (if such a thing exists), but I'm getting the sense that there's a general tendency in academia that researchers rarely publish their negative results. This could be a problem, because this means that the rest of us never learn about the <em>thousands of ways that don't work</em>.
</p>
<p>
Additionally, in 'the' programming community, we also tend to boast our victories and hide our failures. More than one podcast (sorry about the <a href="https://en.wikipedia.org/wiki/Weasel_word">weasel words</a>, but I don't remember which ones) have discussed how this gives young programmers the wrong impression of what programming is like. It is, indeed, a process of much trial and error, but usually, we only publish our polished, final result.
</p>
<p>
Well, I did manage to produce code to fit a polynomial to the Gartner hype cycle, but I never managed to get a <em>good</em> fit.
</p>
<h3 id="34ad323fc07f48709fb86c4045bd5892">
The big picture <a href="#34ad323fc07f48709fb86c4045bd5892">#</a>
</h3>
<p>
I realize that I have a habit of burying the lede when I write technical articles. I don't know if I've picked up that tendency from <a href="https://fsharp.org/">F#</a>, which does demand that you define a value or function before you can use it. This, by the way, <a href="/2015/04/15/c-will-eventually-get-all-f-features-right">is a good feature</a>.
</p>
<p>
Here, I'll try to do it the other way around, and start with the big picture:
</p>
<p>
<pre>data = numpy.loadtxt(<span style="color:#a31515;">'coords.txt'</span>, delimiter=<span style="color:#a31515;">','</span>)
x = data[:, 0]
t = data[:, 1]
w = fit_polynomial(x, t, 9)
plot_fit(x, t, w)</pre>
</p>
<p>
This, by the way, is a <a href="https://www.python.org/">Python</a> script, and it opens with these imports:
</p>
<p>
<pre><span style="color:blue;">import</span> numpy
<span style="color:blue;">import</span> matplotlib.pyplot <span style="color:blue;">as</span> plt</pre>
</p>
<p>
The first line of code reads the <a href="https://en.wikipedia.org/wiki/Comma-separated_values">CSV</a> file into the <code>data</code> variable. The first column in that file contains all the <em>x</em> values, and the second column the <em>y</em> values. <a href="/ref/rogers-girolami">The book</a> that I've been following uses <em>t</em> for the data, rather than <em>y</em>. (Now that I think about it, I believe that this may only be because it works from an example in which the data to be fitted are <a href="https://en.wikipedia.org/wiki/100_metres">100 m dash</a> times, denoted <em>t</em>.)
</p>
<p>
Once the script has extracted the data, it calls the <code>fit_polynomial</code> function to produce a set of weights <code>w</code>. The constant <code>9</code> is the degree of polynomial to fit, although I think that I've made an off-by-one error so that the result is only a eighth-degree polynomial.
</p>
<p>
Finally, the code plots the original data together with the polynomial:
</p>
<p>
<img src="/content/binary/hype-8th-degree-poly.png" alt="Gartner hype cycle and a eighth-degree fitted polynomial.">
</p>
<p>
The green dots are the <em>(x, y)</em> coordinates that I extracted in the previous article, while the red curve is the fitted eighth-degree polynomial. Even though we're definitely in the realm of over-fitting, it doesn't reproduce the Gartner hype cycle.
</p>
<p>
I've even arrived at the value <code>9</code> after some trial and error. After all, I wasn't trying to do any real science here, so over-fitting is definitely allowed. Even so, <code>9</code> seems to be the best fit I can achieve. With lover values, like <code>8</code>, below, the curve deviates too much:
</p>
<p>
<img src="/content/binary/hype-7th-degree-poly.png" alt="Gartner hype cycle and a seventh-degree fitted polynomial.">
</p>
<p>
The value <code>10</code> looks much like <code>9</code>, but above that (<code>11</code>), the curve completely disconnects from the data, it seems:
</p>
<p>
<img src="/content/binary/hype-10th-degree-poly.png" alt="Gartner hype cycle and a tenth-degree fitted polynomial.">
</p>
<p>
I'm not sure why it does this, to be honest. I would have thought that the more degrees you added, the more (over-)fitted the curve would be. Apparently, this is not so, or perhaps I made a mistake in my code.
</p>
<h3 id="183834d3c95544d9a185b5ba84bba9a1">
Calculating the weights <a href="#183834d3c95544d9a185b5ba84bba9a1">#</a>
</h3>
<p>
The <code>fit_polynomial</code> function calculates the polynomial coefficients using a <a href="https://en.wikipedia.org/wiki/Linear_algebra">linear algebra</a> formula that I've found in at least two text books. Numpy makes it easy to invert, transpose, and multiply matrices, so the formula itself is just a one-liner. Here it is in the entire context of the function, though:
</p>
<p>
<pre><span style="color:blue;">def</span> <span style="color:#2b91af;">fit_polynomial</span>(x, t, degree):
<span style="color:#a31515;">"""
Fits a polynomial to the given data.
Parameters
----------
x : Array of shape [n_samples]
t : Array of shape [n_samples]
degree : degree of the polynomial
Returns
-------
w : Array of shape [degree + 1]
"""</span>
<span style="color:green;"># This expansion creates a matrix, so we name that with an upper-case letter</span>
<span style="color:green;"># rather than a lower-case letter, which is used for vectors.</span>
X = expand(x.reshape((<span style="color:blue;">len</span>(x), 1)), degree)
<span style="color:blue;">return</span> numpy.linalg.inv(X.T @ X) @ X.T @ t</pre>
</p>
<p>
This may look daunting, but is really just two lines of code. The rest is <a href="https://en.wikipedia.org/wiki/Docstring">docstring</a> and a comment.
</p>
<p>
The above-mentioned formula is the last line of code. The one before that expands the input data <code>t</code> from a simple one-dimensional array to a matrix of those values squared, cubed, etc. That's how you use the <a href="https://en.wikipedia.org/wiki/Least_squares">least squares</a> method if you want to fit it to a polynomial of arbitrary degree.
</p>
<h3 id="782c5cbd64de43878eea4a3ddfcdf755">
Expansion <a href="#782c5cbd64de43878eea4a3ddfcdf755">#</a>
</h3>
<p>
The <code>expand</code> function looks like this:
</p>
<p>
<pre><span style="color:blue;">def</span> <span style="color:#2b91af;">expand</span>(x, degree):
<span style="color:#a31515;">"""
Expands the given array to polynomial elements of the given degree.
Parameters
----------
x : Array of shape [n_samples, 1]
degree : degree of the polynomial
Returns
-------
Xp : Array of shape [n_samples, degree + 1]
"""</span>
Xp = numpy.ones((<span style="color:blue;">len</span>(x), 1))
<span style="color:blue;">for</span> i <span style="color:blue;">in</span> <span style="color:blue;">range</span>(1, degree + 1):
Xp = numpy.hstack((Xp, numpy.power(x, i)))
<span style="color:blue;">return</span> Xp</pre>
</p>
<p>
The function begins by creating a column vector of ones, here illustrated with only three rows:
</p>