ploeh blog https://blog.ploeh.dk danish software design en-us Mark Seemann Tue, 13 Jan 2026 06:21:50 UTC Tue, 13 Jan 2026 06:21:50 UTC Two regimes of Git https://blog.ploeh.dk/2026/01/12/two-regimes-of-git/ Mon, 12 Jan 2026 08:23:00 UTC <div id="post"> <p> <em>Using Git for CI is not the same as Tactical Git.</em> </p> <p> <a href="https://git-scm.com/">Git</a> is such a versatile tool that when discussing it, interlocutors may often talk past each other. One person's use is so different from the way the next person uses it that every discussion is fraught with risk of misunderstandings. This happens to me a lot, because I use Git in two radically different ways, depending on context. </p> <p> Should you rebase? Merge? Squash? Cherry-pick? </p> <p> Often, being more explicit about a context can help address confusion. </p> <p> I know of at least two ways of using Git that differ so much from each other that I think we may term them two different regimes. The rules I follow in one regime don't all apply in the other, and vice versa. </p> <p> In this article I'll describe both regimes. </p> <h3 id="d0a8a4be292646719815e959011a0e9d"> Collaboration <a href="#d0a8a4be292646719815e959011a0e9d">#</a> </h3> <p> Most people use Git because it facilitates collaboration. Like other source-control systems, it's a way to share a code base with coworkers, or open-source contributors. <a href="https://en.wikipedia.org/wiki/Continuous_integration">Continuous Integration</a> is a subset in this category, and to my knowledge still the best way to collaborate. </p> <p> When I work in this regime, I follow one dominant rule: Once history is shared with others, it should be considered immutable. When you push to a shared instance of the repository, other people may pull your changes. Changing the history after having shared it is going to confuse most Git clients. It's much easier to abstain from editing shared history. </p> <p> What if you shared something that contains an error? Then fix the error and push that update, too. Sometimes, you can use <a href="https://git-scm.com/docs/git-revert">git revert</a> for this. </p> <p> A special case is reserved for mistakes that involve leaking security-sensitive data. If you accidentally share a password, a revert doesn't rectify the problem. The data is still in the history, so this is a singular case where I know of no better remedy than rewriting history. That is, however, quite bothersome, because you now need to communicate to every other collaborator that this is going to happen, and that they may be best off making a new clone of the repository. If there's a better way to address such situations, I don't know of it, but would be happy to learn. </p> <p> Another consequence of the Collaboration regime follows from the way pull requests are typically implemented. In GitHub, sending a pull request is a two-step process: First you push a branch, and then you click a button to send the pull request. I usually use the GitHub web user interface to review my own pull-request branch before pushing the button. Occasionally I spot an error. At this point I consider the branch 'unshared', so I may decide to rewrite the history of that branch and force-push it. Once, however, I've clicked the button and sent the pull request, I consider the branch shared, and the same rules apply: Rewriting history is not allowed. </p> <p> One implication of this is that the set of Git actions you need to know is small: You can effectively get by with <a href="https://git-scm.com/docs/git-add">git add</a>, <a href="https://git-scm.com/docs/git-commit">commit</a>, <a href="https://git-scm.com/docs/git-pull">pull</a>, <a href="https://git-scm.com/docs/git-push">push</a>, and possibly a few more. </p> <p> Many of the 'advanced' Git features, such as <a href="https://git-scm.com/docs/git-rebase">rebase</a> and squash, allow you to rewrite history, so aren't allowed in this regime. </p> <h3 id="513088e0595e493a94a6aa96fa0ae92d"> Tactical Git <a href="#513088e0595e493a94a6aa96fa0ae92d">#</a> </h3> <p> As far as I can tell, Git wasn't originally created for this second use case, but it turns out that it's incredibly useful for local management of code files. This is what I've previously described as <a href="https://stackoverflow.blog/2022/12/19/use-git-tactically/">Tactical Git</a>. </p> <p> Once you realize that you have a version-control system at your fingertips, the opportunities are manifold. You can perform experiments in a branch that only exists on your machine. You may, for example, test alternative API design ideas, implementations, etc. There's no reason to litter the code base with commented-out code because you're afraid that you'll need something later. Just commit it on a local branch. If it later turns out that the experiment didn't turn out to your liking, commit it anyway, but then check out <code>master</code>. You'll leave the experiment on your local machine, and it's there if you need it later. </p> <p> You can even used failed experiments as evidence that a particular idea has undesirable consequences. Have you ever been in a situation where a coworker suggests a new way of doing things. You may have previously responded that you've already tried that, and it didn't work. How well did that answer go over with your coworker? </p> <p> He or she probably wasn't convinced. </p> <p> What if, however, you've <em>kept that experiment on your own machine?</em> Now you can say: "Not only have I already tried this, but I'm happy to share the relevant branch with you." </p> <p> You can see an example of that in listing 8.10 in <a href="/2021/06/14/new-book-code-that-fits-in-your-head">Code That Fits in Your Head</a>. This code listing is based on a side-branch never merged into <code>master</code>. If you have the book, you also have access to the entire Git repository, and you can check for yourself that commit <code>0bb8068</code> is a dead-end branch named <code>explode-maitre-d-arguments</code>. </p> <p> Under the Tactical Git regime, you can also go back and edit mistakes when working on code that you haven't yet shared. I use <a href="https://www.industriallogic.com/blog/whats-this-about-micro-commits/">micro-commits</a>, so I tend to check in small commits often. Sometimes, as I'm working with the code, I notice that I made a mistake a few commits ago. Since I'm a neat freak, I often use interactive rebase to go back and correct my mistakes before sharing the history with anyone else. I don't do that to look perfect, but rather to leave behind a legible trail of changes. If I already know that I made a mistake before I've shared my code with anyone else, there's no reason to burden others with both the mistake and its rectification. </p> <p> In general, I aim to leave as nice a Git history as possible. This is not only for my collaborators' sake, but for my own, too. Legible Git histories and micro-commits make it easier to troubleshoot later, as <a href="/2020/10/05/fortunately-i-dont-squash-my-commits">this story demonstrates</a>. </p> <p> The toolset useful for Tactical Git is different than for collaboration. You still use <code>add</code> and <code>commit</code>, of course, but I also use (interactive) <code>rebase</code> often, as well as <a href="https://git-scm.com/docs/git-stash">stash</a> and <a href="https://git-scm.com/docs/git-branch">branch</a>. Only rarely do I need <a href="https://git-scm.com/docs/git-cherry-pick">cherry-pick</a>, but it's useful when I do need it. </p> <h3 id="47b93db51f6a422296ebbd3fb0439401"> Conclusion <a href="#47b93db51f6a422296ebbd3fb0439401">#</a> </h3> <p> When discussing good Git practices, it's easy to misunderstand each other because there's more than one way to use Git. I know of at least two radically different modes: Collaboration and Tactical Git. The rules that apply under the Collaboration regime should not all be followed slavishly when in the Tactical Git regime. Specifically, the rule about rewriting history is almost turned on its head. Under the Collaboration regime, do not rewrite Git history; under the Tactical Git regime, rewriting history is encouraged. </p> </div> <div id="comments"> <hr> <h2 id="comments-header"> Comments </h2> <div class="comment" id="b4e8f2a1d6c94e3a7b5f9d2c8e1a4f6b"> <div class="comment-author">Carlos Schults <a href="#b4e8f2a1d6c94e3a7b5f9d2c8e1a4f6b">#</a></div> <div class="comment-content"> <p> Hi, Mark. Thanks for the article. Regarding the issue of secrets being added to the soure code, wouldn't it be better to rotate the secrets (i.e, change the password, revoke the API key, etc), instead of changing shared history? Unless that can't be done for some reason, of course. </p> </div> <div class="comment-date">2026-01-12 16:52 UTC</div> </div> <div class="comment" id="3aeed7b08dc244f2976333678c664f1a"> <div class="comment-author"><a href="/">Mark Seemann</a> <a href="#3aeed7b08dc244f2976333678c664f1a">#</a></div> <div class="comment-content"> <p> Thank you for writing. Honestly, that option hadn't crossed my mind, but whenever possible, that sounds like the best alternative. </p> </div> <div class="comment-date">2026-01-13 06: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>. Mark Seemann https://blog.ploeh.dk/2026/01/12/two-regimes-of-git Coupling from a big-O perspective https://blog.ploeh.dk/2026/01/05/coupling-from-a-big-o-perspective/ Mon, 05 Jan 2026 11:45:00 UTC <div id="post"> <p> <em>Don't repeat yourself (DRY) implies O(1) edits.</em> </p> <p> Here's a half-baked idea: We may view coupling in software through the lens of <a href="https://en.wikipedia.org/wiki/Big_O_notation">big-O notation</a>. Since this isn't yet a fully-formed idea of mine, this is one of those articles I write in order to learn from the process of having to formulate the idea to other people. </p> <h3 id="27a38591f54342e9845fe2e67fa2b893"> Widening the scope of big-O analysis <a href="#27a38591f54342e9845fe2e67fa2b893">#</a> </h3> <p> Big-O analysis is usually described in terms of functions on ℝ (the real numbers), such as O(n), O(lg n), O(n<sup>3</sup>), O(2<sup>n</sup>) and so on. This is somewhat ironic because when analysing algorithm efficiency, <em>n</em> is usually an integer (i.e. <em>n</em> ∈ ℕ). That, however, suits me fine, because it establishes precedence for what I have in mind. </p> <p> Usually, big-O analysis is applied to algorithms, and usually by measuring an abstract notion of an 'instruction step'. You can, however, also apply such analysis to other aspects of resource utilization. Even within the confines of algorithm analysis, you may instead of instruction count be concerned with memory consumption. In other words, you may analyze an algorithm in order to determine that it uses O(n<sup>2</sup>) memory. </p> <p> With that in mind, nothing prevents you from widening the scope further. While I tend to be disinterested in the small-scale performance optimizations involved with algorithms, I have a keen eye on how it applies to software architecture. In modern computers, CPU cycles are fast, but network hops are still noticeable to human perception. For example, the well-known <em>n+1 problem</em> really just implies O(n) network calls. Given that a single network hop may already (depending on topology and distance) be observable, even moderate numbers of <em>n</em> (e.g. 100) may be a problem. </p> <p> What I have in mind for this article is to once more transplant the thinking behind big-O notation to a new area. Instead of instructions or network calls, let O(...) indicate the number of edits you have to make in a code base in order to make a change. If we want to be more practical about it, we may measure this number in how many methods or functions we need to edit, or, even more coarsely, the number of files we need to change. </p> <h3 id="09584e8476bd4ef39a204a8069c12d0e"> Don't Repeat Yourself <a href="#09584e8476bd4ef39a204a8069c12d0e">#</a> </h3> <p> In this view, the old <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY principle</a> implies O(1) edits. You create a single point in your code base responsible for a given behaviour. If you need to make changes, you edit a single part of the code base. This seems obvious. </p> <p> What the big-O perspective implies, however, is that a small constant number of edits may be fine, too. For instance, 'dual' coupling, where two code blocks change together, is not that uncommon. This could for example be where you model messages on an internal queue. Every time you add a new message type, you'll need to define both how to send it (i.e. what data it contains and how it serializes) and how to handle it. If you are using a statically typed language, you can use a <a href="https://en.wikipedia.org/wiki/Tagged_union">sum type</a> or <a href="https://en.wikipedia.org/wiki/Visitor_pattern">Visitor</a> to keep track of all message types, which means that the type checker will remind you if you forget one or the other. </p> <p> In big-O notation, we simplify all constants to <em>1</em>, so even if you have systematic, but constant, coupling like this, we would still consider it O(1). In other words, if your architecture contains <em>some</em> coupling that remains constant, we may deem it O(1) and perhaps benign. </p> <p> This also suggests why we have a heuristic like the <a href="https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)">rule of three</a>. Dual duplication is still O(1), and as long as the coupling stays constant, there's no evidence that it's growing. Once you make the third copy does evidence begin to suggest that the coupling is O(n) rather than O(1). </p> <h3 id="e0f1270bc4b24a97bc373f61052011dd"> Small values of 1 <a href="#e0f1270bc4b24a97bc373f61052011dd">#</a> </h3> <p> Big-O notation is concerned with comparing orders of magnitude, which is why specific constants are simplified to <em>1</em>. The number <em>1</em> is a stand-in for any constant value, <em>1</em>, <em>2</em>, <em>10</em>, og even six billion. When editing source code, however, the actual number of edits does matter. In the following sections, I'll give concrete examples where '1' is small. </p> <h3 id="4020dbeed059499e9d345d3657a57e2f"> Test-specific equality <a href="#4020dbeed059499e9d345d3657a57e2f">#</a> </h3> <p> The first example we may consider is <a href="http://xunitpatterns.com/test-specific%20equality.html">test-specific equality</a>. My <a href="/2010/06/29/IntroducingAutoFixtureLikeness">first treatment</a> related to this topic was in 2010, and <a href="/2012/06/21/TheResemblanceidiom">again in 2012</a>. Since then, I've come to view the need for test-specific equality as a test smell. If you are doing test-driven development (which you <a href="/2025/10/20/epistemology-of-software">chiefly should</a>), giving your objects or values <a href="/2021/05/03/structural-equality-for-better-tests">sane equality semantics makes testing much easier</a>. And a well-known benefit of test-driven development (TDD) is that <a href="/2011/11/10/TDDimprovesreusability">code that is easy to test is easy to use</a>. </p> <p> Still, if you must work with mutable objects (as in naive object-oriented design), you can't give objects structural equality. And as I recently rediscovered, functional programming doesn't entirely shield you from this kind of problem either. Functions, for example, don't have clear equality semantics in practice, so when bundling data and behaviour (does that <a href="/2018/01/22/function-isomorphisms">sound familiar</a>?), data structures can't have structural equality. </p> <p> Still, TDD suggests that you should reconsider your API design when that happens. Sometimes, however, part of an API is locked. I recently described such a situation, which prompted me to write <a href="/2025/12/22/test-specific-eq">test-specific Eq instances</a>. In short, the <a href="https://www.haskell.org/">Haskell</a> data type <code>Finch</code> was not an <code>Eq</code> instance, so I added this test-specific data type to improve testability: </p> <p> <pre><span style="color:blue;">data</span>&nbsp;FinchEq&nbsp;=&nbsp;FinchEq &nbsp;&nbsp;{&nbsp;feqID&nbsp;::&nbsp;Int &nbsp;&nbsp;,&nbsp;feqHP&nbsp;::&nbsp;Galapagos.HP &nbsp;&nbsp;,&nbsp;feqRoundsLeft&nbsp;::&nbsp;Galapagos.Rounds &nbsp;&nbsp;,&nbsp;feqColour&nbsp;::&nbsp;Galapagos.Colour &nbsp;&nbsp;,&nbsp;feqStrategyExp&nbsp;::&nbsp;Exp&nbsp;} &nbsp;&nbsp;<span style="color:blue;">deriving</span>&nbsp;(<span style="color:#2b91af;">Eq</span>,&nbsp;<span style="color:#2b91af;">Show</span>)</pre> </p> <p> Later, I also introduced a second test-specific data structure, <code>CellStateEq</code> to address the equivalent problem that <code>CellState</code> isn't an <code>Eq</code> instance. This means that I have two representations of essentially the same kind of data. If I, much later, learn that I need to add, remove, or modify a field of, say, <code>Finch</code>, I would also need to edit <code>FinchEq</code>. </p> <p> There's a clear edit-time coupling with constant value <em>2</em>. When I edit one, I also need to edit the other. In big-O perspective, we could say that the specific value of <em>1</em> is <em>2</em>, or <em>1~2</em>, and so the edits required to maintain this part of the code base is of the order O(1). </p> <h3 id="fca4412f1ed3446694a8e027a1b2666d"> Maintaining Fake objects <a href="#fca4412f1ed3446694a8e027a1b2666d">#</a> </h3> <p> Another interesting example is the one that originally elicited this chain of thought. In <a href="/2025/09/15/greyscale-box-test-driven-development">Greyscale-box test-driven development</a> I showed an example of how using interactive white-box testing with <a href="http://xunitpatterns.com/Configurable%20Test%20Double.html#Dynamically%20Generated%20Test%20Double">Dynamically Generated Test Doubles</a> (AKA Dynamic Mocks) leads to <a href="http://xunitpatterns.com/Fragile%20Test.html">Fragile Tests</a>. More on this later, but I also described how using <a href="http://xunitpatterns.com/Fake%20Object.html">Fake Objects</a> and <a href="/2019/02/18/from-interaction-based-to-state-based-testing">state-based testing</a> doesn't have the same problem. </p> <p> In <a href="https://bsky.app/profile/ladeak.net/post/3lyvldkwf6c2h">a response on Bluesky</a> Laszlo (<a href="https://bsky.app/profile/ladeak.net">@ladeak.net</a>) pointed out that this seemed to imply a three-way coupling that I had, frankly, overlooked. </p> <p> You can review the full description of the example in the article <a href="/2025/09/15/greyscale-box-test-driven-development">Greyscale-box test-driven development</a>, but in summary it proceeds like this: We wish to modify an implementation detail related to how the system queries its database. Specifically, we wish to change an inclusive integer-based upper bound to an exclusive bound. Thus, we change the relevant part of the <a href="https://en.wikipedia.org/wiki/SQL">SQL</a> <code>WHERE</code> clause from </p> <p> <pre><span style="color:maroon;">@Min&nbsp;&lt;=&nbsp;[At]&nbsp;AND&nbsp;[At]&nbsp;&lt;=&nbsp;@Max&quot;</span></pre> </p> <p> to </p> <p> <pre><span style="color:maroon;">@Min&nbsp;&lt;=&nbsp;[At]&nbsp;AND&nbsp;[At]&nbsp;&lt;&nbsp;@Max&quot;</span></pre> </p> <p> Specifically, the single-character edit removes <code>=</code> from the rightmost <code>&lt;=</code>. </p> <p> Since this modification changes the implied contract, we also need to edit the calling code. That's another single-line edit that changes </p> <p> <pre><span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">max</span>&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">min</span>.<span style="font-weight:bold;color:#74531f;">AddDays</span>(1).<span style="font-weight:bold;color:#74531f;">AddTicks</span>(-1);</pre> </p> <p> to </p> <p> <pre><span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">max</span>&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">min</span>.<span style="font-weight:bold;color:#74531f;">AddDays</span>(1);</pre> </p> <p> What I had overlooked was that I should also have changed the single test-specific Fake object used for state-based testing. Since I changed the contract of the <code>IReservationsRepository</code> interface, and since <a href="/2023/11/13/fakes-are-test-doubles-with-contracts">Fakes are Test Doubles with contracts</a>, it follows that the <code>FakeDatabase</code> class must also change. </p> <p> This I had overlooked because no tests based on <code>FakeDatabase</code> failed. More on that in a future post, but the required edit is easy enough. Change </p> <p> <pre>.<span style="font-weight:bold;color:#74531f;">Where</span>(<span style="font-weight:bold;color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="font-weight:bold;color:#1f377f;">min</span>&nbsp;<span style="font-weight:bold;color:#74531f;">&lt;=</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">r</span>.At&nbsp;&amp;&amp;&nbsp;<span style="font-weight:bold;color:#1f377f;">r</span>.At&nbsp;<span style="font-weight:bold;color:#74531f;">&lt;=</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">max</span>).<span style="font-weight:bold;color:#74531f;">ToList</span>());</pre> </p> <p> to </p> <p> <pre>.<span style="font-weight:bold;color:#74531f;">Where</span>(<span style="font-weight:bold;color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="font-weight:bold;color:#1f377f;">min</span>&nbsp;<span style="font-weight:bold;color:#74531f;">&lt;=</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">r</span>.At&nbsp;&amp;&amp;&nbsp;<span style="font-weight:bold;color:#1f377f;">r</span>.At&nbsp;<span style="font-weight:bold;color:#74531f;">&lt;</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">max</span>).<span style="font-weight:bold;color:#74531f;">ToList</span>());</pre> </p> <p> Again, the edit involves deleting a single <code>=</code> character. </p> <p> <img src="/content/binary/three-way-dependency.png" alt="A box labelled 'Calling code' with arrows to two other boxes: One labelled FakeDatabase, and another labelled SqlReservationsRepository." width="500"> </p> <p> Still, in this example, not only two, but three files are coupled. With the perspective of big-O notation, however, we may say that <em>1~3</em>, and the order of edits required to maintain this part of the code base remains O(1). Later in this article, I will discuss the maintenance burden of dynamic mocks, which I consider to be O(n). Thus, even if I have a three-way coupling, I don't expect the coupling to grow over time. That's the point: I prefer O(1) over O(n). </p> <h3 id="8d57760e1eb94d01881585eefa6d0a71"> Large values of 1 <a href="#8d57760e1eb94d01881585eefa6d0a71">#</a> </h3> <p> As I'm sure practical programmers know, big-O notation has limitations. First, as <a href="https://doc.cat-v.org/bell_labs/pikestyle">Rob Pike observed</a>, "<em>n</em> is usually small". More germane to this discussion </p> <blockquote> <p> "algorithms have big constants." </p> <footer><cite><a href="https://doc.cat-v.org/bell_labs/pikestyle">Notes on Programming in C</a>, Rob Pike, 1989</cite></footer> </blockquote> <p> In this context, this implies that the constant we're deliberately ignoring when we label something O(1) could, in theory, be significant. We don't write O(2,000,000), but if we did, it would look like more, wouldn't it? Even if it doesn't depend on <em>n</em>. </p> <p> It looks to me that when we discuss source code edits, <em>5</em> or <em>6</em> could already be considered large. </p> <h3 id="aabab4ba51e245d289e78f11b446ea9b"> Layers <a href="#aabab4ba51e245d289e78f11b446ea9b">#</a> </h3> <p> Although software design thought leaders have denounced layered software architecture more than a decade ago, I don't entirely agree with that position. That, however, is a topic for a different article. In any case, I still regularly see examples of design that involves a <em>UI DTO</em>, a <em>Domain Model</em>, and a <em>Data Access layer</em>. </p> <p> As I enumerated in 2012, a simple operation, such as adding a <em>label</em> field, involves at least six steps. </p> <blockquote> <ol> <li>"A Label column must be added to the database schema and the DbTrack class.</li> <li>"A Label property must be added to the Track class.</li> <li>"The mapping from DbTrack to Track must be updated.</li> <li>"A Label property must be added to the TopTrackViewModel class.</li> <li>"The mapping from Track to TopTrackViewModel must be updated.</li> <li>"The UI must be updated."</li> </ol> <footer><cite><a href="/2012/02/09/IsLayeringWorththeMapping">Is Layering Worth the Mapping?</a>, 2012</cite></footer> </blockquote> <p> People often complain about all the seemingly redundant work involved with such layering, and I don't blame them. At least, if there's no clear motivation for a design like that, and no evident benefit, it looks like redundant work. While you can make good use of separating concerns across layers, that's outside the scope of this article. In the naive way most often employed, it seems like mindless ceremony. </p> <p> Even so, how would we denote the above enumeration in terms of big-O notation? Adding a <em>label</em> field is an O(1) edit. </p> <p> How so? Adding, changing, or deleting a field in a particular database table always entails the same number of steps (six) as outlined above. If, in addition to the Track table you want to add, say, an Album table, you create it according to the three-layer model. This again means that every edit of <em>that</em> table involves six steps. It's still O(1), with <em>1~6</em>, but already it hurts. </p> <p> Apparently, six may be a 'large constant'. </p> <h3 id="3e44a59d433c4b03acdff65a491c51ac"> Linear edits <a href="#3e44a59d433c4b03acdff65a491c51ac">#</a> </h3> <p> So far, we've exclusively examined multiple examples of O(1) edits. Some of them, particularly the layered-architecture example, may seem counterintuitive at first. If it requires editing six different 'blocks' of code to make a single change (not counting tests!) is still O(1), then does <em>anything</em> constitute O(n), or any other kind of relationship? </p> <p> To be realistic, I don't think we're in an analytical regime that allows us fine distinctions like identifying any kind of code organization to be, say O(lg n) or O(n lg n). On the other hand, examples of O(n) abound. </p> <p> Every time you run into the <a href="https://en.wikipedia.org/wiki/Shotgun_surgery">Shotgun Surgery</a> anti-pattern, you are looking at O(n) edits. As a simple example, consider poorly-factored logging, as for example shown initially in <a href="/2020/03/23/repeatable-execution">Repeatable execution</a>. In such situations, you have <em>n</em> classes that log. If you need to change how logging is done, you must change <em>n</em> classes. </p> <p> More generally, the main (unstated) goal of the DRY principle is to turn O(n) edits into O(1) edits. </p> <p> Every junior developer already knows this. Notwithstanding, there's a category of code where even senior programmers routinely forget this. </p> <h3 id="587527167f7c44be89d51536ccae34f6"> Linear test coupling <a href="#587527167f7c44be89d51536ccae34f6">#</a> </h3> <p> When it comes to automated testing, many developers treat test code stepmotherly. The most common mistake is the misguided notion that copy-and-paste code is fine in test code. <a href="/2025/12/01/treat-test-code-like-production-code">It's not</a>. Duplicated test code means that when you make a change in the System Under Test, <em>n</em> tests break, and you will have to fix each one individually, a clear O(n) edit (where <em>n</em> is the number of tests). </p> <p> A more subtle example of an O(n) test maintenance burden can be found in test code that uses dynamic mocks. When you use a configurable mock object, each test contains isolated configuration code related to that specific test. </p> <p> Let's look at an example. Consider the <a href="https://github.com/moq/moq4">Moq</a>-based tests from <a href="/2019/02/25/an-example-of-interaction-based-testing-in-c">An example of interaction-based testing in C#</a>. One test contains this <a href="https://xp123.com/3a-arrange-act-assert/">Assert</a> phase: </p> <p> <pre>readerTD &nbsp;&nbsp;&nbsp;&nbsp;.Setup(r&nbsp;=&gt;&nbsp;r.Lookup(user.Id.ToString())) &nbsp;&nbsp;&nbsp;&nbsp;.Returns(<span style="color:#2b91af;">Result</span>.Success&lt;<span style="color:#2b91af;">User</span>,&nbsp;<span style="color:#2b91af;">IUserLookupError</span>&gt;(user)); readerTD &nbsp;&nbsp;&nbsp;&nbsp;.Setup(r&nbsp;=&gt;&nbsp;r.Lookup(otherUser.Id.ToString())) &nbsp;&nbsp;&nbsp;&nbsp;.Returns(<span style="color:#2b91af;">Result</span>.Success&lt;<span style="color:#2b91af;">User</span>,&nbsp;<span style="color:#2b91af;">IUserLookupError</span>&gt;(otherUser));</pre> </p> <p> Another test arranges the same two <a href="https://martinfowler.com/bliki/TestDouble.html">Test Doubles</a>, but configures the second differently. </p> <p> <pre>readerTD &nbsp;&nbsp;&nbsp;&nbsp;.Setup(r&nbsp;=&gt;&nbsp;r.Lookup(user.Id.ToString())) &nbsp;&nbsp;&nbsp;&nbsp;.Returns(<span style="color:#2b91af;">Result</span>.Success&lt;<span style="color:#2b91af;">User</span>,&nbsp;<span style="color:#2b91af;">IUserLookupError</span>&gt;(user)); readerTD &nbsp;&nbsp;&nbsp;&nbsp;.Setup(r&nbsp;=&gt;&nbsp;r.Lookup(otherUserId)) &nbsp;&nbsp;&nbsp;&nbsp;.Returns(<span style="color:#2b91af;">Result</span>.Error&lt;<span style="color:#2b91af;">User</span>,&nbsp;<span style="color:#2b91af;">IUserLookupError</span>&gt;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">UserLookupError</span>.InvalidId));</pre> </p> <p> Yet more tests arrange the System Under Test (SUT) in other combinations. Refer to the article for the full example. </p> <p> Such tests don't contain duplication per se, but each test is coupled to the SUT's dependencies. When you change one of the interfaces, you break O(n) tests, and you have to fix each one individually. </p> <p> As suggested earlier in the article, this is the reason to favour Fake Objects. While an interface change may still break the tests, the effort to correct them is O(1) edits. </p> <h3 id="aecc149a7055454bae3e287fd5688c02"> Two kinds of coupling <a href="#aecc149a7055454bae3e287fd5688c02">#</a> </h3> <p> The big-O perspective on coupling suggests that there are two kinds of coupling: O(1) coupling and O(n) coupling. We can find duplication in both categories. </p> <p> In the O(1) case, duplication is somehow limited. It may be that you are following the rule of three. This allows two copies of a piece of code to exist. It may be that you've made a particular architectural decision, such as using Fake Objects for testing (triplication), or using layered architecture (sextuplication). In these cases, there's a fixed number of edits that you have to make, and in principle, you should know where to make them. </p> <p> I tend to be less concerned about this kind of coupling because it's manageable. In many cases, you may be able to lean on the compiler to guide you through the task of making a change. In other cases, you could have a checklist. Consider the above example of layered architecture. A checklist would enumerate the six separate steps you need to perform. Once you've checked off all six, you're done. </p> <p> It may be slow, tedious work, but it's generally safe, because you are unlikely to forget a spot. </p> <p> The O(n) case is where real trouble lies. This is the case when you copy and paste a snippet of code every time you need it somewhere new. When, later, you discover that there's a bug in the original 'source', you need to find all the places it occurs. Typical copy-paste code is often slightly modified after paste, so a naive search-and-replace strategy is likely to miss some instances. </p> <p> Of course, if you've copied a whole method, function, class, or module, you may still be able to find it by name, but if you've only copied an unnamed block of code, that will not work either. </p> <h3 id="9c636a02c64d4c14bb54a0425fc52f0c"> Not all edits are equally difficult <a href="#9c636a02c64d4c14bb54a0425fc52f0c">#</a> </h3> <p> To be fair, we should acknowledge that not all edit are equally difficult. There are kinds of changes you can automate. Most modern code editors come with refactoring support. In the case of testing with dynamic mocks, for example, you can rename methods, rearrange parameter lists, or remove a parameter. </p> <p> Even so, some edits are harder. Changing the return type of a method tends to break calling code in most <a href="/2019/12/16/zone-of-ceremony">high-ceremony languages</a>. Likewise, changing a primitive parameter (an integer, a Boolean, a string) to a complex object is non-trivial, as is adding a parameter with no obvious good default value. This is when O(n) coupling hurts. </p> <h3 id="d5b66e9ae9d1444e930554768d276e76"> Limitations <a href="#d5b66e9ae9d1444e930554768d276e76">#</a> </h3> <p> So far, we've considered O(1) and O(n) edits. Are there O(lg n) edits, O(n<sup>2</sup>), or even O(2<sup>n</sup>) edits? </p> <p> I can't rule it out, and if the reader can furnish some convincing examples, I'd be keen to learn about them. To be honest, though, I'm not sure it's that helpful. One could perhaps construe an example where inheritance creates a quadratic growth of subclasses, because someone is trying to model two independent features in a single inheritance tree. This, however, is just bad design, and we don't need the big-O lens to tell us that. </p> <h3 id="93726a996b024da48ae4ae861b52bc49"> Conclusion <a href="#93726a996b024da48ae4ae861b52bc49">#</a> </h3> <p> As a thought experiment, one may adopt big-O notation as a viewpoint on code organisation. This seems particularly valuable when distinguishing between benign and malignant duplication. Duplication usually entails coupling. For a 'code architect', one of the most important tasks is to reduce, or at least control, coupling. </p> <p> Some coupling is of the order O(1). Hidden in this notation is a constant, which may indicate that a change can be made with a single edit, two edits, six edits, and so on. Even if the actual number is 'large', you can put tools in place to minimize risk: A simple checklist may be enough, or perhaps you can leverage a static type system. </p> <p> Other coupling is of the order O(n). Here, a single change must be made in O(n) different places, where <em>n</em> tends to grow over time, and there's no clear way to systematically find and identify them all. This kind of coupling strikes me as more dangerous than O(1) coupling. </p> <p> When I sometimes seem to have a cavalier attitude to duplication, it's likely because I've already subconsciously identified a particular duplication as of the order O(1). </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>. Mark Seemann https://blog.ploeh.dk/2026/01/05/coupling-from-a-big-o-perspective Git integration is ten years away https://blog.ploeh.dk/2025/12/29/git-integration-is-ten-years-away/ Mon, 29 Dec 2025 09:03:00 UTC <div id="post"> <p> <em>We'll get commercial nuclear fusion earlier.</em> </p> <p> Although, as I've <a href="/2023/07/24/is-software-getting-worse">described earlier</a>, I tend to be conservative about updating my laptop, I tend to make exceptions for <a href="https://visualstudio.microsoft.com/">Visual Studio</a> and <a href="https://code.visualstudio.com/">Visual Studio Code</a>. I was recently perusing the "what's new" notes after updating one or the other, and among all the new AI capabilities that I'm not interested in, I noticed something else: 'improved Git integration.' </p> <p> As I reflected on that, a thought occurred to me. It seems to me that I've seen these update notes for at least a decade. Improved Git integration. </p> <p> I'm not even exaggerating. Git support for Visual Studio was <a href="https://www.hanselman.com/blog/git-support-for-visual-studio-git-tfs-and-vs-put-into-context">announced in 2013</a>. It has, indeed, been around for a long time, and I've been blissfully ignoring it throughout. Even so, it struck me when reading release notes in 2025, that the product in question had improved Git integration. </p> <p> Is it not done yet? </p> <p> Apparently not. </p> <p> It wasn't done ten years ago? Is there any reason to believe that it's done now? Or are we witnessing some reverse <a href="https://en.wikipedia.org/wiki/Lindy_effect">Lindy effect</a>? The longer something has been in development, the longer you may expect it to be in development yet? </p> <p> Sarcasm aside, you don't need Git integration in your development environment. Do yourself a favour and learn the <a href="/2024/05/20/fundamentals">fundamentals</a> of Git. It takes a few hours to learn the basics, a few days to become more comfortable with it, but from then, no 'integration' need hold you back. You don't have to wait for the next update. <a href="https://stackoverflow.blog/2022/12/19/use-git-tactically/">Use Git tactically</a> today. </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>. Mark Seemann https://blog.ploeh.dk/2025/12/29/git-integration-is-ten-years-away Test-specific Eq https://blog.ploeh.dk/2025/12/22/test-specific-eq/ Mon, 22 Dec 2025 08:15:00 UTC <div id="post"> <p> <em>Adding Eq instances for better assertions.</em> </p> <p> Most well-written unit tests follow some variation of the <a href="https://xp123.com/3a-arrange-act-assert/">Arrange Act Assert</a> pattern. In the Assert phase, you may write a sequence of assertions that verify different aspects of what 'success' means. Even so, it boils down to this: You check that the <em>expected</em> outcome is equal to the <em>actual</em> outcome. Some testing frameworks like to turn the order around, but the idea remains the same. After all, <a href="https://en.wikipedia.org/wiki/Symmetric_relation">equality is symmetric</a>. </p> <p> The ideal assertion is one that simply checks that <em>actual is equal to expected</em>. Some languages allow custom infix operators, in which case it's natural to define this fundamental assertion as an operator, such as <a href="https://hackage-content.haskell.org/package/tasty-hunit/docs/Test-Tasty-HUnit.html#v:-64--63--61-">@?=</a>. </p> <p> Since this is <a href="https://www.haskell.org/">Haskell</a>, however, the <code>@?=</code> operator comes with type constraints. Specifically, what we compare must be an <code>Eq</code> instance. In other words, the type in question must support the <code>==</code> operator. What do you do when a type is no <code>Eq</code> instance? </p> <h3 id="cd497aa35e354cddb387a4da5c0d65b2"> No Eq <a href="#cd497aa35e354cddb387a4da5c0d65b2">#</a> </h3> <p> In a recent article you saw how <a href="/2025/12/15/tautological-assertions-are-not-always-caused-by-aliasing">a complicated test induced a tautological assertion</a>. The main reason that the test was complicated was that the values involved were not <code>Eq</code> instances. </p> <p> This got me thinking: Might <a href="http://xunitpatterns.com/test-specific%20equality.html">test-specific equality</a> help? </p> <p> The easiest way to find out is to try. In this article, you'll see how that experiment turns out. First, however, you need a quick introduction to the problem space. The task at hand was to implement a <a href="https://en.wikipedia.org/wiki/Cellular_automaton">cellular automaton</a>, ostensibly modelling <a href="https://en.wikipedia.org/wiki/Darwin%27s_finches">Galápagos finches</a> meeting. When two finches encounter each other, they play out a game of <a href="https://en.wikipedia.org/wiki/Prisoner%27s_dilemma">Prisoner's Dilemma</a> according to a strategy implemented in a domain-specific language. </p> <p> Specifically, a finch is modelled like this: </p> <p> <pre><span style="color:blue;">data</span>&nbsp;Finch&nbsp;=&nbsp;Finch &nbsp;&nbsp;{&nbsp;finchID&nbsp;::&nbsp;Int, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">finchHP</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">HP</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">finchRoundsLeft</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">Rounds</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;The&nbsp;colour&nbsp;is&nbsp;used&nbsp;for&nbsp;visualisation,&nbsp;but&nbsp;has&nbsp;no&nbsp;semantic&nbsp;significance. </span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">finchColour</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">Colour</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;The&nbsp;current&nbsp;strategy. </span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">finchStrategy</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">Strategy</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;The&nbsp;expression&nbsp;that&nbsp;is&nbsp;evaluated&nbsp;to&nbsp;produce&nbsp;the&nbsp;strategy. </span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">finchStrategyExp</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">Exp</span> &nbsp;&nbsp;}</pre> </p> <p> The <code>Finch</code> data type is not an <code>Eq</code> instance. The reason is that <code>Strategy</code> is effectively a free monad over this functor: </p> <p> <pre><span style="color:blue;">data</span>&nbsp;EvalOp&nbsp;a &nbsp;&nbsp;=&nbsp;ErrorOp&nbsp;Error &nbsp;&nbsp;|&nbsp;MeetOp&nbsp;(FinchID&nbsp;-&gt;&nbsp;a) &nbsp;&nbsp;|&nbsp;GroomOp&nbsp;(Bool&nbsp;-&gt;&nbsp;a) &nbsp;&nbsp;|&nbsp;IgnoreOp&nbsp;(Bool&nbsp;-&gt;&nbsp;a)</pre> </p> <p> Since <code>EvalOp</code> is a <a href="https://en.wikipedia.org/wiki/Tagged_union">sum</a> of functions, it can't be an <code>Eq</code> instance, and this then applies transitively to <code>Finch</code>, as well as the <code>CellState</code> container that keeps track of each cell in the cellular grid: </p> <p> <pre><span style="color:blue;">data</span>&nbsp;CellState&nbsp;=&nbsp;CellState &nbsp;&nbsp;{&nbsp;cellFinch&nbsp;::&nbsp;Maybe&nbsp;Finch, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">cellRNG</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">StdGen</span> &nbsp;&nbsp;}</pre> </p> <p> An important part of working with this particular code base is that the API is given, and must not be changed. </p> <p> Given these constraints and data types, is there a way to improve test assertions? </p> <h3 id="3b73b7b375c24f40ac22d6274d806a60"> Smelly tests <a href="#3b73b7b375c24f40ac22d6274d806a60">#</a> </h3> <p> The lack of <code>Eq</code> instances makes it difficult to write simple assertions. The worst test I wrote is probably this, making use of a predefined example <code>Finch</code> value named <code>flipflop</code>: </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Cell&nbsp;1&nbsp;reproduces&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;flipflop)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;Nothing&nbsp;(mkStdGen&nbsp;6)&nbsp;<span style="color:green;">--&nbsp;seeded&nbsp;to&nbsp;reprod </span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.reproduce&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:blue;">do</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;Sanity&nbsp;check&nbsp;on&nbsp;first&nbsp;finch.&nbsp;Unfortunately,&nbsp;CellState&nbsp;is&nbsp;no&nbsp;Eq </span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;instance,&nbsp;so&nbsp;we&nbsp;can&#39;t&nbsp;just&nbsp;compare&nbsp;the&nbsp;entire&nbsp;record.&nbsp;Instead, </span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;using&nbsp;HP&nbsp;as&nbsp;a&nbsp;sample: </span>&nbsp;&nbsp;&nbsp;&nbsp;(Galapagos.finchHP&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">fst</span>&nbsp;actual))&nbsp;@?=&nbsp;Just&nbsp;20 &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;New&nbsp;finch&nbsp;should&nbsp;have&nbsp;HP&nbsp;from&nbsp;params: </span>&nbsp;&nbsp;&nbsp;&nbsp;(Galapagos.finchHP&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual))&nbsp;@?=&nbsp;Just&nbsp;14 &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;New&nbsp;finch&nbsp;should&nbsp;have&nbsp;lifespan&nbsp;from&nbsp;params: </span>&nbsp;&nbsp;&nbsp;&nbsp;(Galapagos.finchRoundsLeft&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual))&nbsp;@?= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Just&nbsp;23 &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;New&nbsp;finch&nbsp;should&nbsp;have&nbsp;same&nbsp;colour&nbsp;as&nbsp;parent: </span>&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;Galapagos.finchColour&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual))&nbsp;@?= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Galapagos.finchColour&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;cell1 &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;More&nbsp;assertions,&nbsp;described&nbsp;by&nbsp;their&nbsp;error&nbsp;messages: </span>&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;(Galapagos.finchID&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">fst</span>&nbsp;actual))&nbsp;/= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Galapagos.finchID&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual)))&nbsp;@? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a31515;">&quot;Finches&nbsp;have&nbsp;same&nbsp;ID,&nbsp;but&nbsp;they&nbsp;should&nbsp;be&nbsp;different.&quot;</span> &nbsp;&nbsp;&nbsp;&nbsp;(<span style="color:#2b91af;">(/=)</span>&nbsp;`on`&nbsp;Galapagos.cellRNG)&nbsp;cell2&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual)&nbsp;@? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a31515;">&quot;New&nbsp;cell&nbsp;2&nbsp;should&nbsp;have&nbsp;an&nbsp;updated&nbsp;RNG.&quot;</span></pre> </p> <p> As you can tell from the <a href="http://butunclebob.com/ArticleS.TimOttinger.ApologizeIncode">apologies</a> all these assertions leave something to be desired. The first assertion uses <code>finchHP</code> as a proxy for the entire finch in <code>cell1</code>, which is not supposed to change. Instead of an assertion for each of the first finch's attributes, the test 'hopes' that if <code>finchHP</code> didn't change, then so didn't the other values. </p> <p> The test then proceeds to verify various fields of the new finch in <code>cell2</code>, checking them one by one, since the lack of <code>Eq</code> makes it impossible to simply check that the actual value is equal to the expected value. </p> <p> In comparison, the test you saw in the previous article is almost pretty. It uses another example <code>Finch</code> value named <code>cheater</code>. </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Cell&nbsp;1&nbsp;does&nbsp;not&nbsp;reproduce&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;cheater)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;Nothing&nbsp;(mkStdGen&nbsp;1)&nbsp;<span style="color:green;">--&nbsp;seeded:&nbsp;no&nbsp;repr. </span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.reproduce&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:blue;">do</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;Sanity&nbsp;check&nbsp;that&nbsp;cell&nbsp;1&nbsp;remains,&nbsp;sampling&nbsp;on&nbsp;strategy: </span>&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;Galapagos.finchStrategyExp&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">fst</span>&nbsp;actual))&nbsp;@?= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Galapagos.finchStrategyExp&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;cell1 &nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;Galapagos.finchHP&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual))&nbsp;@?=&nbsp;Nothing</pre> </p> <p> The apparent simplicity is mostly because at that time, I'd almost given up on more thorough testing. In this test, I chose <code>finchStrategyExp</code> as a proxy for each value, and 'hoped' that if these properties behaved as expected, other attributes would, too. </p> <p> Given that I was following test-driven development and thus engaging in <a href="/2025/09/15/greyscale-box-test-driven-development">grey-box testing</a>, I had reason to believe that the implementation was correct if the test passes. </p> <p> Still, those tests exhibit more than one code smell. Could test-specific equality be the answer? </p> <h3 id="0d24dbb0a6c144ff9cdbf7b146f2329a"> Test utilities for finches <a href="#0d24dbb0a6c144ff9cdbf7b146f2329a">#</a> </h3> <p> The fundamental problem is that the <code>finchStrategy</code> field prevents <code>Finch</code> from being an <code>Eq</code> instance. Finding a way to compare <code>Strategy</code> values seems impractical. A more realistic course of action might be to compare all other fields. One option is to introduce a test-specific type with proper <code>Eq</code> and <code>Show</code> instances. </p> <p> <pre><span style="color:blue;">data</span>&nbsp;FinchEq&nbsp;=&nbsp;FinchEq &nbsp;&nbsp;{&nbsp;feqID&nbsp;::&nbsp;Int &nbsp;&nbsp;,&nbsp;feqHP&nbsp;::&nbsp;Galapagos.HP &nbsp;&nbsp;,&nbsp;feqRoundsLeft&nbsp;::&nbsp;Galapagos.Rounds &nbsp;&nbsp;,&nbsp;feqColour&nbsp;::&nbsp;Galapagos.Colour &nbsp;&nbsp;,&nbsp;feqStrategyExp&nbsp;::&nbsp;Exp&nbsp;} &nbsp;&nbsp;<span style="color:blue;">deriving</span>&nbsp;(<span style="color:#2b91af;">Eq</span>,&nbsp;<span style="color:#2b91af;">Show</span>)</pre> </p> <p> This data type only exists in the test code base. It has all the fields of <code>Finch</code>, except <code>finchStrategy</code>. </p> <p> While I could use it as-is, it quickly turns out that a helper function to turn a <code>CellState</code> value into a <code>FinchEq</code> value would also be useful. </p> <p> <pre><span style="color:#2b91af;">finchEq</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">Galapagos</span>.<span style="color:blue;">Finch</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">FinchEq</span> finchEq&nbsp;f&nbsp;=&nbsp;FinchEq &nbsp;&nbsp;{&nbsp;feqID&nbsp;=&nbsp;Galapagos.finchID&nbsp;f &nbsp;&nbsp;,&nbsp;feqHP&nbsp;=&nbsp;Galapagos.finchHP&nbsp;f &nbsp;&nbsp;,&nbsp;feqRoundsLeft&nbsp;=&nbsp;Galapagos.finchRoundsLeft&nbsp;f &nbsp;&nbsp;,&nbsp;feqColour&nbsp;=&nbsp;Galapagos.finchColour&nbsp;f &nbsp;&nbsp;,&nbsp;feqStrategyExp&nbsp;=&nbsp;Galapagos.finchStrategyExp&nbsp;f &nbsp;&nbsp;} <span style="color:#2b91af;">cellFinchEq</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">Galapagos</span>.<span style="color:blue;">CellState</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#2b91af;">Maybe</span>&nbsp;<span style="color:blue;">FinchEq</span> cellFinchEq&nbsp;=&nbsp;<span style="color:blue;">fmap</span>&nbsp;finchEq&nbsp;.&nbsp;Galapagos.cellFinch</pre> </p> <p> Finally, the System Under Test (the <code>reproduce</code> function) takes a tuple as input, and returns a tuple of the same type as output. To avoid some code duplication, it's practical to introduce a data type that can map over both components. </p> <p> <pre><span style="color:blue;">newtype</span>&nbsp;Pair&nbsp;a&nbsp;=&nbsp;Pair&nbsp;(a,&nbsp;a) &nbsp;&nbsp;<span style="color:blue;">deriving</span>&nbsp;(<span style="color:#2b91af;">Eq</span>,&nbsp;<span style="color:#2b91af;">Show</span>,&nbsp;<span style="color:#2b91af;">Functor</span>)</pre> </p> <p> This <code>newtype</code> wrapper makes it possible to map both the first and the second component of a pair (a two-tuple) using a single projection, since <code>Pair</code> is a <code>Functor</code> instance. </p> <p> That's all the machinery required to rewrite the two tests shown above. </p> <h3 id="3aed5cd44da14648bff6b7113018ff2f"> Improving the first test <a href="#3aed5cd44da14648bff6b7113018ff2f">#</a> </h3> <p> The first test may be rewritten as this: </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Cell&nbsp;1&nbsp;reproduces&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;flipflop)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;Nothing&nbsp;(mkStdGen&nbsp;6)&nbsp;<span style="color:green;">--&nbsp;seeded&nbsp;to&nbsp;reprod </span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.reproduce&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;expected&nbsp;=&nbsp;Just&nbsp;$&nbsp;finchEq&nbsp;$&nbsp;flipflop &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;Galapagos.finchID&nbsp;=&nbsp;-1142203427417426925&nbsp;<span style="color:green;">--&nbsp;From&nbsp;Character.&nbsp;Test </span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;Galapagos.finchHP&nbsp;=&nbsp;14 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;Galapagos.finchRoundsLeft&nbsp;=&nbsp;23 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:blue;">do</span> &nbsp;&nbsp;&nbsp;&nbsp;(cellFinchEq&nbsp;&lt;$&gt;&nbsp;Pair&nbsp;actual)&nbsp;@?=&nbsp;Pair&nbsp;(cellFinchEq&nbsp;cell1,&nbsp;expected) &nbsp;&nbsp;&nbsp;&nbsp;(<span style="color:#2b91af;">(/=)</span>&nbsp;`on`&nbsp;Galapagos.cellRNG)&nbsp;cell2&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual)&nbsp;@? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a31515;">&quot;New&nbsp;cell&nbsp;2&nbsp;should&nbsp;have&nbsp;an&nbsp;updated&nbsp;RNG.&quot;</span></pre> </p> <p> That's still a bit of code. If you're used to C# or <a href="https://www.java.com">Java</a> code, you may not bat an eyelid over a fifteen-line code block (that even has a few <a href="/2013/06/24/a-heuristic-for-formatting-code-according-to-the-aaa-pattern">blank lines</a>), but fifteen lines of Haskell code is still significant. </p> <p> There are compound reasons for this. One is that the <code>Galapagos</code> module is a qualified import, which makes the code more verbose than it otherwise could have been. It doesn't help that I follow a strict rule of <a href="/2019/11/04/the-80-24-rule">staying within an 80-character line width</a>. </p> <p> That said, this version of the test has stronger assertions than before. Notice that the first assertion compares two <code>Pair</code>s of <code>FinchEq</code> values. This means that all five comparable fields of each finch is compared against the expected value. Since the assertion compares two <code>Pair</code>s, that's ten comparisons in all. The previous test only made five comparisons on the finches. </p> <p> The second assertion remains as before. It's there to ensure that the System Under Test (SUT) remembers to update its pseudo-random number generator. </p> <p> Perhaps you wonder about the expected values. For the <code>finchID</code>, hopefully the comment gives a hint. I originally set this value to <code>0</code>, ran the test, observed the actual value, and used what I had observed. I could do that because I was refactoring an existing test that exercised an existing SUT, following the rules of <a href="/2025/11/03/empirical-characterization-testing">empirical Characterization Testing</a>. </p> <p> The <code>finchID</code> values are in practice randomly generated numbers. These are notoriously awkward in test contexts, so I could also have excluded that field from <code>FinchEq</code>. Even so, I kept the field, because it's important to be able to verify that the new finch has a different <code>finchID</code> than the parent that begat it. </p> <h3 id="46f55878cf9d4b4a9a6c02c11986fd9c"> Derived values <a href="#46f55878cf9d4b4a9a6c02c11986fd9c">#</a> </h3> <p> Where do the magic constants <code>14</code> and <code>23</code> come from? Although we could use comments to explain their source, another option is to use <a href="http://xunitpatterns.com/Derived%20Value.html">Derived Values</a> to explicitly document their origin: </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Cell&nbsp;1&nbsp;reproduces&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;flipflop)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;Nothing&nbsp;(mkStdGen&nbsp;6)&nbsp;<span style="color:green;">--&nbsp;seeded&nbsp;to&nbsp;reprod </span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.reproduce&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;expected&nbsp;=&nbsp;Just&nbsp;$&nbsp;finchEq&nbsp;$&nbsp;flipflop &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;Galapagos.finchID&nbsp;=&nbsp;-1142203427417426925&nbsp;<span style="color:green;">--&nbsp;From&nbsp;Character.&nbsp;Test </span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;Galapagos.finchHP&nbsp;=&nbsp;Galapagos.startHP&nbsp;Galapagos.defaultParams &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;Galapagos.finchRoundsLeft&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Galapagos.lifespan&nbsp;Galapagos.defaultParams &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:blue;">do</span> &nbsp;&nbsp;&nbsp;&nbsp;(cellFinchEq&nbsp;&lt;$&gt;&nbsp;Pair&nbsp;actual)&nbsp;@?=&nbsp;Pair&nbsp;(cellFinchEq&nbsp;cell1,&nbsp;expected) &nbsp;&nbsp;&nbsp;&nbsp;(<span style="color:#2b91af;">(/=)</span>&nbsp;`on`&nbsp;Galapagos.cellRNG)&nbsp;cell2&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual)&nbsp;@? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a31515;">&quot;New&nbsp;cell&nbsp;2&nbsp;should&nbsp;have&nbsp;an&nbsp;updated&nbsp;RNG.&quot;</span></pre> </p> <p> We now learn that the <code>finchHP</code> value originates from the <code>startHP</code> value of the <code>defaultParams</code>, and similarly for <code>finchRoundsLeft</code>. </p> <p> To be honest, I'm not sure that this is an improvement. It makes the test more abstract, and if we wish that tests may serve as executable documentation, concrete example values may be easier to understand. Besides, this gets uncomfortably close to duplicating the actual implementation code contained in the SUT. </p> <p> This variation only serves as an exploration of alternatives. I would strongly consider rolling this change back, and instead add some comments to the magic numbers. </p> <h3 id="21b8d21e41c14aa39050ee49a72e0b11"> Improving the second test <a href="#21b8d21e41c14aa39050ee49a72e0b11">#</a> </h3> <p> The second test improves better. </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Cell&nbsp;1&nbsp;does&nbsp;not&nbsp;reproduce&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;cheater)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;Nothing&nbsp;(mkStdGen&nbsp;1)&nbsp;<span style="color:green;">--&nbsp;seeded:&nbsp;no&nbsp;repr. </span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.reproduce&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;(cellFinchEq&nbsp;&lt;$&gt;&nbsp;Pair&nbsp;actual)&nbsp;@?=&nbsp;Pair&nbsp;(cellFinchEq&nbsp;cell1,&nbsp;Nothing)</pre> </p> <p> Not only is it shorter, the assertion is much stronger. It achieves the ideal of verifying that the actual value is equal to the expected value, comparing five data fields on each of the two finches. </p> <h3 id="18c1f690d06d4722a99c0e18e2c66bf2"> Comparing cells <a href="#18c1f690d06d4722a99c0e18e2c66bf2">#</a> </h3> <p> The <code>reproduce</code> function uses the pseudo-random number generators embedded in the <code>CellState</code> data type to decide whether a finch reproduces in a given round. Thus, the number generators change in deterministic, but by human cognition unpredictable, ways. It makes sense to exclude the generators from the assertions, apart from the above assertion that verifies the change itself. </p> <p> Other functions in the <code>Galapagos</code> module also work on <code>CellState</code> values, but are entirely deterministic; that is, they don't make use of the pseudo-random number generators. One such function is <code>groom</code>, which models what happens when two finches meet and play out their game of Prisoner's Dilemma by deciding to groom the other for parasites, or not. The function has this type: </p> <p> <pre><span style="color:#2b91af;">groom</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">Params</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;(<span style="color:blue;">CellState</span>,&nbsp;<span style="color:blue;">CellState</span>)&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;(<span style="color:blue;">CellState</span>,&nbsp;<span style="color:blue;">CellState</span>)</pre> </p> <p> By specification, this function has no random behaviour, which means that we expect the number generators to stay the same. Even so, due to the lack of an <code>Eq</code> instance, comparing cells is difficult. </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Groom&nbsp;when&nbsp;right&nbsp;cell&nbsp;is&nbsp;empty&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;flipflop)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;Nothing&nbsp;(mkStdGen&nbsp;1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.groom&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:blue;">do</span> &nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;Galapagos.finchHP&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">fst</span>&nbsp;actual))&nbsp;@?= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Galapagos.finchHP&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;cell1 &nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;Galapagos.finchHP&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual))&nbsp;@?=&nbsp;Nothing</pre> </p> <p> Instead of comparing cells, this test only considers the contents of each cell, and it only compares a single field, <code>finchHP</code>, as a proxy for comparing the more complete data structure. </p> <p> With <code>FinchEq</code> we have a better way of comparing two finches, but we don't have to stop there. We may introduce another test-utility type that can compare cells. </p> <p> <pre><span style="color:blue;">data</span>&nbsp;CellStateEq&nbsp;=&nbsp;CellStateEq &nbsp;&nbsp;{&nbsp;cseqFinch&nbsp;::&nbsp;Maybe&nbsp;FinchEq &nbsp;&nbsp;,&nbsp;cseqRNG&nbsp;::&nbsp;StdGen &nbsp;&nbsp;} &nbsp;&nbsp;<span style="color:blue;">deriving</span>&nbsp;(<span style="color:#2b91af;">Eq</span>,&nbsp;<span style="color:#2b91af;">Show</span>)</pre> </p> <p> A helper function also turns out to be useful. </p> <p> <pre><span style="color:#2b91af;">cellStateEq</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">Galapagos</span>.<span style="color:blue;">CellState</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">CellStateEq</span> cellStateEq&nbsp;cs&nbsp;=&nbsp;CellStateEq &nbsp;&nbsp;{&nbsp;cseqFinch&nbsp;=&nbsp;cellFinchEq&nbsp;cs &nbsp;&nbsp;,&nbsp;cseqRNG&nbsp;=&nbsp;Galapagos.cellRNG&nbsp;cs &nbsp;&nbsp;}</pre> </p> <p> We can now rewrite the test to compare both cells in their entirety (minus the <code>finchStrategy</code>). </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Groom&nbsp;when&nbsp;right&nbsp;cell&nbsp;is&nbsp;empty&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;flipflop)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;Nothing&nbsp;(mkStdGen&nbsp;1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.groom&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;(cellStateEq&nbsp;&lt;$&gt;&nbsp;Pair&nbsp;actual)&nbsp;@?=&nbsp;cellStateEq&nbsp;&lt;$&gt;&nbsp;Pair&nbsp;(cell1,&nbsp;cell2)</pre> </p> <p> Again, the test is both simpler and stronger. </p> <h3 id="13df780b2ce74b40b198e8b05fc0f721"> A fly in the ointment <a href="#13df780b2ce74b40b198e8b05fc0f721">#</a> </h3> <p> Introducing <code>FinchEq</code> and <code>CellStateEq</code> allowed me to improve most of the tests, but a few annoying issues remain. The most illustrative example is this test of the core <code>groom</code> behaviour, which lets two example <code>Finch</code> values named <code>samaritan</code> and <code>cheater</code> interact. </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Groom&nbsp;two&nbsp;finches&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;samaritan)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;cheater)&nbsp;(mkStdGen&nbsp;1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.groom&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;expected&nbsp;=&nbsp;Just&nbsp;&lt;$&gt;&nbsp;Pair &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;finchEq&nbsp;$&nbsp;samaritan&nbsp;{&nbsp;Galapagos.finchHP&nbsp;=&nbsp;16&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;finchEq&nbsp;$&nbsp;cheater&nbsp;{&nbsp;Galapagos.finchHP&nbsp;=&nbsp;13&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;(cellFinchEq&nbsp;&lt;$&gt;&nbsp;Pair&nbsp;actual)&nbsp;@?=&nbsp;expected</pre> </p> <p> This test ought to compare cells with <code>CellStateEq</code>, but only compares finches. The practical reason is that defining the <code>expected</code> value as a pair of cells entails embedding the expected finches in their respective cells. This is possible, but awkward, due to the nested nature of the data types. </p> <p> It's possible to do something about that, too, but that's the topic for another article. </p> <h3 id="f6ff371e3106437195a3debe12c930a5"> Conclusion <a href="#f6ff371e3106437195a3debe12c930a5">#</a> </h3> <p> If a test is difficult to write, it may be a symptom that the System Under Test (SUT) has an API which is difficult to use. When doing test-driven development you may want to reconsider the API. Is there a way to model the desired data and behaviour in such a way that the tests become simpler? If so, the API may improve in general. </p> <p> Sometimes, however, you can't change the SUT API. Perhaps it's already given. Perhaps improving it would be a breaking change. Or perhaps you simply can't think of a better way. </p> <p> An alternative to changing the SUT API is to introduce test utilities, such as types with test-specific equality. This is hardly better than improving the SUT API, but may be useful in those situations where the best option is unavailable. </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>. Mark Seemann https://blog.ploeh.dk/2025/12/22/test-specific-eq Tautological assertions are not always caused by aliasing https://blog.ploeh.dk/2025/12/15/tautological-assertions-are-not-always-caused-by-aliasing/ Mon, 15 Dec 2025 14:12:00 UTC <div id="post"> <p> <em>You can also make mistakes that compile in Haskell.</em> </p> <p> Seeing a (unit) test fail before making it pass is an <a href="/2025/10/20/epistemology-of-software">important part of empirical software engineering</a>. This is nothing new. We've known about the <a href="https://www.jamesshore.com/v2/blog/2005/red-green-refactor">red-green-refactor</a> cycle for at least twenty years, so we know that ensuring that a test can fail is of the essence. </p> <p> A fundamental problem of automated testing is that we're writing code to test code. How do we know that our test code works? After all, it's easy enough to make mistakes, even with simple code. </p> <h3 id="39ab6414de2141288bcc4d513d1fefc1"> The importance of discipline <a href="#39ab6414de2141288bcc4d513d1fefc1">#</a> </h3> <p> When I test-drive a programming task, it regularly happens that I write a test that I expect to fail, only for it to pass. Even so, it doesn't happen that often. During a week of intensive coding, it may happen once or twice. </p> <p> After all, a unit test is supposed to be a simple, short block of code, ideally with a <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> of 1. If you're an experienced programmer, working in a language that you know, you wouldn't expect to make simple mistakes too often. </p> <p> It's easy to get lulled into a false sense of security. When new tests fail (as they should) more than 95% of the time, you may be tempted to cut corners: Just write the test, implement the desired code, and move on. </p> <p> My experience is, however, that I inadvertently write a passing test now and then. I've been doing test-driven development (TDD) for more than twenty years, and this still happens. It is therefore important to keep up discipline and run that damned test, even if you don't feel like it. It's exactly when your attention is flagging that you need this safety mechanism the most. </p> <p> Until you've tried a couple of times writing a test that unexpectedly pass, it can be hard to grasp why the <em>red</em> phase is essential. Therefore I've always felt that it was important to publish examples. </p> <h3 id="c9e6c65653d744789a1177ad5e56fd9c"> Tautologies <a href="#c9e6c65653d744789a1177ad5e56fd9c">#</a> </h3> <p> A new test that passes on the first run is almost always a tautology. Theoretically, it may be that you <em>think</em> that the System Under Test does not yet have a certain capability, but after writing the test, it turns out that, after all, it does. This almost never happens to me. I can't rule out that this may have been the case once or twice in the last few decades, but it's as scarce as hen's teeth. </p> <p> Usually, the problem is that the test is a tautology. While you believe that the test correctly self-checks something relevant, in reality, it's written in such a way that it can't possibly fail. </p> <p> The first time I had the opportunity to document such a <a href="/2019/10/14/tautological-assertion">tautological assertion</a> the underlying problem turned out to be <a href="https://en.wikipedia.org/wiki/Aliasing_(computing)">aliasing</a>. The next examples I ran into also had their roots in aliasing. </p> <p> I began to wonder: Is the problem of tautological assertions mostly related to aliasing? If so, does it mean that the phenomenon of writing a passing test by mistake is mostly isolated to procedural and object-oriented programming? Could it be that this doesn't happen in functional programming? </p> <h3 id="9a1a568358924aeea3b98f5c0240c26d"> If it compiles, it works <a href="#9a1a568358924aeea3b98f5c0240c26d">#</a> </h3> <p> Many so-called functional programming languages are in reality mixed-paradigm languages. The one that I know best is <a href="https://fsharp.org/">F#</a>, which <a href="https://en.wikipedia.org/wiki/Don_Syme">Don Syme</a> calls <em>functional-first</em>. Even so, it's explicitly designed to interact with .NET libraries written in other languages (almost always C#), so it can still suffer from aliasing problems. The same situation applies to <a href="https://clojure.org/">Clojure</a> and <a href="https://www.scala-lang.org/">Scala</a>, which both run on the <a href="https://en.wikipedia.org/wiki/Java_virtual_machine">JVM</a>. </p> <p> A few languages are, however, unapologetically functional. <a href="https://www.haskell.org/">Haskell</a> is probably the most famous. If you rule out actions that run in <code>IO</code>, shared mutable state is not a concern. </p> <p> Haskell's type system is so advanced and powerful that there are programmers who still seem to approach the language with an implied attitude that if it compiles, it works. Clearly, as we shall see, that is not the case. </p> <h3 id="d66b70f0d56e4d38b2c2ff4b8fd91476"> Example <a href="#d66b70f0d56e4d38b2c2ff4b8fd91476">#</a> </h3> <p> Last week, I was writing tests against an API that was already given. As the 53rd test, I wrote this: </p> <p> <pre>testCase&nbsp;<span style="color:#a31515;">&quot;Cell&nbsp;1&nbsp;does&nbsp;not&nbsp;reproduce&quot;</span>&nbsp;$ &nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;cell1&nbsp;=&nbsp;Galapagos.CellState&nbsp;(Just&nbsp;cheater)&nbsp;(mkStdGen&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell2&nbsp;=&nbsp;Galapagos.CellState&nbsp;Nothing&nbsp;(mkStdGen&nbsp;1)&nbsp;<span style="color:green;">--&nbsp;seeded:&nbsp;no&nbsp;repr. </span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actual&nbsp;=&nbsp;Galapagos.reproduce&nbsp;Galapagos.defaultParams&nbsp;(cell1,&nbsp;cell2) &nbsp;&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:blue;">do</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">--&nbsp;Sanity&nbsp;check&nbsp;that&nbsp;cell&nbsp;1&nbsp;remains,&nbsp;sampling&nbsp;on&nbsp;strategy: </span>&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;Galapagos.finchStrategyExp&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">fst</span>&nbsp;actual))&nbsp;@?= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Galapagos.finchStrategyExp&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;cell1 &nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;Galapagos.finchHP&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;cell2)&nbsp;@?=&nbsp;Nothing</pre> </p> <p> To my surprise, it immediately passed. What's wrong with it? Before reading on, see if you can spot the problem. </p> <p> I know that you don't know the problem domain or the particular API. Even so, the problem is in the test itself, not in the implementation code. After all, according to the red-green-refactor cycle, I hadn't yet added the code that would make this test pass. </p> <p> The error is that I meant to verify that the <code>actual</code> value's second component remained <code>Nothing</code>, but either due to a brain fart, or because I copied an earlier test, the last assertion checks that <code>cell2</code> is <code>Nothing</code>. </p> <p> Since <code>cell2</code> is originally initialized with <code>Nothing</code>, and Haskell values are immutable, there's no way it could be anything else. This is a tautological assertion. The correct assertion is </p> <p> <pre>(Galapagos.finchHP&nbsp;&lt;$&gt;&nbsp;Galapagos.cellFinch&nbsp;(<span style="color:blue;">snd</span>&nbsp;actual))&nbsp;@?=&nbsp;Nothing</pre> </p> <p> Notice that it examines <code>snd actual</code> rather than <code>cell2</code>. </p> <h3 id="742d2bcf8fa84779ae120603e2b66347"> Causes <a href="#742d2bcf8fa84779ae120603e2b66347">#</a> </h3> <p> How could I be so stupid? First, to err is human, and this is exactly why it's important to start with a failing test. The error was mine, but even so, it sometimes pays to analyse if there might be an underlying driving force behind the error. In this case, I can identify at least two, although they are related. </p> <p> First, I don't recall exactly how I wrote this test, but looking at previous commits, I find it likely that I copied and pasted an earlier test case. Evidently, I failed to correctly alter the assertion to specify the new test case. </p> <p> Why was I even copying and pasting the test? Because the test is too complicated. As a rule of thumb, pay attention to copy-and-paste, also of test cases. <a href="/2025/12/01/treat-test-code-like-production-code">Test code should be well-factored</a>, without too much duplication, for the same reasons that apply to other code. If a test is too difficult to write, it indicates that the API is too difficult to use. This is feedback about the API design, and you should consider if simplification is possible. </p> <p> And the test is, indeed, too complicated. What I wanted to verify is that <code>Galapagos.cellFinch (snd actual)</code> is <code>Nothing</code>. If so, why didn't I just write <code>Galapagos.cellFinch (snd actual) @?= Nothing</code>? Because that doesn't compile. </p> <p> The issue is that the data type in question (<code>Finch</code>) doesn't have an <code>Eq</code> instance, which <code>@?=</code> requires. Thus, I had to project the value I wanted to examine to a value that does have an <code>Eq</code> instance, such <code>finchHP</code>, which is an <code>Int</code>. </p> <p> Why didn't I assert on <a href="https://hackage.haskell.org/package/base/docs/Data-Maybe.html#v:isNothing">isNothing</a> instead? Eventually, I did, but the problem with asserting on raw Boolean values is that when the assertion fails, you get no good feedback. The test runner will only tell you that the expected value was <code>True</code>, but the actual value <code>False</code>. </p> <p> The <a href="https://hackage-content.haskell.org/package/tasty-hunit/docs/Test-Tasty-HUnit.html#v:assertBool">assertBool</a> action offers a solution, but then you have to write your own error message, and I wasn't yet ready to do that. Eventually, I did, though. </p> <p> The bottom line is that the risk of making mistakes increases, the more complicated things become. This also applies to functional programming, but in reality, simple is rarely easy. </p> <h3 id="bb165f0d1d904feda4e8c9bd3098fd12"> Conclusion <a href="#bb165f0d1d904feda4e8c9bd3098fd12">#</a> </h3> <p> Tautological assertions are not only caused by aliasing, but also plain human error. In this article, you've seen an example of such an error in Haskell. This is a language with a type system that can identify many errors at compile time. Even so, some errors are run-time errors, and when it comes to TDD, in the <em>red</em> phase, the absence of failure indicates an error. </p> <p> I find it important to share such errors when they occur, because they are at the same time regular and uncommon. While rare, they still happen with some periodicity. Since, after all, they don't happen that often, it may take time if you only have your own mistakes to learn from. So learn from mine, too. </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>. Mark Seemann https://blog.ploeh.dk/2025/12/15/tautological-assertions-are-not-always-caused-by-aliasing Pattern guards for a protocol https://blog.ploeh.dk/2025/12/08/pattern-guards-for-a-protocol/ Mon, 08 Dec 2025 13:53:00 UTC <div id="post"> <p> <em>A Haskell example.</em> </p> <p> Recently, I was doing a <a href="https://www.haskell.org/">Haskell</a> project implementing a <a href="https://en.wikipedia.org/wiki/Cellular_automaton">cellular automaton</a> according to predefined rules. Specifically, the story was one of <a href="https://en.wikipedia.org/wiki/Darwin%27s_finches">Galápagos finches</a> meeting and deciding whether or not to groom each other for parasites, effectively playing out a round of <a href="https://en.wikipedia.org/wiki/Prisoner%27s_dilemma">prisoner's dilemma</a>. </p> <p> Each finch is equipped with a particular strategy for repeated play. This strategy is implemented in a custom <a href="https://en.wikipedia.org/wiki/Domain-specific_language">domain-specific language</a> that enables each finch to remember past actions of other finches, and make decisions based on this memory. </p> <h3 id="873756586c264a01b5a2fcadca00ec86"> Meeting protocol <a href="#873756586c264a01b5a2fcadca00ec86">#</a> </h3> <p> An evaluator runs over the code that implements each strategy, returning a free monad that embeds the possible actions a finch may take when meeting another finch. </p> <p> The possible actions are defined by this <a href="https://en.wikipedia.org/wiki/Tagged_union">sum type</a>: </p> <p> <pre><span style="color:blue;">data</span>&nbsp;EvalOp&nbsp;a &nbsp;&nbsp;=&nbsp;ErrorOp&nbsp;Error &nbsp;&nbsp;|&nbsp;MeetOp&nbsp;(FinchID&nbsp;-&gt;&nbsp;a) &nbsp;&nbsp;|&nbsp;GroomOp&nbsp;(Bool&nbsp;-&gt;&nbsp;a) &nbsp;&nbsp;|&nbsp;IgnoreOp&nbsp;(Bool&nbsp;-&gt;&nbsp;a)</pre> </p> <p> When two finches <em>a</em> and <em>b</em> meet, they must interact according to a protocol. </p> <ul> <li>Evaluate the strategy of the finch <em>a</em> up to the next effect, which must be a <code>MeetOp</code>.</li> <li>Invoke the continuation of the <code>MeetOp</code> with the <code>finchID</code> of finch <em>b</em>.</li> <li>Evaluate the strategy up to next effect, which must be <code>GroomOp</code> or <code>IgnoreOp</code>. This decides the behaviour of finch <em>a</em> during this meeting.</li> <li>Similarly, determine the behaviour of finch <em>b</em>, using the <code>finchID</code> of finch <em>a</em>.</li> <li>For each finch, invoke the continuation of the <code>GroomOp</code> or <code>IgnoreOp</code> with the behaviour of the other finch (<code>True</code> for grooming, <code>False</code> for ignoring), yielding two new <code>Strategy</code>s (sic).</li> <li>The resulting <code>Strategy</code>s (sic) are then stored in the <code>Finch</code> objects for the next meeting of the finches.</li> </ul> <p> If at any step a strategy does not produce one of the expected effects (or no effect at all), then the finch has behaved illegally. For example, if in step 1 the first effect is a <code>GroomOp</code>, then this is illegal. </p> <p> This sounds rather complicated, and I was concerned that even though I could pattern-match against the <code>EvalOp</code> cases, I'd end up with duplicated and deeply indented code. </p> <h3 id="1c343de526674bd4b597c1952d514114"> Normal pattern matching <a href="#1c343de526674bd4b597c1952d514114">#</a> </h3> <p> Worrying about duplication, I tried to see if I could isolate each finch's 'handshake' as a separate function. I was still concerned that using normal pattern matching would cause too much indentation, but subsequent experimentation shows that in this case, it's not really that bad. </p> <p> Ultimately, I went with <a href="https://wiki.haskell.org/Pattern_guard">pattern guards</a>, but I think that it may be more helpful to lead with an example of what the code would look like using plain vanilla pattern matching. </p> <p> <pre><span style="color:#2b91af;">tryRun</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">EvalM</span>&nbsp;a&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">FinchID</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#2b91af;">Maybe</span>&nbsp;(<span style="color:#2b91af;">Bool</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">EvalM</span>&nbsp;a,&nbsp;<span style="color:#2b91af;">Bool</span>) tryRun&nbsp;(Free&nbsp;(MeetOp&nbsp;nextAfterMeet))&nbsp;other&nbsp;= &nbsp;&nbsp;<span style="color:blue;">case</span>&nbsp;nextAfterMeet&nbsp;other&nbsp;<span style="color:blue;">of</span> &nbsp;&nbsp;&nbsp;&nbsp;(Free&nbsp;(GroomOp&nbsp;nextAfterGroom))&nbsp;-&gt;&nbsp;Just&nbsp;(nextAfterGroom,&nbsp;True) &nbsp;&nbsp;&nbsp;&nbsp;(Free&nbsp;(IgnoreOp&nbsp;nextAfterIgnore))&nbsp;-&gt;&nbsp;Just&nbsp;(nextAfterIgnore,&nbsp;False) &nbsp;&nbsp;&nbsp;&nbsp;_&nbsp;-&gt;&nbsp;Nothing tryRun&nbsp;_&nbsp;_&nbsp;=&nbsp;Nothing</pre> </p> <p> Now that I write this article, I realize that I should have named the function <code>handshake</code>, but hindsight is twenty-twenty. In the moment, I went with <code>tryRun</code>, using the <code>try</code> prefix to indicate that this operation may fail, as also indicated by the <code>Maybe</code> return type. That naming convention is probably more idiomatic in <a href="https://fsharp.org/">F#</a>, but I digress. </p> <p> As announced, that's not half as bad as I had originally feared. There's the beginning of <a href="https://wiki.c2.com/?ArrowAntiPattern">arrow code</a>, but I suppose you could also say that of any use of <code>if/then/else</code>. Imagine, however, that the protocol involved a few more steps, and you'd have something quite ugly at hand. </p> <p> Another slight imperfection is the repetition of returning <code>Nothing</code>. Again, this code would not keep me up at night, but it just so happened that I originally thought that it would be worse, so I immediately cast about for alternatives. </p> <h3 id="35fc2dd4bc7c407f972a7f084d506f0d"> Using pattern guards <a href="#35fc2dd4bc7c407f972a7f084d506f0d">#</a> </h3> <p> Originally, I thought that perhaps <a href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/view_patterns.html">view patterns</a> would be suitable, but while looking around, I came across <a href="https://wiki.haskell.org/Pattern_guard">pattern guards</a> and thought: What's that? </p> <p> This language feature has been around since 2010, but it's new to me. It's a good fit for the problem at hand, and that's how I actually wrote the <code>tryRun</code> function: </p> <p> <pre><span style="color:#2b91af;">tryRun</span>&nbsp;<span style="color:blue;">::</span>&nbsp;<span style="color:blue;">EvalM</span>&nbsp;a&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">FinchID</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#2b91af;">Maybe</span>&nbsp;(<span style="color:#2b91af;">Bool</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">EvalM</span>&nbsp;a,&nbsp;<span style="color:#2b91af;">Bool</span>) tryRun&nbsp;strategy&nbsp;other &nbsp;&nbsp;|&nbsp;(Free&nbsp;(MeetOp&nbsp;nextAfterMeet))&nbsp;&lt;-&nbsp;strategy &nbsp;&nbsp;,&nbsp;(Free&nbsp;(GroomOp&nbsp;nextAfterGroom))&nbsp;&lt;-&nbsp;nextAfterMeet&nbsp;other &nbsp;&nbsp;=&nbsp;Just&nbsp;(nextAfterGroom,&nbsp;True) tryRun&nbsp;strategy&nbsp;other &nbsp;&nbsp;|&nbsp;(Free&nbsp;(MeetOp&nbsp;nextAfterMeet))&nbsp;&lt;-&nbsp;strategy &nbsp;&nbsp;,&nbsp;(Free&nbsp;(IgnoreOp&nbsp;nextAfterIgnore))&nbsp;&lt;-&nbsp;nextAfterMeet&nbsp;other &nbsp;&nbsp;=&nbsp;Just&nbsp;(nextAfterIgnore,&nbsp;False) tryRun&nbsp;_&nbsp;_&nbsp;=&nbsp;Nothing</pre> </p> <p> Now that I have the opportunity to compare the two alternatives, it's not clear that one is better than the other. You may even prefer the first, normal version. </p> <p> The version using pattern guards has more lines of code, and code duplication in the repetition of the <code>|&nbsp;(Free&nbsp;(MeetOp&nbsp;nextAfterMeet))&nbsp;&lt;-&nbsp;strategy</code> pattern. On the other hand, we get rid of the duplicated <code>Nothing</code> return value. What is perhaps more interesting is that had the handshake protocol involved more steps, the pattern-guards version would remain flat, whereas the other version would require indentation. </p> <p> To be honest, now that I write this article, the example has lost some of its initial lustre. Still, I learned about a Haskell language feature that I didn't know about, and thought I'd share the example. </p> <h3 id="6e8c2d18271344869e706eb6d3fa6db2"> Conclusion <a href="#6e8c2d18271344869e706eb6d3fa6db2">#</a> </h3> <p> Most mature programming languages have so many features that a programmer may use a language for years, and still be unaware of useful alternatives. Haskell is the oldest language I use, and although I've programmed in it for a decade, I still learn new things. </p> <p> In this article, you saw a simple example of using pattern guards. Perhaps you will find this language feature useful in your own code. Perhaps you already use it. </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>. Mark Seemann https://blog.ploeh.dk/2025/12/08/pattern-guards-for-a-protocol Treat test code like production code https://blog.ploeh.dk/2025/12/01/treat-test-code-like-production-code/ Mon, 01 Dec 2025 15:03:00 UTC <div id="post"> <p> <em>You have to read and maintain test code, too.</em> </p> <p> I don't think I've previously published an article with the following simple message, which is clearly an omission on my part. Better late than never, though. </p> <p> <em>Treat test code like production code.</em> </p> <p> You should apply the same coding standards to test code as you do to production code. You should make sure the code is readable, well-factored, goes through review, etc., just like your production code. </p> <h3 id="96bb9c9eb94546b498d619d2a46d6e98"> Test mess <a href="#96bb9c9eb94546b498d619d2a46d6e98">#</a> </h3> <p> It's not uncommon to encounter test code that has received a stepmotherly treatment. Such test code may still pay lip service to an organization's overall coding standards by having correct indents, placement of brackets, and other superficial signs of care. You don't have to dig deep, however, before you discover that the quality of the test code leaves much to be desired. </p> <p> The most common problem is a disregard for the <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY principle</a>. Duplication abound. It's almost as though people feel unburdened by the shackles of good software engineering practices, and as result relish in the freedom to copy and paste. </p> <p> That freedom is, however, purely illusory. We'll return to that shortly. </p> <p> Perhaps the second-most common category of poor coding practices applied to test code is the high frequency of <a href="https://www.bitnative.com/2012/10/22/kill-the-zombies-in-your-code/">Zombie Code</a>. Commented-out code is common. </p> <p> Other, less frequent examples of bad practices include use of arbitrary waits instead of proper thread synchronization, <a href="/2019/02/04/how-to-get-the-value-out-of-the-monad">unwrapping of monadic values</a>, including calling <a href="https://learn.microsoft.com/dotnet/api/system.threading.tasks.task-1.result">Task.Result</a> instead of properly awaiting a value, and so on. </p> <p> I'm sure that you can think of other examples. </p> <h3 id="8aab547e039d4b3f8fa5cf095fd60dcb"> Why good code is important <a href="#8aab547e039d4b3f8fa5cf095fd60dcb">#</a> </h3> <p> I think that I can understand why people treat test code as a second-class citizen. It seems intuitive, although the intuition is wrong. Nevertheless, I think it goes like this: Since the test code doesn't go into production, it's seen as less important. And as we shall see below, there are, indeed, a few areas where you can safely cut corners when it comes to test code. </p> <p> As a general rule, however, it's a bad idea to slack on quality in test code. </p> <p> The reason lies in why we even have coding standards and design principles in the first place. Here's a hint: It's not to placate the computer. </p> <blockquote> <p> "Any fool can write code that a computer can understand. Good programmers write code that humans can understand." </p> <footer><cite><a href="/ref/refactoring">Refactoring</a></cite>, Martin Fowler, 1999, ch. 1, p. 15</footer> </blockquote> <p> The reason we do our best to write code of good quality is that if we don't, it's going to make our work more difficult in the future. Either our own, or someone else's. But frequently, our own. </p> <p> Forty (or fifty?) years of literature on good software development practices grapple with this fundamental problem. This is why my most recent book is called <a href="/2021/06/14/new-book-code-that-fits-in-your-head">Code That Fits in Your Head</a>. We apply software engineering heuristics and care about architecture because we know that if we fail to structure the code well, our mission is in jeopardy: We will not deliver on time, on budget, or with working features. </p> <p> Once we understand this, we see how this applies to test code, too. If you have good test coverage, you will likely have a substantial amount of test code. You need to maintain this part of the code base too. The best way to do so is to treat it like your production code. Apply the same standards and design principles to test code as you do to your production code. This especially means keeping test code DRY. </p> <h3 id="a2931e61642a4861be94f2f4e48fe624"> Test-specific practices <a href="#a2931e61642a4861be94f2f4e48fe624">#</a> </h3> <p> Since test code has a specialized purpose, you'll run into problems unique to that space. How should you structure a unit test? How should you organize them? How should you name them? How do you make them deterministic? </p> <p> Fortunately, thoughtful people have collected and systematized their experience. The absolute most comprehensive such collection is <a href="/ref/xunit-patterns">xUnit Test Patterns</a>, which has been around since 2007. Nothing in that book invalidates normal coding practices. Rather, it suggests specializations of good practices that apply to test code. </p> <p> You may run into the notion that tests should be <a href="http://blog.jayfields.com/2006/05/dry-code-damp-dsls.html">DAMP</a> rather than DRY. If you expand the acronym, however, it stands for Descriptive And Meaningful Phrases, and you may realize that it's a desired quality of code independent of whether or not you repeat yourself. (Even the linked article fails, in my opinion, to erect a convincing dichotomy. Its notion of DRY is clearly not the one normally implied.) I think of the DAMP notion as related to <a href="/ref/ddd">Domain-Driven Design</a>, which is another thematic take on making code fit in your head. </p> <p> For a few years, however, I did, too, believe that copy-and-paste was okay in test code, but have long since learned that duplication slows you down in test code for exactly the same reason that it hurts in 'real' code. One simple change leads to <a href="https://en.wikipedia.org/wiki/Shotgun_surgery">Shotgun Surgery</a>; many tests break, and you have to fix each one individually. </p> <h3 id="3db515539ace45f6a29dd54b6de90f78"> Dispensations <a href="#3db515539ace45f6a29dd54b6de90f78">#</a> </h3> <p> All the same, there are exceptions to the general rule. In certain, well-understood ways, you can treat your test code with less care than production code. </p> <p> Specifically, assuming that test code remains undeployed, you can skip certain security practices. You may, for example, hard-code test-only passwords directly in the tests. The code base that accompanies <a href="/code-that-fits-in-your-head">Code That Fits in Your Head</a> contains an example of that. </p> <p> You may also skip input validation steps, since you control the input for each test. </p> <p> In my experience, security is the dominating exemption from the rule, but there may be other language- or platform-specific details where deviating from normal practices is warranted for test code. </p> <p> One example may be in .NET, where <a href="https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2007">a static code analysis rule may insist that you call ConfigureAwait</a>. This rule is intended for library code that may run in arbitrary environments. When code runs in a unit-testing environment, on the other hand, the context is already known, and this rule can be dispensed with. </p> <p> Another example is that in <a href="https://www.haskell.org/">Haskell</a> GHC may complain about <a href="https://wiki.haskell.org/index.php?title=Orphan_instance">orphan instances</a>. In test code, it may occasionally be useful to give an existing type a new instance, most commonly an <a href="https://hackage-content.haskell.org/package/QuickCheck/docs/Test-QuickCheck.html#t:Arbitrary">Arbitrary</a> instance. While you can also get around this problem with <a href="/2019/09/02/naming-newtypes-for-quickcheck-arbitraries">well-named newtypes</a>, you may also decide that orphan instances are no problem in a test code base, since you don't have to export the test modules as reusable libraries. </p> <h3 id="1e6560fee36e4944bee9f2bdf9fea64c"> Conclusion <a href="#1e6560fee36e4944bee9f2bdf9fea64c">#</a> </h3> <p> You should treat test code like production code. The coding standards that apply to production code should also apply to test code. If you follow the DRY principle for production code, you should also follow the DRY principle in the test code base. </p> <p> The reason is that most coding standards and design principles exist to make code maintainability easier. Since test code is also code, this still applies. </p> <p> There are a few exception, most notably in the area of security, assuming that the test code is never deployed to production. </p> </div> <div id="comments"> <hr> <h2 id="comments-header"> Comments </h2> <div class="comment" id="f28942cb8994436b97ed8883426b2992"> <div class="comment-author"><a href="https://github.com/soenderby">Jakob Sønderby Kristensen</a> <a href="#f28942cb8994436b97ed8883426b2992">#</a></div> <div class="comment-content"> <p> What are your thoughts on abstractions in test code? I have never found it necessary, but have at times been tempted to create abstractions in my test projects that themselves would require testing. This is usually only a consideration in projects with a complex test setup or very large test suites. </p> <p> I am also curious about your thoughts on adding additional logic to the implementation code with the sole purpose of making it easier to test. As an example: Adding a method to a class that makes it a more complete abstraction, but that method is never called in production code. </p> <p> My own opinion is split between keeping tests readable and potentially easier to maintain by using reusable abstractions, and keeping them simple and robust. </p> </div> <div class="comment-date">2025-12-05 13:02 UTC</div> </div> <div class="comment" id="eb7f86e6e0684eed92ee991b649b383d"> <div class="comment-author"><a href="/">Mark Seemann</a> <a href="#eb7f86e6e0684eed92ee991b649b383d">#</a></div> <div class="comment-content"> <p> Thank you for writing. Regarding abstractions in test code, the answer depends on how you define the term <em>abstraction</em>. I find Robert C. Martin's definition useful. </p> <blockquote> <p> "Abstraction is <em>the elimination of the irrelevant and the amplification of the essential.</em>" </p> <footer><cite><a href="/ref/doocautbm">Designing Object-Oriented C++ Applications Using The Booch Method</a>, ch. 00, Robert C. Martin, his emphasis</cite></footer> </blockquote> <p> Using this definition, I have no objection to adding abstractions to test code if necessary, but as you imply, if the test code is simple enough, it may not be necessary. You could consider <a href="http://www.natpryce.com/articles/000714.html">Test Data Builders</a>, custom assertions, setup methods, etc. as test-specific abstractions. But again, if you simplify the System Under Test (SUT) by making data immutable, you <a href="/2017/09/11/test-data-without-builders">don't need Test Data Builders</a> either, so I agree that the need for substantial test abstractions may be a smell indicating that the SUT is too complicated. </p> <p> Regarding your other question, I try to avoid APIs that exist exclusively to support testing, but even so, I think you can subcategorize doing that into a few buckets. Adding new methods or constructors that exist only to be called from unit tests? I don't do that, although you could argue that Constructor Injection is just that: Dependency Injection is often introduced to support testing, but it's also applicable in production code. The constructor that receives dependencies is also used to compose the production application. </p> <p> Additionally, people often ask whether it's okay to make <code>internal</code> or <code>private</code> methods <code>public</code> so that it's possible to test them. In a code base created with test-driven development, <a href="/2021/09/13/unit-testing-private-helper-methods">this shouldn't be necessary</a>, but again, if you have a legacy code base, other rules apply. </p> <p> Another category of code that may at first spring into existence to support testing is what we may term <em>inspection APIs</em>. This could be a read-only property or field accessor that you can query in order to make an assertion. You may also decide to give an composite value <a href="/2021/05/03/structural-equality-for-better-tests">structural equality to improve testing</a>. Or, in property-based testing, you may use the <a href="https://fsharpforfunandprofit.com/posts/property-based-testing-3/#inverseRev">There and back again</a> technique, where one of the directions isn't entirely required. For example, if I were to repeat the <a href="https://codingdojo.org/kata/RomanNumerals/">Roman Numerals kata</a> with property-based testing today, I'd add a 'formatter' or 'serializer', so that I could take any normal integer, format it as a Roman numeral, and then parse it again. This is quite common when testing parsers and the like. You could argue that the formatter isn't strictly required for the job, but it makes testing easier, and usually turns out to be handy in its own right. </p> <p> This tends to be a generalizable observation. <a href="/2011/11/10/TDDimprovesreusability">A test is the first client of the SUT</a>, so if a test needs a capability, it's likely that other client code might find that capability useful, too. It happens that I write a bit of test-helper code that I eventually decide to move to the production code base for that reason. </p> </div> <div class="comment-date">2025-12-10 15:35 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>. Mark Seemann https://blog.ploeh.dk/2025/12/01/treat-test-code-like-production-code Result is the most boring sum type https://blog.ploeh.dk/2025/11/24/result-is-the-most-boring-sum-type/ Mon, 24 Nov 2025 15:15:00 UTC <div id="post"> <p> <em>If you don't see the point, you may be looking in the wrong place.</em> </p> <p> I regularly encounter programmers who are curious about statically typed functional programming, but are struggling to understand the point of <a href="https://en.wikipedia.org/wiki/Tagged_union">sum types</a> (also known as Discriminated Unions, Union Types, or similar). Particularly, I get the impression that recently various <a href="https://x.com/hillelogram/status/1445435617047990273">thought leaders</a> have begun talking about <a href="https://en.wikipedia.org/wiki/Result_type">Result types</a>. </p> <p> There are deep mathematical reasons to start with Results, but on the other hand, I can understand if many learners are left nonplussed. After all, <a href="/2025/10/15/result-isomorphism">Result types are roughly equivalent to exceptions</a>, and since most languages already come with exceptions, it can be difficult to see the point. </p> <p> The short response is that there's a natural explanation. A Result type is, so to speak, the fundamental sum type. From it, you can construct all other sum types. Thus, you can say that Results are the most abstract of all sum types. In that light, it's understandable if you struggle to see how they are useful. </p> <h3 id="f4ab82fa70e3481b9a8bb3bc2c9132b8"> Coproduct <a href="#f4ab82fa70e3481b9a8bb3bc2c9132b8">#</a> </h3> <p> My goal with this article is to point out why and how Result types are the most abstract, and perhaps least interesting, sum types. The point is not to make Result types compelling, or sell sum types in general. Rather, my point is that if you're struggling to understand what all the fuss is about <a href="https://en.wikipedia.org/wiki/Algebraic_data_type">algebraic data types</a>, perhaps Result types are the wrong place to start. </p> <p> In the following, I will tend to call Result by another name: <a href="/2018/06/11/church-encoded-either">Either</a>, which is also the name used in <a href="https://www.haskell.org/">Haskell</a>, where it encodes <a href="https://bartoszmilewski.com/2015/01/07/products-and-coproducts/">a universal construction called a <em>coproduct</em></a>. Where Result indicates a choice between success and failure, Either models a choice between 'left' and 'right'. </p> <p> Although the English language allows the pun 'right = correct', and thereby the mnemonic that the right value is the opposite of failure, 'left' and 'right' are otherwise meant to be as neutral as possible. Ideally, Either carries no semantic value. This is what we would expect from a 'most abstract' representation. </p> <h3 id="0c2f5e20a5c3485c896867d0d121589b"> Canonical representation <a href="#0c2f5e20a5c3485c896867d0d121589b">#</a> </h3> <p> As <a href="https://thinkingwithtypes.com/">Thinking with Types</a> does an admirable job of explaining, Either is part of a canonical representation of types, in which we can rewrite any type as a sum of products. In this context, a <em>product</em> is a pair, as <a href="https://bartoszmilewski.com/2015/01/07/products-and-coproducts/">also outlined by Bartosz Milewski</a>. </p> <p> The point is that we may rewrite any type to a combination of pairs and Either values, with the Either values on the outside. Such rewrites work both ways. You can rewrite any type to a combination of pairs and Eithers, or you can turn a combination of pairs and Eithers into more descriptive types. Since two-way translation is possible, we observe that the representations are isomorphic. </p> <h3 id="c5a93e795c064496bfe9a86c8d95c5ef"> Isomorphism with Maybe <a href="#c5a93e795c064496bfe9a86c8d95c5ef">#</a> </h3> <p> Perhaps the simplest example is the <a href="/2022/07/18/natural-transformations">natural transformation</a> between <code>Either () a</code> and <code>Maybe a</code>, or, in <a href="https://fsharp.org/">F#</a> syntax, <code>Result&lt;&#39;a,unit&gt;</code> and <code>&#39;a&nbsp;option</code>. The <a href="/2022/07/18/natural-transformations">Natural transformations</a> article shows an F# example. </p> <p> For illustration, we may translate this isomorphism to C# in order to help readers who are more comfortable with object-oriented C-like syntax. We may reuse the <code>IgnoreLeft</code> implementation, also from <a href="/2022/07/18/natural-transformations">Natural transformations</a>, to implement a translation from <code><span style="color:#2b91af;">IEither</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:#2b91af;">R</span>&gt;</code> to <code><span style="color:#2b91af;">IMaybe</span>&lt;<span style="color:#2b91af;">R</span>&gt;</code>. </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">IMaybe</span>&lt;<span style="color:#2b91af;">R</span>&gt;&nbsp;<span style="color:#74531f;">ToMaybe</span>&lt;<span style="color:#2b91af;">R</span>&gt;(<span style="color:blue;">this</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:#2b91af;">R</span>&gt;&nbsp;<span style="font-weight:bold;color:#1f377f;">source</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">source</span>.<span style="font-weight:bold;color:#74531f;">IgnoreLeft</span>(); }</pre> </p> <p> In order to go the other way, we may define <code>ToMaybe</code>'s counterpart like this: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:#2b91af;">T</span>&gt;&nbsp;<span style="color:#74531f;">ToEither</span>&lt;<span style="color:#2b91af;">T</span>&gt;(<span style="color:blue;">this</span>&nbsp;<span style="color:#2b91af;">IMaybe</span>&lt;<span style="color:#2b91af;">T</span>&gt;&nbsp;<span style="font-weight:bold;color:#1f377f;">source</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">source</span>.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">ToEitherVisitor</span>&lt;<span style="color:#2b91af;">T</span>&gt;()); } <span style="color:blue;">private</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">ToEitherVisitor</span>&lt;<span style="color:#2b91af;">T</span>&gt;&nbsp;:&nbsp;<span style="color:#2b91af;">IMaybeVisitor</span>&lt;<span style="color:#2b91af;">T</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:#2b91af;">T</span>&gt;&gt; { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:#2b91af;">T</span>&gt;&nbsp;VisitNothing&nbsp;=&gt;&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Left</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:#2b91af;">T</span>&gt;(<span style="color:#2b91af;">Unit</span>.Instance); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:#2b91af;">T</span>&gt;&nbsp;<span style="font-weight:bold;color:#74531f;">VisitJust</span>(<span style="color:#2b91af;">T</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">just</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Right</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:#2b91af;">T</span>&gt;(<span style="font-weight:bold;color:#1f377f;">just</span>); &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> The following two parametrized tests demonstrate the isomorphisms. </p> <p> <pre>[<span style="color:#2b91af;">Theory</span>,&nbsp;<span style="color:#2b91af;">ClassData</span>(<span style="color:blue;">typeof</span>(<span style="color:#2b91af;">UnitIntEithers</span>))] <span style="color:blue;">public</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="font-weight:bold;color:#74531f;">IsomorphismViaMaybe</span>(<span style="color:#2b91af;">IEither</span>&lt;<span style="color:#2b91af;">Unit</span>,&nbsp;<span style="color:blue;">int</span>&gt;&nbsp;<span style="font-weight:bold;color:#1f377f;">expected</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">expected</span>.<span style="font-weight:bold;color:#74531f;">ToMaybe</span>().<span style="font-weight:bold;color:#74531f;">ToEither</span>(); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(<span style="font-weight:bold;color:#1f377f;">expected</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>); } [<span style="color:#2b91af;">Theory</span>,&nbsp;<span style="color:#2b91af;">ClassData</span>(<span style="color:blue;">typeof</span>(<span style="color:#2b91af;">StringMaybes</span>))] <span style="color:blue;">public</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="font-weight:bold;color:#74531f;">IsomorphismViaEither</span>(<span style="color:#2b91af;">IMaybe</span>&lt;<span style="color:blue;">string</span>&gt;&nbsp;<span style="font-weight:bold;color:#1f377f;">expected</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">expected</span>.<span style="font-weight:bold;color:#74531f;">ToEither</span>().<span style="font-weight:bold;color:#74531f;">ToMaybe</span>(); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(<span style="font-weight:bold;color:#1f377f;">expected</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>); }</pre> </p> <p> The first test starts with an Either value, converts it to <a href="/2022/04/25/the-maybe-monad">Maybe</a>, and then converts the Maybe value back to an Either value. The second test starts with a Maybe value, converts it to Either, and converts it back to Maybe. In both cases, the <code>actual</code> value is equal to the <code>expected</code> value, which was also the original input. </p> <p> Being able to map between Either and Maybe (or Result and Option, if you prefer) is hardly illuminating, since Maybe, too, is a general-purpose data structure. If this all seems a bit abstract, I can see why. Some more specific examples may help. </p> <h3 id="dc8fbf510b8f44f4a52d7d55341ff10c"> Calendar periods in F# <a href="#dc8fbf510b8f44f4a52d7d55341ff10c">#</a> </h3> <p> Occasionally I run into the need to treat different calendar periods, such as days, months, and years, in a consistent way. To my recollection, the first time I <a href="/2013/10/21/replace-overloading-with-discriminated-unions">described a model</a> for that was in 2013. In short, in F# you can define a discriminated union for that purpose: </p> <p> <pre><span style="color:blue;">type</span>&nbsp;<span style="color:#066555;">Period</span>&nbsp;=&nbsp;<span style="color:#066555;">Year</span>&nbsp;<span style="color:blue;">of</span>&nbsp;<span style="color:#066555;">int</span>&nbsp;|&nbsp;<span style="color:#066555;">Month</span>&nbsp;<span style="color:blue;">of</span>&nbsp;<span style="color:#066555;">int</span>&nbsp;*&nbsp;<span style="color:#066555;">int</span>&nbsp;|&nbsp;<span style="color:#066555;">Day</span>&nbsp;<span style="color:blue;">of</span>&nbsp;<span style="color:#066555;">int</span>&nbsp;*&nbsp;<span style="color:#066555;">int</span>&nbsp;*&nbsp;<span style="color:#066555;">int</span></pre> </p> <p> A year is just a single integer, whereas a day is a triple, obviously with the components arranged in a sane order, with <code>Day (2025, 11, 14)</code> representing November 14, 2025. </p> <p> Since this is a three-way discriminated union, whereas Either (or, in F#: Result) only has two mutually exclusive options, we need to nest one inside of another to represent this type in canonical form: <code><span style="color:#066555;">Result</span>&lt;<span style="color:#066555;">int</span>,&nbsp;<span style="color:#066555;">Result</span>&lt;(<span style="color:#066555;">int</span>&nbsp;*&nbsp;<span style="color:#066555;">int</span>),&nbsp;(<span style="color:#066555;">int</span>&nbsp;*&nbsp;(<span style="color:#066555;">int</span>&nbsp;*&nbsp;<span style="color:#066555;">int</span>))&gt;&gt;</code>. Note that the 'outer' Result is a choice between a single integer (the year) and another Result value. The inner Result value then presents a choice between a month and a day. </p> <p> Converting back and forth is straightforward: </p> <p> <pre><span style="color:blue;">let</span>&nbsp;<span style="color:#74531f;">periodToCanonical</span>&nbsp;=&nbsp;<span style="color:blue;">function</span> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Year</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">y</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Ok</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">y</span> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Month</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>)&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Error</span>&nbsp;(<span style="color:#066555;">Ok</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>)) &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Day</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">d</span>)&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Error</span>&nbsp;(<span style="color:#066555;">Error</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;(<span style="font-weight:bold;color:#1f377f;">m</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">d</span>))) <span style="color:blue;">let</span>&nbsp;<span style="color:#74531f;">canonicalToPeriod</span>&nbsp;=&nbsp;<span style="color:blue;">function</span> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Ok</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">y</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Year</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">y</span> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Error</span>&nbsp;(<span style="color:#066555;">Ok</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>))&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Month</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>) &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Error</span>&nbsp;(<span style="color:#066555;">Error</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;(<span style="font-weight:bold;color:#1f377f;">m</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">d</span>)))&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Day</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">d</span>)</pre> </p> <p> In F# this translations may strike you as odd, since the choice between <code>Ok</code> and <code>Error</code> hardly comes across as neutral. Even so, there's no loss of information when translating back and forth between the two representations. </p> <p> <pre>&gt; Month (2025, 12) |&gt; periodToCanonical;; val it: Result&lt;int,Result&lt;(int * int),(int * (int * int))&gt;&gt; = Error (Ok (2025, 12)) &gt; Error (Ok (2025, 12)) |&gt; canonicalToPeriod;; val it: Period = Month (2025, 12)</pre> </p> <p> The implied semantic difference between <code>Ok</code> and <code>Error</code> is one reason I favour Either over Result, when I have the choice. When translating to C#, I do have a choice, since there's no built-in coproduct data type. </p> <h3 id="908edd4b21e4412ea20280cccf99cc38"> Calendar periods in C# <a href="#908edd4b21e4412ea20280cccf99cc38">#</a> </h3> <p> If you have been perusing 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>, you may have noticed an <code>IPeriod</code> interface. Since this is <a href="/2021/03/01/pendulum-swing-internal-by-default">internal by default</a>, I haven't discussed it much, but it's equivalent to the above F# discriminated union. It's used to enumerate restaurant reservations for a day, a month, or even a whole year. </p> <p> Since this is a <a href="/2018/06/25/visitor-as-a-sum-type">Visitor-encoded sum type</a>, most of the information about data representation can be discerned from the Visitor interface: </p> <p> <pre><span style="color:blue;">internal</span>&nbsp;<span style="color:blue;">interface</span>&nbsp;<span style="color:#2b91af;">IPeriodVisitor</span>&lt;<span style="color:#2b91af;">T</span>&gt; { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">T</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitYear</span>(<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">year</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">T</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitMonth</span>(<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">year</span>,&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">month</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">T</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitDay</span>(<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">year</span>,&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">month</span>,&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">day</span>); }</pre> </p> <p> Given an appropriate Either definition, we can translate any <code>IPeriod</code> value into a nested Either, just like the above F# example. </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">ToCanonicalPeriodVisitor</span>&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IPeriodVisitor</span>&lt;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:blue;">int</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;&gt;&gt; { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:blue;">int</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;&gt;&nbsp;<span style="font-weight:bold;color:#74531f;">VisitDay</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">year</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">month</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">day</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Right</span>&lt;<span style="color:blue;">int</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;&gt;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Right</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;((<span style="font-weight:bold;color:#1f377f;">year</span>,&nbsp;(<span style="font-weight:bold;color:#1f377f;">month</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">day</span>)))); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:blue;">int</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;&gt;&nbsp;<span style="font-weight:bold;color:#74531f;">VisitMonth</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">year</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">month</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Right</span>&lt;<span style="color:blue;">int</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;&gt;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Left</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;((<span style="font-weight:bold;color:#1f377f;">year</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">month</span>))); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;<span style="color:blue;">int</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;&gt;&nbsp;<span style="font-weight:bold;color:#74531f;">VisitYear</span>(<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">year</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Left</span>&lt;<span style="color:blue;">int</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;&gt;(<span style="font-weight:bold;color:#1f377f;">year</span>); &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> Look out! I've encoded year, month, and day from left to right as I did before. This means that the leftmost alternative indicates a year, and the rightmost alternative in the nested Either value indicates a day. This is structurally equivalent to the above F# encoding. If, however, you are used to thinking about <em>left</em> values indicating error, and <em>right</em> values indicating success, then the two mappings are not similar. In the F# encoding, an 'outer' <code>Ok</code> value indicates a year, whereas here, a left value indicates a year. This may be confusing if your are expecting a <em>right</em> value, corresponding to <code>Ok</code>. </p> <p> The structure is the same, but this may be something to be aware of going forward. </p> <p> You can translate the other way without loss of information. </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">ToPeriodVisitor</span>&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEitherVisitor</span>&lt;<span style="color:blue;">int</span>,&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;,&nbsp;<span style="color:#2b91af;">IPeriod</span>&gt; { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IPeriod</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitLeft</span>(<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">left</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Year</span>(<span style="font-weight:bold;color:#1f377f;">left</span>); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IPeriod</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitRight</span>(<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&gt;&nbsp;<span style="font-weight:bold;color:#1f377f;">right</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">right</span>.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">ToMonthOrDayVisitor</span>()); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">private</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">ToMonthOrDayVisitor</span>&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEitherVisitor</span>&lt;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>),&nbsp;(<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>)),&nbsp;<span style="color:#2b91af;">IPeriod</span>&gt; &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IPeriod</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitLeft</span>((<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>)&nbsp;<span style="font-weight:bold;color:#1f377f;">left</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>)&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">left</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Month</span>(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IPeriod</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitRight</span>((<span style="color:blue;">int</span>,&nbsp;(<span style="color:blue;">int</span>,&nbsp;<span style="color:blue;">int</span>))&nbsp;<span style="font-weight:bold;color:#1f377f;">right</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;(<span style="font-weight:bold;color:#1f377f;">m</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">d</span>))&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">right</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Day</span>(<span style="font-weight:bold;color:#1f377f;">y</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">m</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">d</span>); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> It's all fairly elementary, although perhaps a bit cumbersome. The point of it all, should you have forgotten, is only to demonstrate that we can encode any sum type as a combination of Either values (and pairs). </p> <p> A test like this demonstrates that these two translations comprise a true isomorphism: </p> <p> <pre>[<span style="color:#2b91af;">Theory</span>,&nbsp;<span style="color:#2b91af;">ClassData</span>(<span style="color:blue;">typeof</span>(<span style="color:#2b91af;">PeriodData</span>))] <span style="color:blue;">public</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="font-weight:bold;color:#74531f;">IsomorphismViaEither</span>(<span style="color:#2b91af;">IPeriod</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">expected</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">expected</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">ToCanonicalPeriodVisitor</span>()) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">ToPeriodVisitor</span>()); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(<span style="font-weight:bold;color:#1f377f;">expected</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>); }</pre> </p> <p> This test converts arbitrary <code>IPeriod</code> values to nested Either values, and then translates them back to the same <code>IPeriod</code> value. </p> <h3 id="228670b9d03c4fc7b2057d95488ce02b"> Payment types in F# <a href="#228670b9d03c4fc7b2057d95488ce02b">#</a> </h3> <p> Perhaps you are not convinced by a single example, so let's look at one more. In 2016 I was writing some code to integrate with a payment gateway. To model the various options that the gateway made available, I <a href="/2016/11/28/easy-domain-modelling-with-types">defined a discriminated union</a>, repeated here: </p> <p> <pre><span style="color:blue;">type</span>&nbsp;<span style="color:#066555;">PaymentService</span>&nbsp;=&nbsp;{&nbsp;Name&nbsp;:&nbsp;<span style="color:#066555;">string</span>;&nbsp;Action&nbsp;:&nbsp;<span style="color:#066555;">string</span>&nbsp;} &nbsp; <span style="color:blue;">type</span>&nbsp;<span style="color:#066555;">PaymentType</span>&nbsp;= |&nbsp;<span style="color:#066555;">Individual</span>&nbsp;<span style="color:blue;">of</span>&nbsp;<span style="color:#066555;">PaymentService</span> |&nbsp;<span style="color:#066555;">Parent</span>&nbsp;<span style="color:blue;">of</span>&nbsp;<span style="color:#066555;">PaymentService</span> |&nbsp;<span style="color:#066555;">Child</span>&nbsp;<span style="color:blue;">of</span>&nbsp;originalTransactionKey&nbsp;:&nbsp;<span style="color:#066555;">string</span>&nbsp;*&nbsp;paymentService&nbsp;:&nbsp;<span style="color:#066555;">PaymentService</span></pre> </p> <p> This looks a little more complicated, since it also makes use of the custom <code>PaymentService</code> type. Even so, converting to the canonical sum of products representation, and back again, is straightforward: </p> <p> <pre><span style="color:blue;">let</span>&nbsp;<span style="color:#74531f;">paymentToCanonical</span>&nbsp;=&nbsp;<span style="color:blue;">function</span> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Individual</span>&nbsp;{&nbsp;Name&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">n</span>;&nbsp;Action&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>&nbsp;}&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Ok</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">n</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>) &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Parent</span>&nbsp;{&nbsp;Name&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">n</span>;&nbsp;Action&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>&nbsp;}&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Error</span>&nbsp;(<span style="color:#066555;">Ok</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">n</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>)) &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Child</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">k</span>,&nbsp;{&nbsp;Name&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">n</span>;&nbsp;Action&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>&nbsp;})&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Error</span>&nbsp;(<span style="color:#066555;">Error</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">k</span>,&nbsp;(<span style="font-weight:bold;color:#1f377f;">n</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>))) <span style="color:blue;">let</span>&nbsp;<span style="color:#74531f;">canonicalToPayment</span>&nbsp;=&nbsp;<span style="color:blue;">function</span> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Ok</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">n</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>)&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Individual</span>&nbsp;{&nbsp;Name&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">n</span>;&nbsp;Action&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Error</span>&nbsp;(<span style="color:#066555;">Ok</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">n</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>))&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Parent</span>&nbsp;{&nbsp;Name&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">n</span>;&nbsp;Action&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;<span style="color:#066555;">Error</span>&nbsp;(<span style="color:#066555;">Error</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">k</span>,&nbsp;(<span style="font-weight:bold;color:#1f377f;">n</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>)))&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#066555;">Child</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">k</span>,&nbsp;{&nbsp;Name&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">n</span>;&nbsp;Action&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>&nbsp;})</pre> </p> <p> Again, there's no loss of information going back and forth between these two representations, even if the use of the <code>Error</code> case seems confusing. </p> <p> <pre>&gt; Child ("1234ABCD", { Name = "MasterCard"; Action = "Pay" }) |&gt; paymentToCanonical;; val it: Result&lt;(string * string), Result&lt;(string * string),(string * (string * string))&gt;&gt; = Error (Error ("1234ABCD", ("MasterCard", "Pay"))) &gt; Error (Error ("1234ABCD", ("MasterCard", "Pay"))) |&gt; canonicalToPayment;; val it: PaymentType = Child ("1234ABCD", { Name = "MasterCard" Action = "Pay" })</pre> </p> <p> Again, you might wonder why anyone would ever do that, and you'd be right. As a general rule, there's no reason to do this, and if you think that the canonical representation is more abstract, and harder to understand, I'm not going to argue. The point is, rather, that products (pairs) and coproducts (Either values) are universal building blocks of algebraic data types. </p> <h3 id="705e36f3709e4913904882d8b05eb7a9"> Payment types in C# <a href="#705e36f3709e4913904882d8b05eb7a9">#</a> </h3> <p> As in the calendar-period example, it's possible to demonstrate the concept in alternative programming languages. For the benefit of programmers with a background in C-like languages, I once more present the example in C#. The starting point is where <a href="/2018/06/25/visitor-as-a-sum-type">Visitor as a sum type</a> ends. The code is also <a href="https://github.com/ploeh/ChurchEncoding">available on GitHub</a>. </p> <p> Translation to canonical form may be done with a <a href="https://en.wikipedia.org/wiki/Visitor_pattern">Visitor</a> like this: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">ToCanonicalPaymentTypeVisitor</span>&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IPaymentTypeVisitor</span>&lt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;&gt;&gt; { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#74531f;">VisitChild</span>(<span style="color:#2b91af;">ChildPaymentService</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">child</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Right</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;&gt;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Right</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#1f377f;">child</span>.OriginalTransactionKey, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#1f377f;">child</span>.PaymentService.Name, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#1f377f;">child</span>.PaymentService.Action &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;))); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#74531f;">VisitIndividual</span>(<span style="color:#2b91af;">PaymentService</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">individual</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Left</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;&gt;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span style="font-weight:bold;color:#1f377f;">individual</span>.Name,&nbsp;<span style="font-weight:bold;color:#1f377f;">individual</span>.Action)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#74531f;">VisitParent</span>(<span style="color:#2b91af;">PaymentService</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">parent</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Right</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;&gt;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Left</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span style="font-weight:bold;color:#1f377f;">parent</span>.Name,&nbsp;<span style="font-weight:bold;color:#1f377f;">parent</span>.Action))); &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> If you find the method signatures horrible and near-unreadable, I don't blame you. This is an excellent example that C# (together with similar languages) inhabit the <a href="/2019/12/16/zone-of-ceremony">zone of ceremony</a>; compare this <code>ToCanonicalPaymentTypeVisitor</code> to the above F# <code>paymentToCanonical</code> function, which performs exactly the same work while being as strongly statically typed. </p> <p> Another Visitor translates the other way. </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">FromCanonicalPaymentTypeVisitor</span>&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEitherVisitor</span>&lt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;,&nbsp;<span style="color:#2b91af;">IPaymentType</span>&gt; { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IPaymentType</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitLeft</span>((<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>)&nbsp;<span style="font-weight:bold;color:#1f377f;">left</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">name</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">action</span>)&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">left</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Individual</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">PaymentService</span>(<span style="font-weight:bold;color:#1f377f;">name</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">action</span>)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IPaymentType</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitRight</span>(<span style="color:#2b91af;">IEither</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&gt;&nbsp;<span style="font-weight:bold;color:#1f377f;">right</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">right</span>.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">CanonicalParentChildPaymentTypeVisitor</span>()); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">private</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">CanonicalParentChildPaymentTypeVisitor</span>&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEitherVisitor</span>&lt;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>),&nbsp;(<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>)),&nbsp;<span style="color:#2b91af;">IPaymentType</span>&gt; &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IPaymentType</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitLeft</span>((<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>)&nbsp;<span style="font-weight:bold;color:#1f377f;">left</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">name</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">action</span>)&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">left</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Parent</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">PaymentService</span>(<span style="font-weight:bold;color:#1f377f;">name</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">action</span>)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IPaymentType</span>&nbsp;<span style="font-weight:bold;color:#74531f;">VisitRight</span>((<span style="color:blue;">string</span>,&nbsp;(<span style="color:blue;">string</span>,&nbsp;<span style="color:blue;">string</span>))&nbsp;<span style="font-weight:bold;color:#1f377f;">right</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;(<span style="font-weight:bold;color:#1f377f;">k</span>,&nbsp;(<span style="font-weight:bold;color:#1f377f;">n</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>))&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">right</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Child</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">ChildPaymentService</span>(<span style="font-weight:bold;color:#1f377f;">k</span>,&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">PaymentService</span>(<span style="font-weight:bold;color:#1f377f;">n</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">a</span>))); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> Here I even had to split one generic type signature over multiple lines, in order to prevent horizontal scrolling. At least you have to grant the C# language that it's flexible enough to allow that. </p> <p> Now that it's possible to translate both ways, a simple tests demonstrates the isomorphism. </p> <p> <pre>[<span style="color:#2b91af;">Theory</span>,&nbsp;<span style="color:#2b91af;">ClassData</span>(<span style="color:blue;">typeof</span>(<span style="color:#2b91af;">PaymentTypes</span>))] <span style="color:blue;">public</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="font-weight:bold;color:#74531f;">IsomorphismViaEither</span>(<span style="color:#2b91af;">IPaymentType</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">expected</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="font-weight:bold;color:#1f377f;">expected</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">ToCanonicalPaymentTypeVisitor</span>()) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="font-weight:bold;color:#74531f;">Accept</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">FromCanonicalPaymentTypeVisitor</span>()); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(<span style="font-weight:bold;color:#1f377f;">expected</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>); }</pre> </p> <p> This test translates an arbitrary <code>IPaymentType</code> into canonical form, then translates that representation back to an <code>IPaymentType</code> value, and checks that the two values are identical. There's no loss of information either way. </p> <p> This and the previous example may seem like a detour around the central point that I'm trying to make: That Result (or Either) is the most boring sum type. I could have made the point, including examples, in a few lines of Haskell, but that language is so efficient at that kind of work that I fear that the syntax would look like pseudocode to programmers used to C-like languages. Additionally, Haskell programmers don't need my help writing small mappings like the ones shown here. </p> <h3 id="d0317d94363e404bb2b42e9f3c771673"> Conclusion <a href="#d0317d94363e404bb2b42e9f3c771673">#</a> </h3> <p> Result (or Either) is as a fundamental building block in the context of algebraic data types. As such, this type may be considered the most boring sum type, since it effectively represents any other sum type, up to isomorphism. </p> <p> Object-oriented programmers trying to learn functional programming sometimes struggle to see the light. One barrier to understanding the power of algebraic data types may be related to starting a learning path with a Result type. Since <a href="/2025/10/15/result-isomorphism">Results are equivalent to exceptions</a>, people understandably have a hard time seeing how Result values are better. Since Result types are so abstract, it can be difficult to see the wider perspective. This doubly applies if a teacher leads with Result, with it's success/failure semantics, rather than with Either and its more neutral left/right labels. </p> <p> Since Either is the fundamental sum type, it follows that any other sum type, being more specialized, carries more meaning, and therefore may be more interesting, and more illuminating as examples. In this article, I've used a few simple, but specialized sum types with the intention to help the reader see the difference. </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>. Mark Seemann https://blog.ploeh.dk/2025/11/24/result-is-the-most-boring-sum-type Empirical software prototyping https://blog.ploeh.dk/2025/11/17/empirical-software-prototyping/ Mon, 17 Nov 2025 08:38:00 UTC <div id="post"> <p> <em>How do you add tests to a proof-of-concept? Should you?</em> </p> <p> This is the second article in a small series on <a href="/2025/10/27/empirical-test-after-development">empirical test-after development</a>. I'll try to answer an occasionally-asked question: Should one use test-driven development (TDD) for prototyping? </p> <p> There are variations on this question, but it tends to come up when discussing TDD. Some <a href="https://x.com/hillelogram/status/1445435617047990273">software thought leaders</a> proclaim that you should always take advantage of TDD when writing code. The short response is that there are exceptions to that rule. Those thought leaders know that, too, but they choose to communicate the way that they do in order to make a point. I don't blame them, and I use a similar style of communication from time to time. If you hedge every sentence you utter with qualifications, the message often disappears in unclear language. Thus, when someone admonishes that you should always follow TDD, what they really mean (I suppose; I'm not a telepath) is that you should predominantly use TDD. More than 80% of the time. </p> <p> This is a common teaching tool. A competent teacher takes into account the skill level of a student. A new learner has to start with the basics before advanced topics. Early in the learning process, there's no room for sophistication. Even when a teacher understands that there are exceptions, he or she starts with a general rule, like 'you should always do TDD'. </p> <p> While this may seem like a digression, this detour answers most of the questions related to software prototyping. People find it difficult to apply TDD when developing a prototype. I do, too. So don't. </p> <h3 id="873f1d7273e94b7eb9028fde1d75d890"> Prototyping or proof-of-concept? <a href="#873f1d7273e94b7eb9028fde1d75d890">#</a> </h3> <p> I've already committed the sin of using <em>prototype</em> and <em>proof-of-concept</em> interchangeably. This only reflects how I use these terms in conversation. While I'm aware that the internet offers articles to help me distinguish, I find the differences too subtle to be of use when communicating with other people. Even if I learn the fine details that separate one from the other, I can't be sure that the person I'm talking to shares that understanding. </p> <p> Since <em>prototype</em> is easier to say, I tend to use that term more than <em>proof-of-concept</em>. In any case, a prototype in this context is an exploration of an idea. You surmise that it's possible to do something in a certain way, but you're not sure. Before committing to the uncertain idea, you develop an isolated code base to vet the concept. </p> <p> This could be an idea for an algorithm, use of a new technology such as a framework or reusable library, a different cloud platform, or even a new programming language. </p> <p> Such exploration is already challenging in itself. How is the API of the library structured? Should you call <code>IsFooble</code> or <code>HasFooble</code> here? How do you write a <code>for</code> loop in <a href="https://en.wikipedia.org/wiki/APL_(programming_language)">APL</a>? How does one even compile a <a href="https://www.java.com">Java</a> program? How do you programmatically provision new resources in <a href="https://learn.microsoft.com/en-us/fabric/fundamentals/microsoft-fabric-overview">Microsoft Fabric</a>? How do you convert a <a href="https://en.wikipedia.org/wiki/JPEG">JPG</a> file to <a href="https://en.wikipedia.org/wiki/PDF">PDF</a> on the server? </p> <p> There are plenty of questions like these where you don't even know the shape of things. The point of the exercise is often to figure those things out. When you don't know how APIs are organized, or which technologies are available to you, writing tests first is difficult. No wonder people sometimes ask me about this. </p> <h3 id="33bc345c3bb34ca795532ab0b13e4f19"> Code to throw away <a href="#33bc345c3bb34ca795532ab0b13e4f19">#</a> </h3> <p> The very nature of a prototype is that it's an experiment designed to explore an idea. The safest way to engage with a prototype is to create an isolated code base for that particular purpose. A prototype is not an <a href="https://en.wikipedia.org/wiki/Minimum_viable_product">MVP</a> or an early version of the product. It is a deliberately unstructured exploration of what's possible. The entire purpose of a prototype is to <em>learn</em>. Often the exploration process is time-boxed. </p> <p> If the prototype turns out to be successful, you may proceed to implement the idea in your production code base. Even if you didn't use TDD for the prototype, you should now have learned enough that you can apply TDD for the production implementation. </p> <p> The most common obstacle to this chain of events, I understand, is that 'bosses' demand that a successful prototype be put into production. Try to resist such demands. It often helps planning for this from the outset. If you can, do the prototype in a way that effectively prevents such predictable demands. If you're exploring the viability of a new algorithm, write it in an alternative programming language. For example, I've written prototypes in <a href="https://www.haskell.org/">Haskell</a>, which very effectively prevents demands that the code be put into production. </p> <p> If your organization is a little behind the cutting edge, you can also write the prototype in a newer version of your language or run-time. Use functional programming if you normally use object-oriented design. Or you may pick an auxiliary technology incompatible with how you normally do things: Use the 'wrong' JSON serializer library, an in-memory database, write a command-line program if you need a GUI, or vice versa. </p> <p> You're the technical expert. <a href="/2019/03/18/the-programmer-as-decision-maker">Make technical decisions</a>. Surely, you can come up with something that sounds convincing enough to a non-technical stakeholder to prevent putting the prototype into production. </p> <p> To be sure we're on firm moral ground here: I'm not advocating that you should be dishonest, or work against the interests of your organization. Rather, I suggest that you act politically. Understand what motivates other people. Non-technical stakeholders usually don't have the insight to understand why a successful prototype shouldn't be promoted to production code. Unfortunately, they often view programmers as typists, and with that view, it seems wasteful to repeat the work of typing in the prototype code. <a href="/2018/09/17/typing-is-not-a-programming-bottleneck">Typing, however, is not a bottleneck</a>, but it can be hard to convince other people of this. </p> <p> If all else fails, and you're forced to promote the prototype to production code, you now have a piece of legacy code on hand, in which case the techniques outlined in <a href="/2025/11/03/empirical-characterization-testing">the previous article</a> should prove useful. </p> <h3 id="92448892cad9447dab00ef4e1e82bcff"> Prototyping in existing code bases <a href="#92448892cad9447dab00ef4e1e82bcff">#</a> </h3> <p> A special case occurs when you need to do a prototype in an existing code base. You already have a big, complicated system, and you would like to explore whether a particular idea is applicable in that context. Perhaps data access is currently too slow, and you have an idea of how to speed things up, for example by <a href="/2022/02/14/a-conditional-sandwich-example">speculative prefetching</a>. When the problem is one of performance, you'll need to <a href="https://ericlippert.com/2012/12/17/performance-rant/">measure</a> in a realistic environment. This may prevent you from creating an isolated prototype code base. </p> <p> In such cases, use Git to your advantage. Make a new prototype branch and work there. You may deliberately choose to make it a long-lived <a href="https://martinfowler.com/bliki/FeatureBranch.html">feature branch</a>. Once the prototype is done, the code may now be so out of sync with <em>master</em> that 'merge conflicts' sounds like a plausible excuse to a non-technical stakeholder. As above, be political. </p> <p> In any case, don't merge the prototype branch, even if you could. Instead, use the knowledge gained during the prototype work to re-implement the new idea, this time using empirical software engineering techniques like TDD. </p> <h3 id="1533c57419f64e149a4aec070eb8f714"> Conclusion <a href="#1533c57419f64e149a4aec070eb8f714">#</a> </h3> <p> Prototyping is usually antithetical to TDD. On the other hand, TDD is an effective empirical method for software development. Without it, you have to seek other answers to the question: How do we know that this works? </p> <p> Due to the explorative nature of prototyping, testing of the prototype tends to be explorative as well. Start up the prototype, poke at it, see if it behaves as expected. While you do gain a limited amount of empirical knowledge from such a process, it's unsystematic and non-repeatable, so little <em>corroboration</em> of hypothesis takes place. Therefore, once the prototype work is done, it's important to proceed on firmer footing if the prototype was successful. </p> <p> The safest way is to put the prototype to the side, but use the knowledge to test-drive the production version of the idea. This may require a bit of political manoeuvring. If that fails, and you're forced to promote the prototype to production use, you may use the techniques for adding <a href="/2025/11/03/empirical-characterization-testing">empirical Characterization Tests</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>. Mark Seemann https://blog.ploeh.dk/2025/11/17/empirical-software-prototyping 100% coverage is not that trivial https://blog.ploeh.dk/2025/11/10/100-coverage-is-not-that-trivial/ Mon, 10 Nov 2025 12:00:00 UTC <div id="post"> <p> <em>Dispelling a myth I helped propagate.</em> </p> <p> Most people who have been around automated testing for a few years understand that <a href="/2015/11/16/code-coverage-is-a-useless-target-measure">code coverage is a useless target measure</a>. Unfortunately, through a game of Chinese whispers, this message often degenerates to the simpler, but incorrect, notion that code coverage is useless. </p> <p> As I've already covered in that article, code coverage may be useful for other reasons. That's not my agenda for this article. Rather, something about this discussion have been bothering me for a long time. </p> <p> Have you ever had an uneasy feeling about a topic, without being able to put your finger on exactly what the problem is? This happens to me regularly. I'm going along with the accepted narrative until the cognitive dissonance becomes so conspicuous that I can no longer ignore it. </p> <p> In this article, I'll grapple with the notion that 'reaching 100% code coverage is easy.' </p> <h3 id="1e210ae46a1b45d4a3764694d9128fc7"> Origins <a href="#1e210ae46a1b45d4a3764694d9128fc7">#</a> </h3> <p> This tends to come up when discussing code coverage. People will say that 100% code coverage isn't a useful measure, because it's easy to reach 100%. I have <a href="/2015/11/16/code-coverage-is-a-useless-target-measure">used that argument myself</a>. Fortunately I also cited my influences in 2015; in this case Martin Fowler's <a href="https://martinfowler.com/bliki/AssertionFreeTesting.html">Assertion Free Testing</a>. </p> <blockquote> <p> "[...] of course you can do this and have 100% code coverage - which is one reason why you have to be careful on interpreting code coverage data." </p> <footer><a href="https://martinfowler.com/bliki/AssertionFreeTesting.html">Assertion Free Testing</a>, Martin Fowler, 2004</footer> </blockquote> <p> This may not be the only source of such a claim, but it may have been a contributing factor. There's little wrong with Fowler's article, which doesn't make any groundless claims, but I can imagine how <a href="https://martinfowler.com/bliki/SemanticDiffusion.html">semantic diffusion</a> works on an idea like that. </p> <p> Fowler also wrote that it's "a story from a friend of a friend." When the source of a story is twice-removed like that, alarm bells should go off. This is the stuff that urban legends are made of, and I wonder if this isn't rather an example of 'programmer folk wisdom'. I've heard variations of that story many times over the years, from various people. </p> <h3 id="b6de8ca704e0437dadc73f58c0fe84fa"> It's not that easy <a href="#b6de8ca704e0437dadc73f58c0fe84fa">#</a> </h3> <p> Even though I've helped promulgate the idea that reaching 100% code coverage is easy if you cheat, I now realise that that's an overstatement. Even if you write no assertions, and surround the test code with a <code>try/catch</code> block, you can't trivially reach 100% coverage. There are going to be branches that you can't reach. </p> <p> This often happens in real code bases that query databases, call web services, and so on. If a branch depends on <a href="http://xunitpatterns.com/indirect%20input.html">indirect input</a>, you can't force execution down that path just by suppressing exceptions. </p> <p> An example is warranted. </p> <h3 id="11319fa843404ea193e56cc614603975"> Example <a href="#11319fa843404ea193e56cc614603975">#</a> </h3> <p> Consider this <code>ReadReservation</code> method in the <code>SqlReservationsRepository</code> class from the code base that accompanies my book <a href="/2021/06/14/new-book-code-that-fits-in-your-head">Code That Fits in Your Head</a>: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:blue;">async</span>&nbsp;<span style="color:#2b91af;">Task</span>&lt;<span style="color:#2b91af;">Reservation</span>?&gt;&nbsp;<span style="font-weight:bold;color:#74531f;">ReadReservation</span>(<span style="color:blue;">int</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">restaurantId</span>,&nbsp;<span style="color:#2b91af;">Guid</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">id</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">const</span>&nbsp;<span style="color:blue;">string</span>&nbsp;readByIdSql&nbsp;=&nbsp;<span style="color:maroon;">@&quot; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;[PublicId],&nbsp;[At],&nbsp;[Name],&nbsp;[Email],&nbsp;[Quantity] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM&nbsp;[dbo].[Reservations] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHERE&nbsp;[PublicId]&nbsp;=&nbsp;@id&quot;</span>; &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">using</span>&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">conn</span>&nbsp;=&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">SqlConnection</span>(ConnectionString); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">using</span>&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">cmd</span>&nbsp;=&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">SqlCommand</span>(readByIdSql,&nbsp;<span style="font-weight:bold;color:#1f377f;">conn</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#1f377f;">cmd</span>.Parameters.<span style="font-weight:bold;color:#74531f;">AddWithValue</span>(<span style="color:#a31515;">&quot;@id&quot;</span>,&nbsp;<span style="font-weight:bold;color:#1f377f;">id</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">await</span>&nbsp;<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>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">using</span>&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">rdr</span>&nbsp;=&nbsp;<span style="font-weight:bold;color:#8f08c4;">await</span>&nbsp;<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>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">if</span>&nbsp;(!<span style="font-weight:bold;color:#1f377f;">rdr</span>.<span style="font-weight:bold;color:#74531f;">Read</span>()) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">null</span>; &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">return</span>&nbsp;<span style="color:#74531f;">ReadReservationRow</span>(<span style="font-weight:bold;color:#1f377f;">rdr</span>); }</pre> </p> <p> Even though it only has a <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> of 2, most of it is unreachable to a test that tries to avoid hard work. </p> <p> You can try to cheat in the suggested way by adding a test like this: </p> <p> <pre>[<span style="color:#2b91af;">Fact</span>] <span style="color:blue;">public</span>&nbsp;<span style="color:blue;">async</span>&nbsp;<span style="color:#2b91af;">Task</span>&nbsp;<span style="font-weight:bold;color:#74531f;">ReadReservation</span>() { &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">try</span> &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">sut</span>&nbsp;=&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">SqlReservationsRepository</span>(<span style="color:#a31515;">&quot;dunno&quot;</span>); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="font-weight:bold;color:#8f08c4;">await</span>&nbsp;<span style="font-weight:bold;color:#1f377f;">sut</span>.<span style="font-weight:bold;color:#74531f;">ReadReservation</span>(0,&nbsp;<span style="color:#2b91af;">Guid</span>.<span style="color:#74531f;">NewGuid</span>()); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-weight:bold;color:#8f08c4;">catch</span>&nbsp;{&nbsp;} }</pre> </p> <p> Granted, this test passes, and if you had 0% code coverage before, it does improve the metric slightly. Interestingly, the <a href="https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-code-coverage">Coverlet collector for .NET</a> reports that only the first line, which creates the <code>conn</code> variable, is covered. I wonder, though, if this is due to some kind of compiler optimization associated with asynchronous execution that the coverage tool fails to capture. </p> <p> More understandably, execution reaches <code>conn.OpenAsync()</code> and crashes, since the test hasn't provided a connection to a real database. This is what happens if you run the test without the surrounding <code>try/catch</code> block. </p> <p> Coverlet reports 18% coverage, and that's as high you can get with 'the easy hack'. 100% is some distance away. </p> <h3 id="c6e5475f8257495f9c93e4b69e08f761"> Toward better coverage <a href="#c6e5475f8257495f9c93e4b69e08f761">#</a> </h3> <p> You may protest that we can do better than this. After all, with utter disregard for using proper arguments, I passed <code>"dunno"</code> as a connection string. Clearly that doesn't work. </p> <p> Couldn't we easily get to 100% by providing a proper connection string? Perhaps, but what's a proper connection string? </p> <p> It doesn't help if you pass a well-formed connection string instead of <code>"dunno"</code>. In fact, it will only slow down the test, because then <code>conn.OpenAsync()</code> will attempt to open the connection. If the database is unreachable, that statement will eventually time out and fail with an exception. </p> <p> Couldn't you, though, give it a connection string to a real database? </p> <p> Yes, you could. If you do that, though, you should make sure that the database has a schema compatible with <code>readByIdSql</code>. Otherwise, the query will fail. What happens if the implied schema changes? Now you need to make sure that the database is updated, too. This sounds error-prone. Perhaps you should automate that. </p> <p> Furthermore, you may easily cover the branch that returns <code>null</code>. After all, when you query for <code>Guid.NewGuid()</code>, that value is not going to be in the table. On the other hand, how will you cover the other branch; the one that returns a row? </p> <p> You can only do that if you know the ID of a value already in that table. You may write a second test that queries for that known value. Now you have 100% coverage. </p> <p> What you have done at this point, however, is no longer an easy cheat to get to 100%. You have, essentially, added integration tests of the data access subsystem. </p> <p> How about adding some assertions to make the tests useful? </p> <h3 id="5286d5b5be734102b73c181d8df7dbaf"> Integration tests for 100% <a href="#5286d5b5be734102b73c181d8df7dbaf">#</a> </h3> <p> In most systems, you will at least need some integration tests to reach 100% code coverage. While the code shown in <a href="/code-that-fits-in-your-head">Code That Fits in Your Head</a> doesn't have 100% code coverage (that was never my goal), it looks quite good. (It's hard to get a single number, because Coverlet apparently can't measure coverage by running multiple test projects, so I can only get partial results. Coverage is probably better than 80%, I estimate.) </p> <p> To test <code>ReadReservation</code> I wrote integration tests that automate setup and tear-down of a local test-specific database. The book, and the Git repository that accompanies it, has all the details. </p> <p> Getting to 100%, or even 80%, requires dedicated work. In a realistic code base, the claim that reaching 100% is trivial is hardly true. </p> <h3 id="5c0e004b31bb42208054e1e95f01b29d"> Conclusion <a href="#5c0e004b31bb42208054e1e95f01b29d">#</a> </h3> <p> Programmer folk wisdom 'knows' that code coverage is useless. One argument is that any fool can reach 100% by writing assertion-free tests surrounded by <code>try/catch</code> blocks. </p> <p> This is hardly true in most significant code bases. Whenever you deal with indirect input, <code>try/catch</code> is insufficient to control whereto execution branches. </p> <p> This suggests that high code-coverage numbers are good, and low numbers bad. <a href="/2018/11/12/what-to-test-and-not-to-test">What constitutes high and low is context-dependent</a>. What seems to remain true, however, is that code coverage is a useless target. This has little to do with how trivial it is to reach 100%, but rather everything to do with how humans respond to incentives. </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>. Mark Seemann https://blog.ploeh.dk/2025/11/10/100-coverage-is-not-that-trivial