ploeh blog https://blog.ploeh.dk danish software design en-us Mark Seemann Fri, 16 Apr 2021 06:30:08 UTC Fri, 16 Apr 2021 06:30:08 UTC Threading context through a catamorphism https://blog.ploeh.dk/2021/04/12/threading-context-through-a-catamorphism/ Mon, 12 Apr 2021 11:09:00 UTC <div id="post"> <p> <em>A problem solved after 1½ years.</em> </p> <p> You've probably noticed that it's easier to learn something new if it looks or sounds like something you already know. As a native Dane, I've found it easier to learn English and German than Russian and Japanese. If you originally were a Java or C# developer, you probably find <a href="https://en.wikipedia.org/wiki/JavaScript">JavaScript</a> more approachable than <a href="https://clojure.org">Clojure</a> or <a href="https://en.wikipedia.org/wiki/APL_(programming_language)">APL</a>. </p> <p> I believe that this extends to <a href="/2017/10/04/from-design-patterns-to-category-theory">design patterns and universal abstractions</a> as well. If code new to you follows well-known abstractions, it may be easier to learn than if it's structured in an entirely ad-hoc manner. This is my motivation for learning such universal abstractions as <a href="/2017/10/06/monoids">monoids</a>, <a href="/2018/03/22/functors">functors</a>, and <a href="/2019/04/29/catamorphisms">catamorphisms</a>. </p> <p> I particularly enjoy when it's possible to apply such abstractions to a proper problem. This occasionally happens. One example is my small article series on a <a href="/2019/08/26/functional-file-system">functional file system</a>. </p> <h3 id="2aa7c4b2f26840e7bfed2a42064853a7"> A fly in the ointment <a href="#2aa7c4b2f26840e7bfed2a42064853a7" title="permalink">#</a> </h3> <p> In those articles, I described how you could base most of the code on the <a href="/2019/08/05/rose-tree-catamorphism">rose tree catamorphism</a>. There was just one snag. There was one function, <code>calculateMoves</code>, that I was unable to implement with the catamorphism. In the article, I acknowledged my failure: <blockquote> "Earlier, I wrote that you can implement desired <code>Tree</code> functionality with the <code>foldTree</code> function, but that was a simplification. If you can implement the functionality of <code>calculateMoves</code> with <code>foldTree</code>, I don't know how." </blockquote> This was true for both <a href="/2019/09/09/picture-archivist-in-haskell">the Haskell proof of concept</a> as well as <a href="/2019/09/16/picture-archivist-in-f">the F# port</a>. </p> <p> <a href="https://about.me/tysonwilliams">Tyson Williams</a> and I <a href="/2019/09/16/picture-archivist-in-f#68b26807cc424856b8f762f214389826">discussed this wart</a> without getting closer to a solution. </p> <p> As the idiom goes, perfect is the enemy of good, so I decided to move on, although it nagged me. </p> <h3 id="641a9df4d9a24cb7bf687b041f8c305e"> Problem, condensed <a href="#641a9df4d9a24cb7bf687b041f8c305e" title="permalink">#</a> </h3> <p> The problem with the <code>calculateMoves</code> function was that it needed to thread a 'context' recursively through the entire data structure. In this case, the context was a file path. </p> <p> When <code>calculateMoves</code> runs over the input tree, it needs to thread a relative <code>path</code> through the function, building it up as it traverses the data structure. </p> <p> For example, if a leaf node named <code>1</code> is in a directory named <code>b</code>, which itself is a subdirectory of <code>a</code>, the relative path should be <code>a/b/1</code>. This example is straight from the test cases shown in both articles. You can also find the tests in the <a href="https://github.com/ploeh/picture-archivist">GitHub repository</a>. </p> <p> Each time <code>calculateMoves</code> visits a <code>Node</code> or <code>Leaf</code> it needs to know the parent <code>path</code> to calculate the destination path. As the articles show, this isn't too hard to do with regular pattern matching and recursion. </p> <p> I couldn't figure out, however, how to thread the <code>path</code> through the function when I tried to implement it with the catamorphism. </p> <h3 id="2461821e89084c5f8da43b2199d77d33"> Breakthrough <a href="#2461821e89084c5f8da43b2199d77d33" title="permalink">#</a> </h3> <p> While I'm ready to walk away from problems when I'm stuck, I tend to remember them. Sometimes, I run into a solution much later. </p> <p> This happened to me yesterday. I was trying to answer <a href="https://stackoverflow.com/q/67037663/126014">a Stack Overflow question</a> which was explicitly about the application of universal abstractions. Once more, I was stuck by being unable to thread a 'context' through a catamorphism. This time, instead of a <code>path</code>, the context was an indentation depth. Basically, the question was how to render a tree with proper indentation. </p> <p> Again, this isn't hard if you resort to explicit pattern matching and recursion, but I couldn't figure out how to do it via the data structure's catamorphism. </p> <p> Fortunately, <a href="https://stackoverflow.com/users/1364288/danidiaz">the user danidiaz</a> posted <a href="https://stackoverflow.com/a/67042881/126014">an awesome answer</a> while I was struggling. The answer uses a trick that I hadn't noticed before: It threads the indentation depth through the data structure by using the catamorphism to produce a structure map with <em>a function</em> as the carrier type. Specifically, danidiaz defines the algebra <code>Todo' (Int -&gt; String) -&gt; Int -&gt; String</code> to reduce a <code>Todo' (Int -&gt; String)</code> to an <code>Int -&gt; String</code> function. This function then gets initialised with the depth <code>0</code>. </p> <p> While I've been doing functional programming for years, I sometimes still tend to forget that functions are first-class values... </p> <p> This trick, though, seems to be universally applicable. If you need to thread a context through a catamorphism, define the algebra to work on <em>functions</em> that take the context as an argument. </p> <p> If this is a universally applicable trick, it also ought to work with the <code>calculateMoves</code> function. </p> <h3 id="f3e4908437ea4ab7bf0dd01d82ec470e"> Haskell re-implementation <a href="#f3e4908437ea4ab7bf0dd01d82ec470e" title="permalink">#</a> </h3> <p> In my <a href="https://www.haskell.org">Haskell</a> proof of concept, the <code>calculateMoves</code> function originally looked like this: </p> <p> <pre><span style="color:#2b91af;">calculateMoves</span>&nbsp;::&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">Move</span> calculateMoves&nbsp;=&nbsp;imp&nbsp;<span style="color:#a31515;">&quot;&quot;</span> &nbsp;&nbsp;<span style="color:blue;">where</span>&nbsp;imp&nbsp;path&nbsp;&nbsp;&nbsp;&nbsp;(Leaf&nbsp;x)&nbsp;=&nbsp;Leaf&nbsp;$&nbsp;Move&nbsp;x&nbsp;$&nbsp;replaceDirectory&nbsp;x&nbsp;path &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imp&nbsp;path&nbsp;(Node&nbsp;x&nbsp;xs)&nbsp;=&nbsp;Node&nbsp;(path&nbsp;&lt;/&gt;&nbsp;x)&nbsp;$&nbsp;imp&nbsp;(path&nbsp;&lt;/&gt;&nbsp;x)&nbsp;&lt;$&gt;&nbsp;xs</pre> </p> <p> It uses an <code>imp</code> (for <em>implementation</em>) function to explicitly <a href="/2015/12/01/recurse">recurse</a> over a <code>Tree FilePath FilePath</code>. Until yesterday, I couldn't come up with a better solution to thread the <code>path</code> through the data structure. </p> <p> The new trick suggests that it'd be possible to implement the function on <code>foldTree</code> (the catamorphism) by using <em>a function</em> as the carrier type. Since the context to be threaded through the catamorphism is a <code>String</code> (the <code>path</code>), the catamorphism should produce a function that takes a <code>String</code> as argument. In other words, the carrier type of the <code>Tree</code> should be <code>String -&gt; Tree FilePath Move</code>. </p> <p> Let's expand on this: The type of <code>foldTree</code> is <code>foldTree :: (a -&gt; [c] -&gt; c) -&gt; (b -&gt; c) -&gt; Tree a b -&gt; c</code>. Usually, I tend to think of the type parameter <code>c</code> as the type of some value, but since it's unconstrained, it can also be <em>a function</em>. That's what we need here: <code>c</code> should be <code>String -&gt; Tree FilePath Move</code>. </p> <p> That's not too hard to do, because of currying. Just write functions that take an extra <code>String</code> argument and pass them to <code>foldTree</code>: </p> <p> <pre><span style="color:#2b91af;">calculateMoves</span>&nbsp;::&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">Move</span> calculateMoves&nbsp;t&nbsp;=&nbsp;foldTree&nbsp;fNode&nbsp;fLeaf&nbsp;t&nbsp;<span style="color:#a31515;">&quot;&quot;</span> &nbsp;&nbsp;<span style="color:blue;">where</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">fLeaf</span>&nbsp;::&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#2b91af;">String</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">Move</span> &nbsp;&nbsp;&nbsp;&nbsp;fLeaf&nbsp;x&nbsp;&nbsp;&nbsp;&nbsp;path&nbsp;=&nbsp;Leaf&nbsp;$&nbsp;Move&nbsp;x&nbsp;$&nbsp;replaceDirectory&nbsp;x&nbsp;path &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">fNode</span>&nbsp;::&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;[<span style="color:#2b91af;">String</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">Move</span>]&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:#2b91af;">String</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">Move</span> &nbsp;&nbsp;&nbsp;&nbsp;fNode&nbsp;x&nbsp;fs&nbsp;path&nbsp;=&nbsp;Node&nbsp;(path&nbsp;&lt;/&gt;&nbsp;x)&nbsp;$&nbsp;($&nbsp;path&nbsp;&lt;/&gt;&nbsp;x)&nbsp;&lt;$&gt;&nbsp;fs</pre> </p> <p> Here I've used type annotations for the local functions, but that's entirely optional: </p> <p> <pre><span style="color:#2b91af;">calculateMoves</span>&nbsp;::&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;<span style="color:blue;">Tree</span>&nbsp;<span style="color:#2b91af;">FilePath</span>&nbsp;<span style="color:blue;">Move</span> calculateMoves&nbsp;t&nbsp;=&nbsp;foldTree&nbsp;fNode&nbsp;fLeaf&nbsp;t&nbsp;<span style="color:#a31515;">&quot;&quot;</span> &nbsp;&nbsp;<span style="color:blue;">where</span> &nbsp;&nbsp;&nbsp;&nbsp;fLeaf&nbsp;x&nbsp;&nbsp;&nbsp;&nbsp;path&nbsp;=&nbsp;Leaf&nbsp;$&nbsp;Move&nbsp;x&nbsp;$&nbsp;replaceDirectory&nbsp;x&nbsp;path &nbsp;&nbsp;&nbsp;&nbsp;fNode&nbsp;x&nbsp;fs&nbsp;path&nbsp;=&nbsp;Node&nbsp;(path&nbsp;&lt;/&gt;&nbsp;x)&nbsp;$&nbsp;($&nbsp;path&nbsp;&lt;/&gt;&nbsp;x)&nbsp;&lt;$&gt;&nbsp;fs</pre> </p> <p> I included the type annotations to make it a little clearer what's going on. Recall that the type of <code>foldTree</code> is <code>foldTree :: (a -&gt; [c] -&gt; c) -&gt; (b -&gt; c) -&gt; Tree a b -&gt; c</code>. First consider the second of the two function arguments, the one I call <code>fLeaf</code> in the above code. It's the simplest of the two, so it makes sense to start with that one. </p> <p> The generic type of <code>fLeaf</code> is <code>b -&gt; c</code>. How does that map to the type of <code>fLeaf</code>, which is <code>FilePath -&gt; String -&gt; Tree FilePath Move</code>? </p> <p> Well, the <code>Tree</code> that the catamorphism runs on is a <code>Tree FilePath FilePath</code>. Mapped to the parametrically polymorphic type of <code>foldTree</code> that's <code>Tree a b</code>. In other words, <code>b</code> maps to <code>FilePath</code>. Thus, in order to fit the type of <code>b -&gt; c</code>, the type corresponding to <code>b</code> in <code>fLeaf</code> must be <code>FilePath</code>. What's left? <code>String -&gt; Tree FilePath Move</code> is what's left. The function takes a <code>FilePath</code> as input and returns a <code>String -&gt; Tree FilePath Move</code>. In other words, <code>c ~ String -&gt; Tree FilePath Move</code>. </p> <p> How does that fit with <code>fNode</code>? </p> <p> Generically, this function must have the type <code>a -&gt; [c] -&gt; c</code>. We've already established that <code>c</code> must be <code>String -&gt; Tree FilePath Move</code>. Since the catamorphism runs on a <code>Tree FilePath FilePath</code>, we also know that <code>a</code> must be <code>FilePath</code>. Thus, plugging in all the types, <code>fNode</code> must have the type <code>FilePath -&gt; [String -&gt; Tree FilePath Move] -&gt; String -&gt; Tree FilePath Move</code>. Note, particularly, that the second argument is a list of functions. That's why I decided to name the parameter <code>fs</code>, for <em>functions</em>. </p> <p> The entire expression <code>foldTree fNode fLeaf t</code>, then, has the type <code>String -&gt; Tree FilePath Move</code>, since <code>c</code> is <code>String -&gt; Tree FilePath Move</code> and the return type of <code>foldTree</code> is <code>c</code>. </p> <p> The final trick is to apply this function to the initial relative path <code>""</code>, which returns a <code>Tree FilePath Move</code>. </p> <p> This compiles and passes all tests. <code>calculateMoves</code> is now implemented using the <code>Tree</code> catamorphism, a goal that eluded me for more than one and a half years. </p> <h3 id="48fe66e3bffa413c8fe15e465581cb4e"> F# re-implementation <a href="#48fe66e3bffa413c8fe15e465581cb4e" title="permalink">#</a> </h3> <p> With the Haskell proof of concept in place, it's fairly trivial to port the new implementation to the <a href="https://fsharp.org">F#</a> code base. </p> <p> The <code>calculateMoves</code> function originally looked like this: </p> <p> <pre><span style="color:green;">//&nbsp;Tree&lt;string,FileInfo&gt;&nbsp;-&gt;&nbsp;Tree&lt;string,Move&gt;</span> <span style="color:blue;">let</span>&nbsp;calculateMoves&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;replaceDirectory&nbsp;(f&nbsp;:&nbsp;FileInfo)&nbsp;d&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInfo&nbsp;(Path.Combine&nbsp;(d,&nbsp;f.Name)) &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;<span style="color:blue;">rec</span>&nbsp;imp&nbsp;path&nbsp;=&nbsp;<span style="color:blue;">function</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;Leaf&nbsp;x&nbsp;<span style="color:blue;">-&gt;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Leaf&nbsp;{&nbsp;Source&nbsp;=&nbsp;x;&nbsp;Destination&nbsp;=&nbsp;replaceDirectory&nbsp;x&nbsp;path&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;Node&nbsp;(x,&nbsp;xs)&nbsp;<span style="color:blue;">-&gt;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;newNPath&nbsp;=&nbsp;Path.Combine&nbsp;(path,&nbsp;x) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Tree.node&nbsp;newNPath&nbsp;(List.map&nbsp;(imp&nbsp;newNPath)&nbsp;xs) &nbsp;&nbsp;&nbsp;&nbsp;imp&nbsp;<span style="color:#a31515;">&quot;&quot;</span></pre> </p> <p> In the F# code base, the catamorphism is called <code>Tree.cata</code>, but otherwise looks like the Haskell <code>foldTree</code> function. The refactoring is also similar: </p> <p> <pre><span style="color:green;">//&nbsp;Tree&lt;string,&nbsp;FileInfo&gt;&nbsp;-&gt;&nbsp;Tree&lt;string,&nbsp;Move&gt;</span> <span style="color:blue;">let</span>&nbsp;calculateMoves&nbsp;t&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;FileInfo&nbsp;-&gt;&nbsp;string&nbsp;-&gt;&nbsp;FileInfo</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;replaceDirectory&nbsp;(f&nbsp;:&nbsp;FileInfo)&nbsp;d&nbsp;=&nbsp;FileInfo&nbsp;(Path.Combine&nbsp;(d,&nbsp;f.Name)) &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;FileInfo&nbsp;-&gt;&nbsp;string&nbsp;-&gt;&nbsp;Tree&lt;&#39;a,&nbsp;Move&gt;</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;fLeaf&nbsp;x&nbsp;path&nbsp;=&nbsp;Leaf&nbsp;{&nbsp;Source&nbsp;=&nbsp;x;&nbsp;Destination&nbsp;=&nbsp;replaceDirectory&nbsp;x&nbsp;path&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;string&nbsp;-&gt;&nbsp;(string&nbsp;-&gt;&nbsp;Tree&lt;string,&nbsp;&#39;a&gt;)&nbsp;list&nbsp;-&gt;&nbsp;string&nbsp;-&gt;&nbsp;Tree&lt;string,&nbsp;&#39;a&gt;</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;fNode&nbsp;x&nbsp;fs&nbsp;path&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;newNPath&nbsp;=&nbsp;Path.Combine&nbsp;(path,&nbsp;x) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Tree.node&nbsp;newNPath&nbsp;(List.map&nbsp;(<span style="color:blue;">fun</span>&nbsp;f&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;f&nbsp;newNPath)&nbsp;fs) &nbsp;&nbsp;&nbsp;&nbsp;Tree.cata&nbsp;fNode&nbsp;fLeaf&nbsp;t&nbsp;<span style="color:#a31515;">&quot;&quot;</span></pre> </p> <p> Again, the expression <code>Tree.cata fNode fLeaf t</code> has the type <code>string -&gt; Tree&lt;string, Move&gt;</code>, so applying it to <code>""</code> produces a <code>Tree&lt;string, Move&gt;</code> return value. </p> <h3 id="21524d98dcbb4593abc18c55efbfd105"> Conclusion <a href="#21524d98dcbb4593abc18c55efbfd105" title="permalink">#</a> </h3> <p> I don't recall where I read the following, but I was under the impression that a data structure's catamorphism was its 'universal API', upon which you could implement any other functionality. I'd love it if it was true, but after my 2019 failure to implement <code>calculateMoves</code> via the <code>Tree</code> catamorphism, I wasn't sure if such a conjecture would hold. </p> <p> I still don't know if that assertion holds universally, but at least one reason to doubt it has now been removed. </p> </div> <div id="comments"> <hr> <h2 id="comments-header"> Comments </h2> <div class="comment" id="1301010b460845db8730e4aa617504a4"> <div class="comment-author"><a href="https://about.me/tysonwilliams">Tyson Williams</a></div> <div class="comment-content"> <p> Excellent work Mark! I too had not forgotten about this, and it nagged me as well. </p> <p> To some extent, I feel like your explanation of how to implement <code>calculateMoves</code> via <code>Tree.cata</code> is top-down. By top-down, I mean it might depend on discovering the key idea of having <code>Tree.cata</code> return a function and then figuring out the correct type for that function. A good thing about such top-down approaches is being immediately aware that a better solution likely exists even if it takes some time and effort to find it. </p> <p> I was curious if a bottom-up approach would work. By bottom-up, I mean applying small refacorings to the code that are motivated by the principles, conventions, or style of functional programming. I do think I found such an approach. Of course it is a bit contradictory of me to only be able to find this approach after I read your presentation of the top-down approach. However, I am thinking of it like a kata. I now know such a bottom-up approach should be possible, and I want to find it. </p> <p> My bottom-up approach is in <a href="https://github.com/TysonMN/picture-archivist/tree/calculateMoves_via_cata_slow_refactor">this branch</a>. Here is a brief summary of how I want myself to think of making those commits in that order. </p> <p> Each case of the discriminated union could be extracted to its own function. This is easy to do in the <code>Leaf</code> case (so do it now), but it is not as easy to do in the <code>Node</code> case because of recursion, so delay that change for a bit. If we did extract both functions though, both functions would include the argument that I called <code>pathToParent</code>. Since it is passed in everywhere, it should be passed in nowhere (by eta reducing). To do that, we need it to be the last parameter to <code>imp</code>. After switching this order, we now deal with the recursion by doing it as soon as possible. Then the remaining code in that case can be extracted, and <code>imp</code> is essentially <code>Tree.cata</code>. </p> <p> In this approach, I never thought about the possibility of <code>Tree.cata</code> returning a function. It just sort of fell out as a consequence of my other changes. </p> </div> <div class="comment-date">2021-04-12 17:49 UTC</div> </div> <div class="comment" id="c90c8190c0f44e60a44fc605b9a84113"> <div class="comment-author"><a href="https://github.com/gonzaw">Gonzalo Waszczuk</a></div> <div class="comment-content"> <p> Very nice! </p> <p> In Haskell there is a library called <a href="https://hackage.haskell.org/package/recursion-schemes-5.2.2.1">recursion-schemes</a> that showcases these types of recursion with catamorphisms, but also with many others recursion schemes. You can check it out and see if it gives you any new ideas. </p> <p> Regarding this use of catamorphism, the library itself I believe shows a very similar example <a href="https://hackage.haskell.org/package/recursion-schemes-5.2.2.1/docs/Data-Functor-Foldable.html">here</a>, using the Reader type (which is isomorphic to the function you used in your example): </p> <pre> >>> :{ let pprint2 :: Tree Int -> String pprint2 = flip runReader 0 . cataA go where go :: TreeF Int (Reader Int String) -> Reader Int String go (NodeF i rss) = do -- rss :: [Reader Int String] -- ss :: [String] ss <- local (+ 2) $ sequence rss indent <- ask let s = replicate indent ' ' ++ "* " ++ show i pure $ intercalate "\n" (s : ss) :} </pre> <pre> >>> putStrLn $ pprint2 myTree * 0 * 1 * 2 * 3 * 31 * 311 * 3111 * 3112 </pre> </div> <div class="comment-date">2021-04-14 02:27 UTC</div> </div> <div class="comment" id="d26feeefed69421499e766dc1737ca31"> <div class="comment-author"><a href="/">Mark Seemann</a></div> <div class="comment-content"> <p> Gonzalo, thank you for reminding me of the <em>recursion-schemes</em> library. It's one of those tomes of knowledge of which I'm aware, but never really have gotten around to look at... </p> </div> <div class="comment-date">2021-04-16 6:29 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/2021/04/12/threading-context-through-a-catamorphism Mazes on Voronoi tessellations https://blog.ploeh.dk/2021/04/05/mazes-on-voronoi-tesselations/ Mon, 05 Apr 2021 09:03:00 UTC <div id="post"> <p> <em>Recursive backtracker maze generation on a Voronoi diagram.</em> </p> <p> Today's blog post <a href="https://observablehq.com/@ploeh/mazes-on-voronoi-tessellations">appears on Observable</a>. It's an interactive environment where you can play with and fork the code. <a href="https://observablehq.com/@ploeh/mazes-on-voronoi-tessellations">Go there to read it</a>. </p> <p> <img src="/content/binary/recursive-backtracker-on-voronoi-tiles.png" alt="Recursive backtracker algorithm running on a Voronoi tessellation."> </p> <p> <a href="https://observablehq.com">Observable</a> is a really neat platform which has managed to do what I thought was nigh-impossible: make me return to <a href="https://en.wikipedia.org/wiki/JavaScript">JavaScript</a>. The site's <a href="https://observablehq.com/about">been around for some years</a>, and I hope it'll be around for even more years. </p> <p> <em>ploeh blog</em>, on the other hand, has been around <a href="/2009/01/28/LivingInInterestingTimes">since 2009</a>, and I intend to keep it around for much longer. Who knows if <em>Observable</em> will outlive the blog. Enjoy the article while it's there. </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/2021/04/05/mazes-on-voronoi-tesselations Table-driven tennis scoring https://blog.ploeh.dk/2021/03/29/table-driven-tennis-scoring/ Mon, 29 Mar 2021 06:15:00 UTC <div id="post"> <p> <em>Probably the most boring implementation of the tennis kata I've ever written.</em> </p> <p> Regular readers of this blog will know that I keep coming back to the <a href="https://codingdojo.org/kata/Tennis">tennis kata</a>. It's an interesting little problem to attack from various angles. </p> <p> The tennis scoring rules essentially describe a finite state machine, and while I was thinking about the state transitions involved, I came across an article by <a href="http://blog.mikemccandless.com">Michael McCandless</a> about <a href="http://blog.mikemccandless.com/2014/08/scoring-tennis-using-finite-state.html">scoring tennis using finite-state automata</a>. </p> <p> This isn't the first time I've thought about simply enumerating all possible states in the state machine, but I decided to spend half an hour on actually doing it. While Michael McCandless shows that an optimisation is possible, his minimised version doesn't enable us to report all intermediary states with the correct labels. For example, he optimises away <em>thirty-all</em> by replacing it with <em>deuce</em>. The end result is still the same, in the sense that the minimised state machine will arrive at the same winner for the same sequence of balls, but it can't correctly report the score while the game is in progress. </p> <p> For that reason, I decided to use his non-optimised state machine as a launch pad. </p> <h3 id="d32da6b59b7448959d6bed2f10f84569"> States <a href="#d32da6b59b7448959d6bed2f10f84569" title="permalink">#</a> </h3> <p> I used <a href="https://fsharp.org">F#</a> to enumerate all twenty states: </p> <p> <pre><span style="color:blue;">type</span>&nbsp;Score&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;LoveAll &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FifteenLove &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;LoveFifteen &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;ThirtyLove &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FifteenAll &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;LoveThirty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FortyLove &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;ThirtyFifteen &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FifteenThirty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;LoveForty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FortyFifteen &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;ThirtyAll &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FifteenForty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;GamePlayerOne &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FortyThirty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;ThirtyForty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;GamePlayerTwo &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;AdvantagePlayerOne &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;Deuce &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;AdvantagePlayerTwo</pre> </p> <p> Utterly boring, yes, but perhaps boring code might be good code. </p> <h3 id="1eb656d32be0461aa11c321ec478a1cf"> Table-driven methods <a href="#1eb656d32be0461aa11c321ec478a1cf" title="permalink">#</a> </h3> <p> <a href="http://amzn.to/1dLYr0r">Code Complete</a> describes a programming technique called <em>table-driven methods</em>. The idea is to replace branching instructions such as <code>if</code>, <code>else</code>, and <code>switch</code> with a lookup table. The book assumes that the table exists in memory, but in this case, we can implement the table lookup with pattern matching: </p> <p> <pre><span style="color:green;">//&nbsp;Score&nbsp;-&gt;&nbsp;Score</span> <span style="color:blue;">let</span>&nbsp;ballOne&nbsp;=&nbsp;<span style="color:blue;">function</span> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;LoveAll&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;FifteenLove &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FifteenLove&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;ThirtyLove &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;LoveFifteen&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;FifteenAll &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;ThirtyLove&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;FortyLove &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FifteenAll&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;ThirtyFifteen &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;LoveThirty&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;FifteenThirty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FortyLove&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;GamePlayerOne &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;ThirtyFifteen&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;FortyFifteen &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FifteenThirty&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;ThirtyAll &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;LoveForty&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;FifteenForty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FortyFifteen&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;GamePlayerOne &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;ThirtyAll&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;FortyThirty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FifteenForty&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;ThirtyForty &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;GamePlayerOne&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;GamePlayerOne &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;FortyThirty&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;GamePlayerOne &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;ThirtyForty&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;Deuce &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;GamePlayerTwo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;GamePlayerTwo &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;AdvantagePlayerOne&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;GamePlayerOne &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;Deuce&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;AdvantagePlayerOne &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;AdvantagePlayerTwo&nbsp;<span style="color:blue;">-&gt;</span>&nbsp;Deuce</pre> </p> <p> The <code>ballOne</code> function returns the new score when player one wins a ball. It takes the old score as input. </p> <p> I'm going to leave <code>ballTwo</code> as an exercise to the reader. </p> <h3 id="47bf74d3fafd478fafa354563459f0ad"> Smoke test <a href="#47bf74d3fafd478fafa354563459f0ad" title="permalink">#</a> </h3> <p> Does it work, then? Here's a few interactions with the API in <em>F# Interactive:</em> </p> <p> <pre>&gt; ballOne LoveAll;; val it : Score = FifteenLove &gt; LoveAll |&gt; ballOne |&gt; ballTwo;; val it : Score = FifteenAll &gt; LoveAll |&gt; ballOne |&gt; ballTwo |&gt; ballTwo;; val it : Score = FifteenThirty &gt; LoveAll |&gt; ballOne |&gt; ballTwo |&gt; ballTwo |&gt; ballTwo;; val it : Score = FifteenForty &gt; LoveAll |&gt; ballOne |&gt; ballTwo |&gt; ballTwo |&gt; ballTwo |&gt; ballOne;; val it : Score = ThirtyForty &gt; LoveAll |&gt; ballOne |&gt; ballTwo |&gt; ballTwo |&gt; ballTwo |&gt; ballOne |&gt; ballTwo;; val it : Score = GamePlayerTwo</pre> </p> <p> It looks like it's working. </p> <h3 id="17290385a4a042189ef0b5b04cf200c6"> Automated tests <a href="#17290385a4a042189ef0b5b04cf200c6" title="permalink">#</a> </h3> <p> Should I be writing unit tests for this implementation? </p> <p> I don't see how a test would be anything but a duplication of the two 'transition tables'. <em>Given that the score is thirty-love, when player one wins the ball, then the new score should be forty-love</em>. Indeed, the <code>ballOne</code> function already states that. </p> <p> We <a href="/2013/04/02/why-trust-tests">trust tests because they are simple</a>. When the implementation is as simple as the test that would exercise it, then what's the benefit of the test? </p> <p> To be clear, there are still compelling reasons to write tests for some simple implementations, but that's another discussion. I don't think those reasons apply here. I'll write no tests. </p> <h3 id="fb03ecc39926472790ba2c5eaa025a91"> Code size <a href="#fb03ecc39926472790ba2c5eaa025a91" title="permalink">#</a> </h3> <p> While this code is utterly dull, it takes up some space. In all, it runs to 67 lines of code. </p> <p> For comparison, the code base that evolves throughout my <a href="/2016/02/10/types-properties-software">Types + Properties = Software</a> article series is 65 lines of code, not counting the tests. When I also count the tests, that entire code base contains around 300 lines of code. That's more than four times as much code. </p> <p> Preliminary <a href="https://amzn.to/2OBNBoY">research implies that bug count correlates linearly with line count</a>. The more lines of code, the more bugs. </p> <p> While I believe that this is probably a simplistic rule of thumb, there's much to like about smaller code bases. In total, this utterly dull implementation is actually smaller than a comparable implementation built from small functions. </p> <h3 id="5ac7b217f375464aa21320c8f0bfe0a7"> Conclusion <a href="#5ac7b217f375464aa21320c8f0bfe0a7" title="permalink">#</a> </h3> <p> Many software problems can be modelled as finite state machines. I find that this is often the case in my own field of line-of-business software and web services. </p> <p> It's not always possible to exhaustively enumerate all states, because each 'type' of state carries data that can't practically be enumerated. For example, <a href="/2017/06/27/pure-times">polling consumers</a> need to carry timing statistics. These statistics influence how the state machine transitions, but the range of possible values is so vast that it can't be enumerated as types. </p> <p> It may not happen often that you can fully enumerate all states and transitions of a finite state machine, but I think it's worthwhile to be aware of such refactoring opportunities. It might make your code dully simple. </p> </div> <div id="comments"> <hr> <h2 id="comments-header"> Comments </h2> <div class="comment" id="57354557ce724eefb675d8788c5bea94"> <div class="comment-author"><a href="https://taeguk.co.uk">Dave Shaw</a></div> <div class="comment-content"> <p>Hi Mark, I have had a similar experience whilst coding a <a href="https://en.wikipedia.org/wiki/Shut_the_box"> Shut the box</a> game, when trying to detect if it was game over or not. <br/> Originally it was a complex set of loops to calculate all the discrete summands for each roll of the dice, then checking if the remaining flaps were in that set. This was done along with a suite of tests for every possible combination set of summands up to 12 (for 2 dice). <br /> Then whilst explaining the pain in writing this to a friend, they simply said, <i>there's only a finite list, why not hard code them?</i>, and that's what I went with, a dictionary with each possible roll from 2 dice, and the possible values from the flaps that could be used to meet that roll. All the tests were removed; as you pointed out, they would just be a reimplmentation of the table. </p> </div> <div class="comment-date">2021-04-07 13:30 UTC</div> </div> <div class="comment" id="858ccadaae1b41268d3bf4454ab9fcb0"> <div class="comment-author"><a href="/">Mark Seemann</a></div> <div class="comment-content"> <p> Dave, thank you for writing. It's good to hear that you have a similar experience. I wonder if it's constrained to game simulation, or if 'real-world' examples exist. </p> </div> <div class="comment-date">2021-04-09 6:30 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/2021/03/29/table-driven-tennis-scoring The dispassionate developer https://blog.ploeh.dk/2021/03/22/the-dispassionate-developer/ Mon, 22 Mar 2021 06:50:00 UTC <div id="post"> <p> <em>Caring for your craft is fine, but should you work for free?</em> </p> <p> I've met many passionate developers in my career. Programmers who are deeply interested in technology, programming languages, methodology, and self-improvement. I've also seen many online profiles where people present themselves as 'passionate developers'. </p> <p> These are the people who organise and speak at user groups. They write blog posts and host podcasts. They contribute to open source development in their free time. </p> <p> I suppose that I can check many of those boxes myself. In the last few years, though, I've become increasingly sceptic that this is a good idea. </p> <h3 id="8894ee52bd514210a5f8193f38634f43"> Working for free <a href="#8894ee52bd514210a5f8193f38634f43" title="permalink">#</a> </h3> <p> In the last five years or so, I've noticed what looks like a new trend. Programmers contact me to ask about paid mentorship. They offer to pay me <em>out of their own pocket</em> to mentor them. </p> <p> I find that flattering, but it also makes me increasingly disenchanted with the software development industry. To be clear, this isn't an attack on the good people who care so much about their craft that they are willing to spend their hard-earned cash on improving their skill. This is more a reflection on employers. </p> <p> For reasons that are complicated and that I don't fully understand, the software development community in the eighties and nineties developed a culture of anti-capitalism and liberal values that put technology on a pedestal for its own sake. Open source good; commercial software bad. Free software good; commercial software bad. </p> <p> I'm not entirely unsympathetic to such ideas, but it's seems clear, now, that these ideas have had unintended consequences. The idea of free software, for example, has led to a software economy where you, the user, are no longer the customer, but the product. </p> <p> The idea of open source, too, seems largely defunct as a means of 'sticking it to the man'. The big tech companies now embrace open source. Despite initial enmity towards open source, <a href="https://en.wikipedia.org/wiki/Microsoft_and_open_source">Microsoft now owns GitHub and is one of the most active contributors</a>. Google and Facebook control popular front-end platforms such as <a href="https://en.wikipedia.org/wiki/Angular_(web_framework)">Angular</a> and <a href="https://en.wikipedia.org/wiki/React_(JavaScript_library)">React</a>, as well as many other technologies such as <a href="https://en.wikipedia.org/wiki/Android_(operating_system)">Android</a> or <a href="https://en.wikipedia.org/wiki/GraphQL">GraphQL</a>. Continue the list at your own leisure. </p> <p> Developing open source is seen as a way to establish credibility, not only for companies, but for individuals as well. Would you like a cool job in tech? Show me your open-source portfolio. </p> <p> Granted, the focus on open-source contributions as a replacement for a CV seems to have peaked, and good riddance. </p> <p> I deliberately chose to use the word <em>portfolio</em>, above. Like a struggling artist, you're expected to show up with such a stunning sample of your work that you amaze your potential new employer and blow away your competition. Unlike struggling artists, though, you've already given away everything in your portfolio, and so have other job applicants. Employers benefit from this. You work for free. </p> <h3 id="2d37b0297422447c9c92e2f18828f5a7"> The passion ethos <a href="#2d37b0297422447c9c92e2f18828f5a7" title="permalink">#</a> </h3> <p> You're expected to 'contribute' to open source software. Why? Because employers want employees who are <em>passionate</em> about their craft. </p> <p> As you start to ponder the implied ethos, the stranger it gets. Would you like engineers to be <em>passionate</em> as they design new bridges? Would you like a surgeon to be <em>passionate</em> as she operates on you? Would you like judges to be <em>passionate</em> as they pass sentence on your friend? </p> <p> I'd like such people to <em>care</em> about their vocation, but I'd prefer that they keep a cool head and make as rational decisions as possible. </p> <p> Why should programmers be <em>passionate?</em> </p> <p> I don't think that it's in our interest to be passionate, but it <em>is</em> in employers' interest. Not only are passionate people expected to work for free, they're also easier to manipulate. Tell a passionate person something he wants to hear, and he may turn off further critical thinking because the praise <em>feels</em> good. </p> <p> Some open-source maintainers have created crucial software that runs everywhere. Companies make millions off that free software, while maintainers are often left with an increasing support burden and no money. </p> <p> They do, however, often get a pat on the back. They get invited to speak at conferences, and can add <em>creator of Xyz</em> to their social media bios. </p> <p> Until they burn out, that is. <ins datetime="2021-03-22T11:49Z"><em>Passion</em>, after all, comes from the Latin for <em>suffering</em></ins>. </p> <h3 id="192b9f90f1e94fcf97649edc5c234f39"> Self-improvement <a href="#192b9f90f1e94fcf97649edc5c234f39" title="permalink">#</a> </h3> <p> I remember consulting with a development organisation, helping them adopt some new technology. As my engagement was winding down, I had a meeting with the manager to discuss how they should be able to carry on without me. This was back in my Microsoft days, so I suggested that they institute a training programme for the employees. To give it structure, they could, for example, study for some Microsoft certifications. </p> <p> The development manager immediately shot down that idea: <em>"If we do that, they'll leave us once they have the certification."</em> </p> <p> I was flabbergasted. </p> <p> You've probably seen quotes like this: <blockquote> <p> "What happens if we train our people and they leave?" </p> <p> "What happens if we don't and they stay?" </p> </blockquote> This is one of those bon mots that seem impossible to attribute to a particular source, but the idea is clear enough. The sentiment doesn't seem to represent mainstream behaviour, though. </p> <p> Granted, I've met more than one visionary leader willing to invest in employees' careers, but most managers don't. </p> <p> While I teach and coach internationally, I naturally have more experience with my home region of Copenhagen, and more broadly Scandinavia. Here, it's a common position that anything that relates to work should only happen during work hours. If the employer doesn't allow training on the job, then most employees don't train. </p> <p> What happens if you don't keep up to date with new methodologies, new frameworks, new programming languages? Your skill set becomes obsolete. Not overnight, but over the years. Finding a new job becomes harder and harder. </p> <p> As your marketability atrophies, your employer can treat you worse and worse. After all, where are you going to go? </p> <p> If you're tired of working with legacy code without tests, most of your suggestions for improvements will be met by a shrug. <em>We don't have time for that now. It's more important to deliver value to the customer.</em> </p> <p> You'll have to work long hours and weekends fire-fighting 'unexpected' issues in production while still meeting deadlines. </p> <p> A sufficiently cynical employer may have no qualms keeping employees busy this way. </p> <p> To be clear, I'm not saying that it's good business sense to treat skilled employees like this, and I'm not saying that this is how <em>all</em> employers conduct business, but I've seen enough development organisations that fit the description. </p> <p> As disappointing as it may be, keeping up to date with technology is <em>your</em> responsibility, and if you can't sneak in some time for self-improvement at work, you'll have to do it on your own time. </p> <p> This has little to do with passion, but much to do with self-preservation. </p> <h3 id="a40b07d82eef4ee0a657df53662b4418"> Can I help you? <a href="#a40b07d82eef4ee0a657df53662b4418" title="permalink">#</a> </h3> <p> The programmers who contact me (and others) for mentorship are the enlightened ones who've already figured this out. </p> <p> That doesn't mean that I'm comfortable taking people's hard-earned money. If I teach you something that improves your productivity, your employer benefits, too. I think that your employer should pay for that. </p> <p> I'm aware that most companies don't want to do that. It's also my experience that while most employers couldn't care less whether you pay me for mentorship, they don't want you to show me their code. This basically means that I can't really mentor you, unless you can reproduce the problems you're having as anonymised code examples. </p> <p> But if you can do that, you can ask the whole internet. You can try asking on <a href="https://stackoverflow.com">Stack Overflow</a> and then ping me. You're also welcome to ask me. If your <a href="https://en.wikipedia.org/wiki/Minimal_working_example">minimal working example</a> is interesting, I may turn it into a blog post, and you pay nothing. </p> <p> People also ask me how they can convince their managers or colleagues to do things differently. I often wonder why they don't <a href="/2019/03/18/the-programmer-as-decision-maker">make technical decisions</a> already, but this may be my cultural bias talking. In Denmark you can often get away with the ask-for-forgiveness-rather-than-permission attitude, but it may not be a good idea in your culture. </p> <p> Can I magically convince your manager to do things differently? Not magically, but I do know an effective trick: get him or her to hire me (or another expensive consultant). Most people don't heed advice given for free, but if they pay dearly for it, they tend to pay attention. </p> <p> Other than that, I can only help you as I've passionately tried to help the world-wide community for decades: by blogging, answering questions on Stack Overflow, writing books, <a href="/schedule">speaking at user groups and conferences</a>, <a href="/about#video">publishing videos</a>, and so on. </p> <h3 id="2eb915d9d2aa411884599d592a310be0"> Ticking most of the boxes <a href="#2eb915d9d2aa411884599d592a310be0" title="permalink">#</a> </h3> <p> Yes, I know that I fit the mould of the <em>passionate developer</em>. I've blogged regularly since 2006, I've <a href="https://stackoverflow.com/users/126014/mark-seemann?tab=answers">answered thousands of questions on Stack Overflow</a>, I've given more than a hundred presentations, been a podcast guest, and co-written <a href="/dippp">a book</a>, none of which has made me rich. If I don't do it for the passion, then why do I do it? </p> <p> Sometimes it's hard and tedious work, but even so, I do much of it because I can't really help it. I <em>like</em> to write and teach. I suppose that makes me passionate. </p> <p> My point with this article isn't that there's anything wrong with being passionate about software development. The point is that you might want to regard it as a <em>weakness</em> rather than an asset. If you <em>are</em> passionate, beware that someone doesn't take advantage of you. </p> <p> I realise that I didn't view the world like this when I started blogging in January 2006. I was driven by my passion. In retrospect, though, I think that I have been both privileged and fortunate. I'm not sure my career path is reproducible today. </p> <p> When I started blogging, it was a new-fangled thing. Just the fact that you blogged was enough to you get a little attention. I was in the right place at the right time. </p> <p> The same is true for Stack Overflow. The site was still fairly new when I started, and a lot of frequently asked questions were only asked on my watch. I still get upvotes on answers from 2009, because these are questions that people still ask. I was just lucky enough to be around <em>the first time</em> it was asked on the site. </p> <p> I'm also privileged by being an able-bodied man born into the middle class in one the world's richest countries. I received a free education. Denmark has free health care and generous social security. Taking some chances with your career in such an environment isn't even reckless. I've worked for more than one startup. That's not risky here. Twice, I've worked for a company that went out of business; in none of those cases did I lose money. </p> <p> Yes, I've been fortunate, but my point is that you should probably not use my career as a model for yours, just as you shouldn't use those of <a href="https://en.wikipedia.org/wiki/Robert_C._Martin">Robert C. Martin</a>, <a href="https://en.wikipedia.org/wiki/Kent_Beck">Kent Beck</a>, or <a href="https://en.wikipedia.org/wiki/Martin_Fowler_(software_engineer)">Martin Fowler</a>. It's hardly a reproducible career path. </p> <h3 id="47dbcc3e81fc408881d0a173f5226f53"> Conclusion <a href="#47dbcc3e81fc408881d0a173f5226f53" title="permalink">#</a> </h3> <p> What <em>can</em> you do, then, if you want to stand out from the crowd? How <em>do</em> you advance your software development career? </p> <p> I don't know. I never claimed that this was easy. </p> <p> Being good at something helps, but you must also make sure that the right people know what you're good at. You're probably still going to have to invest some of your 'free' time to make that happen. </p> <p> Just beware that you aren't being taken advantage of. Be dispassionate. </p> </div> <div id="comments"> <hr> <h2 id="comments-header"> Comments </h2> <div class="comment" id="c86dd3a1f4814201a7d15ba3b95c67c0"> <div class="comment-author"><a href="https://github.com/Jankowski-J">Jakub Jankowski</a></div> <div class="comment-content"> <p> Thanks Mark for your post. </p> <p> I really relate to your comment about portfolio. I am still a young developer, not even 30 years old. A few years ago, I had an unhealthy obsession, that I should have a portfolio, otherwise I would be having a hard time finding job. </p> <p> I am not entirely sure where this thought was coming from, but it is not important in what I want to convey. I was worrying that I do not have a portfolio and that anxiety itself, prevented me from doing any real work to have anything to showcase. Kinda vicious cycle. </p> <p> Anyways, even without a portfolio, I didn't have any troubles switching jobs. I focused on presenting what I have learned in every project I worked on. What was good about it, what were the struggles. I presented myself not as a just a "mercenary" if you will. I always gave my best at jobs and at the interviews and somehow managed to prove to myself that a portfolio is not a <em>must</em>. </p> <p> Granted, everybody's experience is different and we all work in different market conditions. But my takeaway is - don't fixate on a thing, if it's not an issue. That's kinda what I was doing a few years back. </p> </div> <div class="comment-date">2021-03-28 16:25 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/2021/03/22/the-dispassionate-developer Pendulum swing: pure by default https://blog.ploeh.dk/2021/03/15/pendulum-swing-pure-by-default/ Mon, 15 Mar 2021 06:47:00 UTC <div id="post"> <p> <em>Favour pure functions over polymorphic dependencies.</em> </p> <p> This is an article in <a href="/2021/02/22/pendulum-swings">a small series of articles about personal pendulum swings</a>. Here, I'll discuss another contemporary one-eighty. This one is older than the other two I've discussed in this article series, but I believe that it deserves to be included. </p> <p> Once upon I time, I used to consider Dependency Injection (DI) and injected interfaces an unequivocal good: the more, the merrier. These days, I tend to only model true application dependencies as injected dependencies. For the rest, I use <a href="https://en.wikipedia.org/wiki/Pure_function">pure functions</a>. </p> <h3 id="52438454eb1747cb81e897e1a44dfa1b"> Background <a href="#52438454eb1747cb81e897e1a44dfa1b" title="permalink">#</a> </h3> <p> When I started my programming career, I'd barely taught myself to program. I worked in both Visual Basic, VBScript, and C++ before I encountered the concept of an interface. What C++ I wrote was entirely procedural, and I don't recall being aware of inheritance. Visual Basic 6 didn't have inheritance, and I'm fairly sure that VBScript didn't, either. </p> <p> I vaguely recall first being introduced to the concept of an interface in Visual Basic. It took me some time to wrap my head around it, and while I thought it seemed clever, I couldn't find any practical use for it. </p> <p> I think that I wrote my first professional C# code base in 2002. We didn't use Dependency Injection or interfaces. I don't even recall that we used much inheritance. </p> <h3 id="cae8dc76412149dbbe4eb4854888f652"> Inject all the things <a href="#cae8dc76412149dbbe4eb4854888f652" title="permalink">#</a> </h3> <p> When I discovered test-driven development (TDD) the year after, it didn't take me too long to figure out that I'd need to isolate units from their dependencies. Based on initial successes, I even wrote <a href="https://docs.microsoft.com/archive/msdn-magazine/2004/october/unit-testing-mock-objects-to-the-rescue-test-your-net-code-with-nmock">an article about mock objects</a> for MSDN Magazine October 2004. </p> <p> At that time I'd made interfaces a part of my active technique. I still struggled with how to replace a unit's 'real' dependencies with the mock objects. Initially, I used what I in <a href="https://amzn.to/36xLycs">Dependency Injection in .NET</a> later called <em>Bastard Injection</em>. As I also described in the book, things took a dark turn for while as I discovered the <a href="/2010/02/03/ServiceLocatorisanAnti-Pattern">Service Locator anti-pattern</a> - only, at that time, I didn't realise that it was an anti-pattern. Soon after, fortunately, I discovered <a href="/2014/06/10/pure-di">Pure DI</a>. </p> <p> That problem solved, I began an era of my programming career where everything became an interface. It does enable unit testing, so it's better than not being able to test, but after some years I began to sense the limits. </p> <p> Perhaps the worst problem is that you get a deluge of interfaces. Many of these interfaces have similar-sounding names like <code>IReservationsManager</code> and <code>IRestaurantManager</code>. This makes discoverability harder: Which of these interfaces should you use? One defines <a href="/2020/11/23/good-names-are-skin-deep">a <code>TrySave</code> method, the other a <code>Check</code> method</a>, and they aren't that different. </p> <p> This wasn't clear to me when I worked in teams with one or two programmers. Once I saw how this played out in larger teams, however, I began to understand that one developer's interface remained undiscovered by other team members. When existing 'abstractions' are unclear, it leads to frequent reinvention of interfaces to implement the same functionality. Duplication abounds. </p> <p> Designing with many fine-grained dependencies also has a tendency drag into existence many <em>factory interfaces</em>, a <a href="https://blogs.cuttingedge.it/steven/posts/2016/abstract-factories-are-a-code-smell">well-known design smell</a>. </p> <h3 id="b29309513d1946238cb08718f6be8903"> Have a sandwich <a href="#b29309513d1946238cb08718f6be8903" title="permalink">#</a> </h3> <p> It's remarkable how effectively you can lie to yourself. As late as 2017 <a href="https://softwareengineering.stackexchange.com/a/356822/19115">I still concluded that fine-grained dependencies were best</a>, despite most of my arguments pointing in another direction. </p> <p> I first encountered functional programming in 2010, but was off to a slow start. It took me years before I realised that <a href="/2017/01/27/from-dependency-injection-to-dependency-rejection">Dependency Injection isn't functional</a>. There are other ways to address the problem of separating pure functions from impure actions, the simplest of which is the <a href="/2020/03/02/impureim-sandwich">impureim sandwich</a>. </p> <p> Which parts of the application architecture are inherently impure? The usual suspects: the system clock, random number generators, the file system, databases, network resources. Notice how these are the dependencies that you usually need to replace with <a href="http://xunitpatterns.com/Test%20Double.html">Test Doubles</a> in order to make unit tests deterministic. </p> <p> It makes sense to model these as dependencies. I still define interfaces for those and use Dependency Injection to control them. I do, however, use the impureim sandwich architecture to deal with the impure actions first, so that I can then delegate all the complex decision logic to pure functions. </p> <p> <a href="/2015/05/07/functional-design-is-intrinsically-testable">Pure functions are intrinsically testable</a>, so that solves many of the problems with testability. There's still a need to test how the impure actions interact with the pure functions. Here I take a step up in the <a href="https://martinfowler.com/bliki/TestPyramid.html">Test Pyramid</a> and write just enough <a href="/2019/02/18/from-interaction-based-to-state-based-testing">state-based integration tests</a> to render it probable that the integration works as intended. You can see an example of such a test <a href="/2021/01/18/parametrised-test-primitive-obsession-code-smell">here</a>. </p> <h3 id="bb9264be0f1648b48f6572e1054fab95"> Conclusion <a href="#bb9264be0f1648b48f6572e1054fab95" title="permalink">#</a> </h3> <p> From having favoured fine-grained Dependency Injection, I now write all decision logic as pure functions by default. These only need to implement interfaces if you need the <em>logic</em> of the system to be interchangeable, which isn't that often. I do still use Dependency Injection for the impure dependencies of the system. There's usually only a handful of those. </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/2021/03/15/pendulum-swing-pure-by-default Pendulum swing: sealed by default https://blog.ploeh.dk/2021/03/08/pendulum-swing-sealed-by-default/ Mon, 08 Mar 2021 07:28:00 UTC <div id="post"> <p> <em>Inheritance is evil. Seal your classes.</em> </p> <p> This is an article in <a href="/2021/02/22/pendulum-swings">a small series of articles about personal pendulum swings</a>. Here, I document another recent change of heart that's been a long way coming. In short, I now <code>seal</code> C# classes whenever I remember to do it. </p> <h3 id="1f7f814e8f314fd291ad5fd73b12c7bf"> Background <a href="#1f7f814e8f314fd291ad5fd73b12c7bf" title="permalink">#</a> </h3> <p> After I discovered test-driven development (TDD) (circa 2003) I embarked on a quest for proper ways to enable testability. <a href="https://martinfowler.com/articles/nonDeterminism.html">Automated tests should be deterministic</a>, but real software systems rarely are. Software depends on the system clock, random number generators, the file system, the states of databases, web services, and so on. All of these may change independently of the software, making it difficult to express an automated systems test in a deterministic manner. </p> <p> This is a known problem in TDD. In order to get the system under test (SUT) under control, you have to <a href="http://bit.ly/working-effectively-with-legacy-code">introduce what Michael Feathers calls <em>seams</em></a>. In C#, there's traditionally been two ways you could do that: <a href="/2016/06/15/sut-double">extract and override</a>, and interfaces. </p> <p> The original <a href="http://amzn.to/16E4q3z">Framework Design Guidelines</a> explicitly recommended base classes over interfaces, and I wasn't wise to how unfortunate that recommendation was. For a long time, I'd define abstractions with (abstract) base classes. I was even envious of Java, where instance members are virtual (overridable) by default. In C# you must explicitly declare a method <code>virtual</code> to make it overridable. </p> <p> Abstract base classes aren't too bad if you leave them completely empty, but I never had much success with non-abstract base classes and virtual members and the whole extract-and-override manoeuvre. I soon concluded that <a href="/2016/06/15/sut-double">Dependency Injection with interfaces</a> was a better alternative. </p> <p> Even after I changed to exclusively relying on interfaces (instead of abstract base classes), remnants of the rule stuck with me for years: <em>unsealed good; sealed bad</em>. Even today, the framework design guidelines favour unsealed classes: <blockquote> <p> "CONSIDER using unsealed classes with no added virtual or protected members as a great way to provide inexpensive yet much appreciated extensibility to a framework." </p> <footer><cite><a href="https://docs.microsoft.com/dotnet/standard/design-guidelines/unsealed-classes">Framework Design Guidelines</a></cite></footer> </blockquote> I can no longer agree with this guidance; I think it's poor advice. </p> <h3 id="ae5513333afc437fb4ac795c2af8a4a1"> You don't need inheritance <a href="#ae5513333afc437fb4ac795c2af8a4a1" title="permalink">#</a> </h3> <p> Base classes imply class inheritance as a reuse and extensibility mechanism. We've known since 1994, though, that inheritance probably isn't the best design principle. <blockquote> <p> "Favor object composition over class inheritance." </p> <footer><cite><a href="http://amzn.to/XBYukB">Design Patterns</a></cite></footer> </blockquote> In single-inheritance languages like C# and Java, inheritance is just evil. Once you decide to inherit from a base class, you exclude all other base classes. <em>Inheritance signifies a single 'yes' and an infinity of 'noes'.</em> This is particularly problematic if you rely on inheritance for reuse. You can only 'reuse' a single base class, which again leads to duplication or bloated base classes. </p> <p> It's been years (probably more than a decade) since I stopped relying on base classes for anything. You don't need inheritance. <a href="https://www.haskell.org">Haskell</a> doesn't have it at all, and I only use it in C# when a framework forces me to derive from some base class. </p> <p> There's little you can do with an abstract class that you can't do in some other way. <a href="/2018/02/19/abstract-class-isomorphism">Abstract classes are isomorphic with Dependency Injection up to accessibility.</a> </p> <h3 id="516f72a613aa4884a86448da1c256ebb"> Seal <a href="#516f72a613aa4884a86448da1c256ebb" title="permalink">#</a> </h3> <p> If I already follow a design principle of not relying on inheritance, then why keep classes unsealed? <a href="https://www.python.org/dev/peps/pep-0020">Explicit is better than implicit</a>, so why not make that principle visible? Seal classes. </p> <p> It doesn't have any immediate impact on the code, but it might make it clearer to other programmers that an explicit decision was made. </p> <p> You already saw examples in the <a href="/2021/03/01/pendulum-swing-internal-by-default">previous article</a>: Both <code>Month</code> and <code>Seating</code> are sealed classes. They're also immutable records. I seal more than record types, too: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:blue;">sealed</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">HomeController</span></pre> </p> <p> I seal Controllers, as well as services: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:blue;">sealed</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">SmtpPostOffice</span>&nbsp;:&nbsp;<span style="color:#2b91af;">IPostOffice</span></pre> </p> <p> Another example is <a href="/2020/11/09/checking-signed-urls-with-aspnet">an ASP.NET filter</a> named <code>UrlIntegrityFilter</code>. </p> <p> A common counter-argument is that 'you may need extensibility in the future': <blockquote> <p> "by using "sealed" and not virtual in libs dev says "I thought of all extension point" which seems arrogant" </p> <footer><cite><a href="https://twitter.com/dun3/status/586790512528596992">Tobias Hertkorn</a></cite></footer> </blockquote> I agree that it'd be arrogant to claim that you've thought about all extension points. Trying to predict future need is futile. </p> <p> I don't agree, however, that making everything virtual is a good idea, but it's because I disagree with the underlying premise. The presupposition is that extensibility should be enabled through inheritance. If it's not already clear, I believe that this has many undesirable consequences. There are better ways to enable extensibility than through inheritance. </p> <h3 id="3ab4e94848d742aa8e3b12377415e8d1"> Conclusion <a href="#3ab4e94848d742aa8e3b12377415e8d1" title="permalink">#</a> </h3> <p> I've begun to routinely seal new classes. I don't always remember to do it, but I think that I ought to. As I also explained in the previous article, this is only my default. If something has to be a base class, that's still an option. Likewise, just because a class starts out <code>sealed</code> doesn't mean that it has to stay <code>sealed</code> forever. While sealing an unsealed class is a breaking change, unsealing a sealed class isn't. </p> <p> I can't think of any reason why I'd do that, though. </p> <p> <strong>Next: </strong> <a href="/2021/03/15/pendulum-swing-pure-by-default">Pendulum swing: pure by default</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/2021/03/08/pendulum-swing-sealed-by-default Pendulum swing: internal by default https://blog.ploeh.dk/2021/03/01/pendulum-swing-internal-by-default/ Mon, 01 Mar 2021 08:26:00 UTC <div id="post"> <p> <em>Declare new C# classes as internal by default, and public by choice.</em> </p> <p> This is an article in <a href="/2021/02/22/pendulum-swings">a small series of articles about personal pendulum swings</a>. Here, I document a recent change of heart that's been a long way coming. In short, I now declare C# classes as <code>internal</code> unless they're driven by tests. </p> <h3 id="199c0f3d9cdc4ee5a6e93ce54a3f39a8"> Background <a href="#199c0f3d9cdc4ee5a6e93ce54a3f39a8" title="permalink">#</a> </h3> <p> When you create a new class in Visual Studio, the default accessibility is <code>internal</code>. In fact, Visual Studio's default templates don't add an access modifier at all, but if no access modifier is present, it implies <code>internal</code>. </p> <p> When I started out programming C#, I don't recall thinking much about accessibility modifiers. By default, then, I'd be using mostly <code>internal</code> classes. What little I knew about encapsulation (<em>information hiding</em>, anyone?) led me to believe that the more <code>internal</code> my code was, the better encapsulation it had. </p> <p> It's possible that I make my past self more ignorant than I actually was. It's almost twenty years ago: I don't recall all the details. </p> <h3 id="c98c637b240f4f0c97d6fc4d0f7d10f2"> Public all the things <a href="#c98c637b240f4f0c97d6fc4d0f7d10f2" title="permalink">#</a> </h3> <p> When I discovered test-driven development (TDD) (circa 2003) all my classes became public. They had to. When tests are interacting with code in another library, they can only exercise the system under test (SUT) if they can reach it. The tests make the SUT classes public. </p> <p> Yes, it's technically possible to test <code>internal</code> classes in .NET, but <a href="/2015/09/22/unit-testing-internals">I don't believe that you should</a>. I've yet to change my mind about that; no imminent pendulum swing there. You're testing something you <em>care</em> about. If the <code>internal</code> code serves any, <em>any</em>, purpose, it must be somehow observable. If so, verify that such observable behaviour takes place; if not, delete the code. (I'm sure you can dream up some corner cases where this doesn't hold; fine: I'm painting with a broad brush, here.) </p> <p> For years, I applied TDD, but I wasn't aware of the red-green-refactor cycle. I rarely changed the public API that the tests interacted with, and when I did, I made sure to adjust the tests accordingly. If a refactoring gave rise to new classes, I'd often write tests for those new classes as well. </p> <p> Imagine, for example, invoking the <em>Extract Class</em> refactoring. The new class would be as covered by tests as before the extraction, but what happens next is typically that you need to tweak it. When that happened to me, I'd typically write completely new tests to cover it. To do that, I'd need the extracted class to be <code>public</code>. </p> <p> In this phase of my professional life, my classes were almost exclusively <code>public</code>, with <code>internal</code> classes only making a rare appearance. </p> <p> One problem this tends to cause is that it makes code bases more brittle. Every type change is a potential breaking change. When every public class is covered by tests, this makes tests brittle. </p> <p> I think that it's relevant to consider the context of the code base. At this phase of my professional life, I maintained <a href="https://github.com/AutoFixture/AutoFixture">AutoFixture</a>, a fairly popular open-source library. I wanted that library to be stable so that users could trust it. I considered the test suite a guard of the contract. As long as a change didn't break any test, I considered it likely that it wasn't a breaking change. Thus, I was already conservative when it came to editing tests. I <a href="/2013/04/02/why-trust-tests">considered test to be append-only</a> in principle. </p> <p> I still consider it prudent to be conservative when it comes to a library with a public API. This doesn't mean, however, that this line of thinking carries over to code bases without a public (language-level) API. This may include web sites and services, but could also include installed apps. As long as there's no public API, there's no contract to break. </p> <h3 id="af12c8cba91944a29b9c377f5c3e045f"> Internal by default <a href="#af12c8cba91944a29b9c377f5c3e045f" title="permalink">#</a> </h3> <p> In 2020 I wrote a REST API of middling complexity. I used <a href="/outside-in-tdd">outside-in TDD</a> as a major driver. In the spirit of behaviour-driven development I favour describing the observable behaviour of the system. I use <a href="/2021/01/25/self-hosted-integration-tests-in-aspnet">self-hosted</a> <a href="/2019/02/18/from-interaction-based-to-state-based-testing">state-based integration tests</a> for this purpose. Only when I find that these tests get too complex do I grudgingly drop down to the unit-test level. </p> <p> The things that I test with unit tests have to be <code>public</code>. This still leaves plenty of room for behaviour described by the integration tests to have <code>internal</code> implementation details. The code base I mentioned has several examples of that. Some of them I've already described here on the blog. </p> <p> For example, notice that the <code>LinksFilter</code> <a href="/2020/08/24/adding-rest-links-as-a-cross-cutting-concern">shown here</a> is an <code>internal</code> class. Its behaviour is covered by abundant integration tests, so I'm not afraid to refactor it if need be. Those <code>LinkToYear</code>, <code>LinkToMonth</code>, and <code>LinkToDay</code> extension methods that it uses <a href="/2020/08/10/an-aspnet-core-url-builder">are internal too</a>. </p> <p> Another example is the <code>UrlIntegrityFilter</code> <a href="/2020/11/09/checking-signed-urls-with-aspnet">seen here</a>. The class itself is <code>internal</code> and its behaviour is composed from <code>private</code> helper functions. Its <a href="/2020/11/02/signing-urls-with-aspnet">counterpart</a> <code>SigningUrlHelper</code> is also <code>internal</code>. (Its companion <code>SigningUrlHelperFactory</code>, shown in the same article, is <code>public</code>, but that's an oversight on my part. It can easily be <code>internal</code> as well.) All that URL-signing behaviour is, again, covered by tests that verify the behaviour of the REST API. </p> <p> Another example from the same code base can be found in its so-called <em>calendar</em> feature. The system is an online restaurant reservation system. It allows clients to browse a day, a month, or even a year to see if there are any free spots for a given time slot. You can <a href="/2020/08/24/adding-rest-links-as-a-cross-cutting-concern">see an example here</a>. While I test-drove the calendar feature with integration tests, it quickly dawned on me that I had three disparate cases (day, month, year) that essentially represented the same concept: a <em>period</em>. </p> <p> A period is a closed set of heterogeneous data. A year contains only a single datum: the year itself (e.g. 2021). A month contains both a month and a year, and so on. A closed set of heterogeneous data describes a <a href="https://en.wikipedia.org/wiki/Tagged_union">sum type</a>, and since I know that in object-oriented programming, <a href="/2018/06/25/visitor-as-a-sum-type">sum types can be encoded as Visitors</a>, I introduced a Visitor API: </p> <p> <pre><span style="color:blue;">internal</span>&nbsp;<span style="color:blue;">interface</span>&nbsp;<span style="color:#2b91af;">IPeriod</span> { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">T</span>&nbsp;Accept&lt;<span style="color:#2b91af;">T</span>&gt;(<span style="color:#2b91af;">IPeriodVisitor</span>&lt;<span style="color:#2b91af;">T</span>&gt;&nbsp;visitor); } <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;VisitYear(<span style="color:blue;">int</span>&nbsp;year); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">T</span>&nbsp;VisitMonth(<span style="color:blue;">int</span>&nbsp;year,&nbsp;<span style="color:blue;">int</span>&nbsp;month); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">T</span>&nbsp;VisitDay(<span style="color:blue;">int</span>&nbsp;year,&nbsp;<span style="color:blue;">int</span>&nbsp;month,&nbsp;<span style="color:blue;">int</span>&nbsp;day); }</pre> </p> <p> I decided, however, to keep this API <code>internal</code>, since this isn't the only possible way to model this feature. As is the case with the other examples I've shown here, the behaviour is covered by integration tests. I feel free to refactor. In fact, this Visitor-based API is actually the result of a refactoring from something more ad hoc that I didn't like. </p> <p> Here's one of the three <code>IPeriod</code> implementation, in case you're curious: </p> <p> <pre><span style="color:blue;">internal</span>&nbsp;<span style="color:blue;">sealed</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">Month</span>&nbsp;:&nbsp;<span style="color:#2b91af;">IPeriod</span> { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">private</span>&nbsp;<span style="color:blue;">readonly</span>&nbsp;<span style="color:blue;">int</span>&nbsp;year; &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">private</span>&nbsp;<span style="color:blue;">readonly</span>&nbsp;<span style="color:blue;">int</span>&nbsp;month; &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">Month</span>(<span style="color:blue;">int</span>&nbsp;year,&nbsp;<span style="color:blue;">int</span>&nbsp;month) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">this</span>.year&nbsp;=&nbsp;year; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">this</span>.month&nbsp;=&nbsp;month; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">T</span>&nbsp;Accept&lt;<span style="color:#2b91af;">T</span>&gt;(<span style="color:#2b91af;">IPeriodVisitor</span>&lt;<span style="color:#2b91af;">T</span>&gt;&nbsp;visitor) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">return</span>&nbsp;visitor.VisitMonth(year,&nbsp;month); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:blue;">override</span>&nbsp;<span style="color:blue;">bool</span>&nbsp;Equals(<span style="color:blue;">object</span>?&nbsp;obj) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">return</span>&nbsp;obj&nbsp;<span style="color:blue;">is</span>&nbsp;<span style="color:#2b91af;">Month</span>&nbsp;month&nbsp;&amp;&amp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;year&nbsp;==&nbsp;month.year&nbsp;&amp;&amp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">this</span>.month&nbsp;==&nbsp;month.month; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:blue;">override</span>&nbsp;<span style="color:blue;">int</span>&nbsp;GetHashCode() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">return</span>&nbsp;<span style="color:#2b91af;">HashCode</span>.Combine(year,&nbsp;month); &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> This class, too, is <code>internal</code>, as are its two companions <code>Day</code> and <code>Year</code>. I'll leave it as an exercise for the interested reader to implement these two classes, as well as <code>IPeriodVisitor&lt;T&gt;</code> implementations that return the next or previous period, or the first or last tick of the period, etcetera. </p> <h3 id="af9c22ec88af4e3fa5f4b5c2356b5692"> Public by choice <a href="#af9c22ec88af4e3fa5f4b5c2356b5692" title="permalink">#</a> </h3> <p> This shifted emphasis of mine isn't a return to a simpler time. It's not <em>internal all the things!</em> It's about shifting the default for classes that are <em>not</em> driven by tests. Those classes that are artefacts of TDD are still <code>public</code> since <a href="/2015/09/22/unit-testing-internals">I don't directly unit test internal classes</a>. </p> <p> Other classes may start out as <code>internal</code> and then get promoted to <code>public</code> by choice. For example, I'd introduced a <code>Seating</code> class in the code base to model how long a seating was supposed to take: </p> <p> <pre><span style="color:blue;">internal</span>&nbsp;<span style="color:blue;">sealed</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">Seating</span> { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">internal</span>&nbsp;<span style="color:#2b91af;">Seating</span>(<span style="color:#2b91af;">TimeSpan</span>&nbsp;seatingDuration,&nbsp;<span style="color:#2b91af;">Reservation</span>&nbsp;reservation) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SeatingDuration&nbsp;=&nbsp;seatingDuration; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reservation&nbsp;=&nbsp;reservation; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;Members&nbsp;follow...</span></pre> </p> <p> Some restaurants have second seatings (or more). They give you a predefined duration after which you're supposed to be done so that they can reuse your table for another party. I'd used the <code>Seating</code> class to encapsulate some logic related to that, such as the <code>Overlaps</code> method: </p> <p> <pre><span style="color:blue;">internal</span>&nbsp;<span style="color:#2b91af;">DateTime</span>&nbsp;Start { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">get</span>&nbsp;{&nbsp;<span style="color:blue;">return</span>&nbsp;Reservation.At;&nbsp;} } <span style="color:blue;">internal</span>&nbsp;<span style="color:#2b91af;">DateTime</span>&nbsp;End { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">get</span>&nbsp;{&nbsp;<span style="color:blue;">return</span>&nbsp;Start&nbsp;+&nbsp;SeatingDuration;&nbsp;} } <span style="color:blue;">internal</span>&nbsp;<span style="color:blue;">bool</span>&nbsp;Overlaps(<span style="color:#2b91af;">Reservation</span>&nbsp;other) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;otherSeating&nbsp;=&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Seating</span>(SeatingDuration,&nbsp;other); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">return</span>&nbsp;Start&nbsp;&lt;&nbsp;otherSeating.End&nbsp;&amp;&amp;&nbsp;otherSeating.Start&nbsp;&lt;&nbsp;End; }</pre> </p> <p> While I considered this a well-designed little class with good encapsulation, I kept it <code>internal</code> simply because there was no need to make it <code>public</code>. It was indirectly covered by test cases, but it was a result of a refactoring and not directly test-driven. </p> <p> As I started to add a new feature, I realised that I'd be able to write new unit tests in a better way if I could reuse <code>Seating</code> and a variation of its <code>Overlaps</code> method. I considered it carefully and decided to make the class and its members public: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:blue;">sealed</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">Seating</span> { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">Seating</span>(<span style="color:#2b91af;">TimeSpan</span>&nbsp;seatingDuration,&nbsp;<span style="color:#2b91af;">Reservation</span>&nbsp;reservation) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SeatingDuration&nbsp;=&nbsp;seatingDuration; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reservation&nbsp;=&nbsp;reservation; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;Members&nbsp;follow...</span></pre> </p> <p> I made this decision after explicit deliberation. It didn't take long, though, but I did shortly stop to consider whether this seemed like a good idea. This code base isn't a <a href="/2012/12/18/RangersandZookeepers">reusable library in the wild</a>, so I wasn't concerned about misuse of the API. I did consider, on the other hand, how this would increase coupling between the tests and the production code base. It didn't take me long to decide that in this case, I was okay with that. </p> <p> <code>Seating</code> had already existed as an <code>internal</code> class for some time and had proven useful and stable. Putting on my <a href="http://amzn.to/WBCwx7">DDD</a> hat, I also thought that <code>Seating</code> represented a proper domain concept. </p> <h3 id="f6ef0cc965d845fe889170ee956baa4d"> Conclusion <a href="#f6ef0cc965d845fe889170ee956baa4d" title="permalink">#</a> </h3> <p> You can go back and forth on how you write code; which rules of thumb you apply. For many years, I favoured <code>public</code> classes. I think that I even, at one time, tweaked the Visual Studio templates to explicitly create new classes as <code>public</code>. </p> <p> Now, I've changed my heuristic. Classes driven into existence by tests are <code>public</code>; they have to be. Other classes I now make <em>internal by default, and public by choice</em>. </p> <p> This is going to be my rule until I change it. </p> <p> <strong>Next:</strong> <a href="/2021/03/08/pendulum-swing-sealed-by-default">Pendulum swing: sealed by default</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/2021/03/01/pendulum-swing-internal-by-default Pendulum swings https://blog.ploeh.dk/2021/02/22/pendulum-swings/ Mon, 22 Feb 2021 08:04:00 UTC <div id="post"> <p> <em>The software development industry goes back and forth on how to do things, and so do I.</em> </p> <p> I've been working with something IT-related since 1994, and I've been a professional programmer since 1999. When you observe the software development industry over decades, you may start to notice some trends. One decade, service-oriented architecture (SOA) is cool; the next, consolidation sets in; then it's micro-services; and, as far as I can tell, monoliths are on the way in again, although I'm sure that we'll find something else to call them. </p> <p> It's as if a pendulum swings from one extreme to the other. Sooner or later, it comes back, only to then continue its swing in the other direction. If you view it over time and assume no loss to friction, a pendulum describes a sine wave. </p> <p> <img src="/content/binary/sine-wave.png" alt="A sine wave."> </p> <p> There's probably several reasons for this motion. The benign interpretation is that it's still a young industry and we're still learning. It's not uncommon to see oscillations in dynamic systems, particularly when feedback isn't immediate. </p> <p> Software architecture tends to produce slow feedback. Architecture solves more than one problem, including scalability, but a major motivation to think about architecture is to pick a way to organise the source code so that you don't have to rewrite from scratch every 2-3 years. Tautologically, then, it takes years before you know whether or not you succeeded. </p> <p> While waiting for feedback, you may continue doing what you believe is right: micro-services versus monoliths, unit tests versus acceptance tests, etcetera. Once you discover that a particular way to work has problems, you may overcompensate by going too far in the other direction. </p> <p> Once you discover the problem with that, you may begin to pull back towards the original position. Because feedback is delayed, the pendulum once more swings too far. </p> <p> If we manage to learn from our mistakes, one could hope that the oscillations we currently observe will dampen until we reach equilibrium in the future. The industry is still so young, though, that the pendulum makes wide swings. Perhaps it'll takes decades, or even centuries, before the oscillations die down. </p> <p> The more cynic interpretation is that most software developers have only a few years of professional experience, and aren't taught the experiences of past generations. <blockquote> <p> "Those who cannot remember the past are condemned to repeat it." </p> <footer><cite>George Santayana</cite></footer> </blockquote> In this light, the industry keeps regurgitating the same ideas over and over, never learning from past mistakes. </p> <p> The truth is probably a mix of both explanations. </p> <h3 id="36d029a90bfa4d35a7e8fc10048b8bcc"> Personal pendulum <a href="#36d029a90bfa4d35a7e8fc10048b8bcc" title="permalink">#</a> </h3> <p> I've noticed a similar tendency in myself. I work in a particular way until I run into the limitations of that way. Then, after a time of frustration, I change direction. </p> <p> As an example, I'm an autodidact programmer. In the beginning of my career, I'd just throw together code until I thought it worked, then launch the software with the debugger attached only to discover that it didn't, then go back and tweak some more, and so on. </p> <p> Then I discovered test-driven development (TDD) and for years, it was the only way I could conceive of working. As my experience with TDD grew, I started to notice that it wasn't the panacea that I believed when it was all new. <a href="/2010/12/22/TheTDDApostate">I wrote about that as early as late 2010</a>. Knowing myself, I'd probably started to notice problems with TDD before that. I have cognitive biases just like the next person. You can lie to yourself for years before the problems become so blatant that you can no longer ignore them. </p> <p> To be clear, I never lost faith in TDD, but I began to glimpse the contours of its limitations. It's good for many circumstances, and it's still my preferred technique for developing new production code, but I use other techniques for e.g. prototyping. </p> <p> In 2020 I wrote a code base of middling complexity, and I noticed that I'd started to change my position on some other long-standing practices. As I've tried to explain, it may look like pendulum swings, but I hope that they are, at least, dampened swings. I intend to observe what happens so that I can learn from these new directions. </p> <p> In the following, I'll be writing about these new approaches that I'm trying on, and so far like: <ul> <li><a href="/2021/03/01/pendulum-swing-internal-by-default">Pendulum swing: internal by default</a></li> <li><a href="/2021/03/08/pendulum-swing-sealed-by-default">Pendulum swing: sealed by default</a></li> <li><a href="/2021/03/15/pendulum-swing-pure-by-default">Pendulum swing: pure by default</a></li> </ul> I'd be naive if I believed these to be my final words on any of these topics. I'm currently trying them out for size; in a few decades I'll know more about how it all turns out. </p> <h3 id="fdb1ddeb6709428ca1f0e7f441085b3d"> Conclusion <a href="#fdb1ddeb6709428ca1f0e7f441085b3d" title="permalink">#</a> </h3> <p> One year TDD is all the rage; a few years later, it's BDD. One year it's SOA, then it's <a href="https://alistair.cockburn.us/hexagonal-architecture/">ports and adapters</a> (which implies consolidated deployment), then it's micro-services. One year, it's XML, then it's JSON, then it's YAML. One decade it's structured programming, then it's object-orientation, then it's functional programming, and so on ad nauseam. </p> <p> Hopefully, this is just a symptom of growing pains. Hopefully, we'll learn from all these wild swings so that we don't have to rewrite applications when older developers leave. </p> <p> The only course of action that I can see for myself here is to document how I work so that I, and others, can learn from those experiences. </p> <p> <strong>Next:</strong> <a href="/2021/03/01/pendulum-swing-internal-by-default">Pendulum swing: internal by default</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/2021/02/22/pendulum-swings When properties are easier than examples https://blog.ploeh.dk/2021/02/15/when-properties-are-easier-than-examples/ Mon, 15 Feb 2021 07:33:00 UTC <div id="post"> <p> <em>Sometimes, describing the properties of a function is easier than coming up with examples.</em> </p> <p> Instead of the term <em>test-driven development</em> you may occasionally encounter the phrase <em>example-driven development</em>. The idea is that each test is an example of how the system under test ought to behave. As you add more tests, you add more examples. </p> <p> I've noticed that beginners often find it difficult to come up with good examples. This is the reason I've developed the <a href="/2019/10/07/devils-advocate">Devil's advocate</a> technique. It's meant as a heuristic that may help you identify the next good example. It's particularly effective if you combine it with the <a href="https://blog.cleancoder.com/uncle-bob/2013/05/27/TheTransformationPriorityPremise.html">Transformation Priority Premise</a> (TPP) and <a href="https://en.wikipedia.org/wiki/Equivalence_partitioning">equivalence partitioning</a>. </p> <p> I've noticed, however, that translating concrete examples into code is not always straightforward. In the following, I'll describe an experience I had in 2020 while developing an online restaurant reservation system. </p> <h3 id="83a8dd13c9694ebc99b5fa4ae049b3b4"> Problem outline <a href="#83a8dd13c9694ebc99b5fa4ae049b3b4" title="permalink">#</a> </h3> <p> I'm going to start by explaining what it was that I was trying to do. I wanted to present the <a href="https://en.wikipedia.org/wiki/Ma%C3%AEtre_d%27h%C3%B4tel">maître d'</a> (or other restaurant staff) with a schedule of a day's reservations. It should take the form of a list of time entries, one entry for every time one or more new reservations would start. I also wanted to list, for each entry, all reservations that were currently ongoing, or would soon start. Here's a simple example, represented as JSON: </p> <p> <pre><span style="color:#2e75b6;">&quot;date&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;2023-08-23&quot;</span>, <span style="color:#2e75b6;">&quot;entries&quot;</span>:&nbsp;[ &nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;time&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;20:00:00&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;reservations&quot;</span>:&nbsp;[ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;id&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;af5feb35f62f475cb02df2a281948829&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;at&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;2023-08-23T20:00:00.0000000&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;email&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;crystalmeth@example.net&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;name&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;Crystal&nbsp;Metheney&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;quantity&quot;</span>:&nbsp;3 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;id&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;eae39bc5b3a7408eb2049373b2661e32&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;at&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;2023-08-23T20:30:00.0000000&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;email&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;x.benedict@example.org&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;name&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;Benedict&nbsp;Xavier&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;quantity&quot;</span>:&nbsp;4 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;] &nbsp;&nbsp;}, &nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;time&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;20:30:00&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;reservations&quot;</span>:&nbsp;[ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;id&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;af5feb35f62f475cb02df2a281948829&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;at&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;2023-08-23T20:00:00.0000000&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;email&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;crystalmeth@example.net&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;name&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;Crystal&nbsp;Metheney&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;quantity&quot;</span>:&nbsp;3 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;id&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;eae39bc5b3a7408eb2049373b2661e32&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;at&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;2023-08-23T20:30:00.0000000&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;email&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;x.benedict@example.org&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;name&quot;</span>:&nbsp;<span style="color:#a31515;">&quot;Benedict&nbsp;Xavier&quot;</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e75b6;">&quot;quantity&quot;</span>:&nbsp;4 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;] &nbsp;&nbsp;} ]</pre> </p> <p> To keep the example simple, there are only two reservations for that particular day: one for 20:00 and one for 20:30. Since something happens at both of these times, both time has an entry. My intent isn't necessarily that a user interface should show the data in this way, but I wanted to make the relevant data available so that a user interface could show it if it needed to. </p> <p> The first entry for 20:00 shows both reservations. It shows the reservation for 20:00 for obvious reasons, and it shows the reservation for 20:30 to indicate that the staff can expect a party of four at 20:30. Since this restaurant runs with a single seating per evening, this effectively means that although the reservation hasn't started yet, it still reserves a table. This gives a user interface an opportunity to show the state of the restaurant at that time. The table for the 20:30 party isn't active yet, but it's effectively reserved. </p> <p> For restaurants with shorter seating durations, the schedule should reflect that. If the seating duration is, say, two hours, and someone has a reservation for 20:00, you can sell that table to another party at 18:00, but not at 18:30. I wanted the functionality to take such things into account. </p> <p> The other entry in the above example is for 20:30. Again, both reservations are shown because one is ongoing (and takes up a table) and the other is just starting. </p> <h3 id="63e308b1c630441e8f55fe3ecaa5a03f"> Desired API <a href="#63e308b1c630441e8f55fe3ecaa5a03f" title="permalink">#</a> </h3> <p> A major benefit of test-driven development (TDD) is that you get fast feedback on the API you intent for the system under test (SUT). You write a test against the intended API, and besides a pass-or-fail result, you also learn something about the interaction between client code and the SUT. You often learn that the original design you had in mind isn't going to work well once it meets the harsh realities of an actual programming language. </p> <p> In TDD, you often have to revise the design multiple times during the process. </p> <p> This doesn't mean that you can't have a plan. You can't write the initial test if you have no inkling of what the API should look like. For the schedule feature, I did have a plan. It turned out to hold, more or less. I wanted the API to be a method on a class called <code>MaitreD</code>, which already had these four fields and the constructors to support them: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">TimeOfDay</span>&nbsp;OpensAt&nbsp;{&nbsp;<span style="color:blue;">get</span>;&nbsp;} <span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">TimeOfDay</span>&nbsp;LastSeating&nbsp;{&nbsp;<span style="color:blue;">get</span>;&nbsp;} <span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">TimeSpan</span>&nbsp;SeatingDuration&nbsp;{&nbsp;<span style="color:blue;">get</span>;&nbsp;} <span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&nbsp;Tables&nbsp;{&nbsp;<span style="color:blue;">get</span>;&nbsp;}</pre> </p> <p> I planned to implement the new feature as a new instance method on that class: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>)</pre> </p> <p> This plan turned out to hold in general, although I ultimately decided to simplify the return type by getting rid of the <code>Occurrence</code> <a href="https://bartoszmilewski.com/2014/01/14/functors-are-containers">container</a>. It's going to be present throughout this article, however, so I need to briefly introduce it. I meant to use it as a generic container of anything, but with an time-stamp associated with the value: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:blue;">sealed</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">T</span>&gt; { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">Occurrence</span>(<span style="color:#2b91af;">DateTime</span>&nbsp;<span style="color:#1f377f;">at</span>,&nbsp;<span style="color:#2b91af;">T</span>&nbsp;<span style="color:#1f377f;">value</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;At&nbsp;=&nbsp;<span style="color:#1f377f;">at</span>; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Value&nbsp;=&nbsp;<span style="color:#1f377f;">value</span>; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">DateTime</span>&nbsp;At&nbsp;{&nbsp;<span style="color:blue;">get</span>;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">T</span>&nbsp;Value&nbsp;{&nbsp;<span style="color:blue;">get</span>;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">TResult</span>&gt;&nbsp;<span style="color:#74531f;">Select</span>&lt;<span style="color:#2b91af;">TResult</span>&gt;(<span style="color:#2b91af;">Func</span>&lt;<span style="color:#2b91af;">T</span>,&nbsp;<span style="color:#2b91af;">TResult</span>&gt;&nbsp;<span style="color:#1f377f;">selector</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">if</span>&nbsp;(<span style="color:#1f377f;">selector</span>&nbsp;<span style="color:blue;">is</span>&nbsp;<span style="color:blue;">null</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">throw</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">ArgumentNullException</span>(<span style="color:blue;">nameof</span>(<span style="color:#1f377f;">selector</span>)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">TResult</span>&gt;(At,&nbsp;<span style="color:#1f377f;">selector</span>(Value)); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:blue;">override</span>&nbsp;<span style="color:blue;">bool</span>&nbsp;<span style="color:#74531f;">Equals</span>(<span style="color:blue;">object</span>?&nbsp;<span style="color:#1f377f;">obj</span>) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:#1f377f;">obj</span>&nbsp;<span style="color:blue;">is</span>&nbsp;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">T</span>&gt;&nbsp;<span style="color:#1f377f;">occurrence</span>&nbsp;&amp;&amp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;At&nbsp;<span style="color:#74531f;">==</span>&nbsp;<span style="color:#1f377f;">occurrence</span>.At&nbsp;&amp;&amp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">EqualityComparer</span>&lt;<span style="color:#2b91af;">T</span>&gt;.Default.<span style="color:#74531f;">Equals</span>(Value,&nbsp;<span style="color:#1f377f;">occurrence</span>.Value); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:blue;">override</span>&nbsp;<span style="color:blue;">int</span>&nbsp;<span style="color:#74531f;">GetHashCode</span>() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:#2b91af;">HashCode</span>.<span style="color:#74531f;">Combine</span>(At,&nbsp;Value); &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> You may notice that due to the presence of the <code>Select</code> method this is a <a href="/2018/03/22/functors">functor</a>. </p> <p> There's also a little extension method that we may later encounter: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">T</span>&gt;&nbsp;<span style="color:#74531f;">At</span>&lt;<span style="color:#2b91af;">T</span>&gt;(<span style="color:blue;">this</span>&nbsp;<span style="color:#2b91af;">T</span>&nbsp;<span style="color:#1f377f;">value</span>,&nbsp;<span style="color:#2b91af;">DateTime</span>&nbsp;<span style="color:#1f377f;">at</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">T</span>&gt;(<span style="color:#1f377f;">at</span>,&nbsp;<span style="color:#1f377f;">value</span>); }</pre> </p> <p> The plan, then, is to return a collection of occurrences, each of which may contain a collection of tables that are relevant to include at that time entry. </p> <h3 id="d121920365874005a3bf46d0555bd008"> Examples <a href="#d121920365874005a3bf46d0555bd008" title="permalink">#</a> </h3> <p> When I embarked on developing this feature, I thought that it was a good fit for example-driven development. Since the input for <code>Schedule</code> requires a collection of <code>Reservation</code> objects, each of which comes with some data, I expected the test cases to become verbose. So I decided to bite the bullet right away and define test cases using <a href="https://xunit.net">xUnit.net</a>'s <code>[ClassData]</code> feature. I wrote this test: </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;">ScheduleTestCases</span>))] <span style="color:blue;">public</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="color:#74531f;">Schedule</span>( &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">MaitreD</span>&nbsp;<span style="color:#1f377f;">sut</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">Table</span>[]&gt;&gt;&nbsp;<span style="color:#1f377f;">expected</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="color:#1f377f;">sut</span>.<span style="color:#74531f;">Schedule</span>(<span style="color:#1f377f;">reservations</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">expected</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">o</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">ts</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">ts</span>.<span style="color:#74531f;">AsEnumerable</span>())), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>); }</pre> </p> <p> This is almost as simple as it can be: Call the method and verify that <code>expected</code> is equal to <code>actual</code>. The only slightly complicated piece is the nested projection of <code>expected</code> from <code>IEnumerable&lt;Occurrence&lt;Table[]&gt;&gt;</code> to <code>IEnumerable&lt;Occurrence&lt;IEnumerable&lt;Table&gt;&gt;&gt;</code>. There are ugly reasons for this that I don't want to discuss here, since they have no bearing on the actual topic, which is coming up with tests. </p> <p> I also added the <code>ScheduleTestCases</code> class and a single test case: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">class</span>&nbsp;<span style="color:#2b91af;">ScheduleTestCases</span>&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TheoryData</span>&lt;<span style="color:#2b91af;">MaitreD</span>,&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;,&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">Table</span>[]&gt;&gt;&gt; { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">ScheduleTestCases</span>() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;No&nbsp;reservations,&nbsp;so&nbsp;no&nbsp;occurrences:</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#74531f;">Add</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">MaitreD</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(18), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(21), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(6), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Communal</span>(12)), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Array</span>.<span style="color:#74531f;">Empty</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Array</span>.<span style="color:#74531f;">Empty</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">Table</span>[]&gt;&gt;()); &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> The simplest implementation that passed that test was this: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">yield</span>&nbsp;<span style="color:#8f08c4;">break</span>; }</pre> </p> <p> Okay, hardly rocket science, but this was just a test case to get started. So I added another one: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="color:#74531f;">SingleReservationCommunalTable</span>() { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">table</span>&nbsp;=&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Communal</span>(12); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">r</span>&nbsp;=&nbsp;<span style="color:#2b91af;">Some</span>.Reservation; &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#74531f;">Add</span>(<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">MaitreD</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(18), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(21), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(6), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">table</span>), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>[]&nbsp;{&nbsp;<span style="color:#1f377f;">r</span>&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>[]&nbsp;{&nbsp;<span style="color:blue;">new</span>[]&nbsp;{&nbsp;<span style="color:#1f377f;">table</span>.<span style="color:#74531f;">Reserve</span>(<span style="color:#1f377f;">r</span>)&nbsp;}.<span style="color:#74531f;">At</span>(<span style="color:#1f377f;">r</span>.At)&nbsp;}); }</pre> </p> <p> This test case adds a single reservation to a restaurant with a single communal table. The <code>expected</code> result is now a single occurrence with that reservation. In true TDD fashion, this new test case caused a test failure, and I now had to adjust the <code>Schedule</code> method to pass all tests: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">if</span>&nbsp;(<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Any</span>()) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">r</span>&nbsp;=&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">First</span>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">yield</span>&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:blue;">new</span>[]&nbsp;{&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Communal</span>(12).<span style="color:#74531f;">Reserve</span>(<span style="color:#1f377f;">r</span>)&nbsp;}.<span style="color:#74531f;">AsEnumerable</span>().<span style="color:#74531f;">At</span>(<span style="color:#1f377f;">r</span>.At); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">yield</span>&nbsp;<span style="color:#8f08c4;">break</span>; }</pre> </p> <p> You might have wanted to jump to something prettier right away, but I wanted to proceed according to the Devil's advocate technique. I was concerned that I was going to mess up the implementation if I moved too fast. </p> <p> And that was when I basically hit a wall. </p> <h3 id="c8fd655d50414215b04f891676a09bd8"> Property-based testing to the rescue <a href="#c8fd655d50414215b04f891676a09bd8" title="permalink">#</a> </h3> <p> I couldn't figure out how to proceed from there. Which test case ought to be the next? I wanted to follow the spirit of the TPP and pick a test case that would cause another incremental step in the right direction. The sheer number of possible combinations overwhelmed me, though. Should I adjust the reservations? The table configuration for the <code>MaitreD</code> class? The <code>SeatingDuration</code>? </p> <p> It's possible that you'd be able to conjure up the perfect next test case, but I couldn't. I actually let it stew for a couple of days before I decided to give up on the example-driven approach. While I couldn't see a clear path forward with concrete examples, I had a vivid vision of how to proceed with <a href="/property-based-testing-intro">property-based testing</a>. </p> <p> I left the above tests in place and instead added a new test class to my code base. Its only purpose: to test the <code>Schedule</code> method. The test method itself is only a composition of various data definitions and the actual test code: </p> <p> <pre>[<span style="color:#2b91af;">Property</span>] <span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">Property</span>&nbsp;<span style="color:#74531f;">Schedule</span>() { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:#2b91af;">Prop</span>.<span style="color:#74531f;">ForAll</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GenReservation.<span style="color:#74531f;">ArrayOf</span>().<span style="color:#74531f;">ToArbitrary</span>(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#74531f;">ScheduleImp</span>); }</pre> </p> <p> This uses <a href="https://fscheck.github.io/FsCheck">FsCheck</a> 2.14.3, which is written in <a href="https://fsharp.org">F#</a> and composes better if you also write the tests in F#. In order to make things a little more palatable for C# developers, I decided to implement the building blocks for the property using methods and class properties. </p> <p> The <code>ScheduleImp</code> method, for example, actually implements the test. This method runs a hundred times (FsCheck's default value) with randomly generated input values: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="color:#74531f;">ScheduleImp</span>(<span style="color:#2b91af;">Reservation</span>[]&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;Create&nbsp;a&nbsp;table&nbsp;for&nbsp;each&nbsp;reservation,&nbsp;to&nbsp;ensure&nbsp;that&nbsp;all</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;reservations&nbsp;can&nbsp;be&nbsp;allotted&nbsp;a&nbsp;table.</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">tables</span>&nbsp;=&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Standard</span>(<span style="color:#1f377f;">r</span>.Quantity)); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">sut</span>&nbsp;=&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">MaitreD</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(18), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(21), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(6), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">tables</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="color:#1f377f;">sut</span>.<span style="color:#74531f;">Schedule</span>(<span style="color:#1f377f;">reservations</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">r</span>.At).<span style="color:#74531f;">Distinct</span>().<span style="color:#74531f;">Count</span>(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Count</span>()); }</pre> </p> <p> The step you see in the first line of code is an example of a trick that I find myself doing often with property-based testing: instead of trying to find some good test values for a particular set of circumstances, I create a set of circumstances that fits the randomly generated test values. As the code comment explains, given a set of <code>Reservation</code> values, it creates a table that fits each reservation. In that way I ensure that all the reservations can be allocated a table. </p> <p> I'll soon return to how those random <code>Reservation</code> values are generated, but first let's discuss the rest of the test body. Given a valid <code>MaitreD</code> object it calls the <code>Schedule</code> method. In the <a href="/2013/06/24/a-heuristic-for-formatting-code-according-to-the-aaa-pattern">assertion phase</a>, it so far only verifies that there's as many time entries in <code>actual</code> as there are distinct <code>At</code> values in <code>reservations</code>. </p> <p> That's hardly a comprehensive description of the SUT, but it's a start. The following implementation passes both the new property, as well as the two examples above. </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;r&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#1f377f;">reservations</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">group</span>&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Communal</span>(12).<span style="color:#74531f;">Reserve</span>(r)&nbsp;<span style="color:blue;">by</span>&nbsp;r.At&nbsp;<span style="color:blue;">into</span>&nbsp;g &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;g.<span style="color:#74531f;">AsEnumerable</span>().<span style="color:#74531f;">At</span>(g.Key); }</pre> </p> <p> I know that many C# programmers don't like query syntax, but I've always had a soft spot for it. I liked it, but wasn't sure that I'd be able to keep it up as I added more constraints to the property. </p> <h3 id="5670f47a815542bfac848645e9a3ccf4"> Generators <a href="#5670f47a815542bfac848645e9a3ccf4" title="permalink">#</a> </h3> <p> Before we get to that, though, I promised to show you how the random <code>reservations</code> are generated. FsCheck has an API for that, and it's also query-syntax-friendly: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">Email</span>&gt;&nbsp;GenEmail&nbsp;=&gt; &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;s&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Arb</span>.<span style="color:#2b91af;">Default</span>.<span style="color:#74531f;">NonWhiteSpaceString</span>().Generator &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Email</span>(s.Item); <span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">Name</span>&gt;&nbsp;GenName&nbsp;=&gt; &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;s&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Arb</span>.<span style="color:#2b91af;">Default</span>.<span style="color:#74531f;">StringWithoutNullChars</span>().Generator &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Name</span>(s.Item); <span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;GenReservation&nbsp;=&gt; &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;id&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Arb</span>.<span style="color:#2b91af;">Default</span>.<span style="color:#74531f;">Guid</span>().Generator &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;d&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Arb</span>.<span style="color:#2b91af;">Default</span>.<span style="color:#74531f;">DateTime</span>().Generator &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;e&nbsp;<span style="color:blue;">in</span>&nbsp;GenEmail &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;n&nbsp;<span style="color:blue;">in</span>&nbsp;GenName &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;q&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Arb</span>.<span style="color:#2b91af;">Default</span>.<span style="color:#74531f;">PositiveInt</span>().Generator &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Reservation</span>(id,&nbsp;d,&nbsp;e,&nbsp;n,&nbsp;q.Item);</pre> </p> <p> <code>GenReservation</code> is a generator of <code>Reservation</code> values (for a simplified explanation of how such a generator might work, see <a href="/2017/09/18/the-test-data-generator-functor">The Test Data Generator functor</a>). It's composed from smaller generators, among these <code>GenEmail</code> and <code>GenName</code>. The rest of the generators are general-purpose generators defined by FsCheck. </p> <p> If you refer back to the <code>Schedule</code> property above, you'll see that it uses <code>GenReservation</code> to produce an array generator. This is another general-purpose combinator provided by FsCheck. It turns any single-object generator into a generator of arrays containing such objects. Some of these arrays will be empty, which is often desirable, because it means that you'll automatically get coverage of that edge case. </p> <h3 id="ad13aac51d654a7f988b1106579f42fd"> Iterative development <a href="#ad13aac51d654a7f988b1106579f42fd" title="permalink">#</a> </h3> <p> As I already <a href="/2015/01/10/diamond-kata-with-fscheck">discovered in 2015</a> some problems are just much better suited for property-based development than example-driven development. As I expected, this one turned out to be just such a problem. (Recently, <a href="https://www.hillelwayne.com">Hillel Wayne</a> identified a set of problems with no clear properties as <a href="https://buttondown.email/hillelwayne/archive/cross-branch-testing/">rho problems</a>. I wonder if we should pick another Greek letter for this type of problems that almost ooze properties. Sigma problems? Maybe we should just call them <em>describable problems</em>...) </p> <p> For the next step, I didn't have to write a completely new property. I only had to add a new assertion, and thereby strengthening the postconditions of the <code>Schedule</code> method: </p> <p> <pre><span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>( &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">o</span>.At).<span style="color:#74531f;">OrderBy</span>(<span style="color:#1f377f;">d</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">d</span>), &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">o</span>.At));</pre> </p> <p> I added the above assertion to <code>ScheduleImp</code> after the previous assertion. It simply states that <code>actual</code> should be sorted in ascending order. </p> <p> To pass this new requirement I added an ordering clause to the implementation: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;r&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#1f377f;">reservations</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">group</span>&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Communal</span>(12).<span style="color:#74531f;">Reserve</span>(r)&nbsp;<span style="color:blue;">by</span>&nbsp;r.At&nbsp;<span style="color:blue;">into</span>&nbsp;g &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">orderby</span>&nbsp;g.Key &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;g.<span style="color:#74531f;">AsEnumerable</span>().<span style="color:#74531f;">At</span>(g.Key); }</pre> </p> <p> It passes all tests. Commit to Git. Next. </p> <h3 id="040edba86dfd4bfe8a57cef15b4a9ff6"> Table configuration <a href="#040edba86dfd4bfe8a57cef15b4a9ff6" title="permalink">#</a> </h3> <p> If you consider the current implementation, there's much not to like. The worst offence, I think, is that it conjures a hard-coded communal table out of thin air. The method ought to use the table configuration passed to the <code>MaitreD</code> object. This seems like an obvious flaw to address. I therefore added this to the property: </p> <p> <pre>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">All</span>(<span style="color:#1f377f;">actual</span>,&nbsp;<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#74531f;">AssertTables</span>(<span style="color:#1f377f;">tables</span>,&nbsp;<span style="color:#1f377f;">o</span>.Value)); } <span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="color:#74531f;">AssertTables</span>( &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&nbsp;<span style="color:#1f377f;">expected</span>, &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&nbsp;<span style="color:#1f377f;">actual</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>(<span style="color:#1f377f;">expected</span>.<span style="color:#74531f;">Count</span>(),&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Count</span>()); }</pre> </p> <p> It's just another assertion that uses the helper assertion also shown. As a first pass, it's not enough to cheat the Devil, but it sets me up for my next move. The plan is to assert that no tables are generated out of thin air. Currently, <code>AssertTables</code> only verifies that the actual count of tables in each occurrence matches the expected count. </p> <p> The Devil easily foils that plan by generating a table for each reservation: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">tables</span>&nbsp;=&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Communal</span>(12).<span style="color:#74531f;">Reserve</span>(<span style="color:#1f377f;">r</span>)); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;r&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#1f377f;">reservations</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">group</span>&nbsp;r&nbsp;<span style="color:blue;">by</span>&nbsp;r.At&nbsp;<span style="color:blue;">into</span>&nbsp;g &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">orderby</span>&nbsp;g.Key &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:#1f377f;">tables</span>.<span style="color:#74531f;">At</span>(g.Key); }</pre> </p> <p> This (unfortunately) passes all tests, so commit to Git and move on. </p> <p> The next move I made was to add an assertion to <code>AssertTables</code>: </p> <p> <pre><span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>( &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">expected</span>.<span style="color:#74531f;">Sum</span>(<span style="color:#1f377f;">t</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">t</span>.Capacity), &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Sum</span>(<span style="color:#1f377f;">t</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">t</span>.Capacity));</pre> </p> <p> This new requirement states that the total capacity of the actual tables should be equal to the total capacity of the allocated tables. It doesn't prevent the Devil from generating tables out of thin air, but it makes it harder. At least, it makes it so hard that I found it more reasonable to use the supplied table configuration: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">tables</span>&nbsp;=&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Zip</span>(Tables,&nbsp;(<span style="color:#1f377f;">r</span>,&nbsp;<span style="color:#1f377f;">t</span>)&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">t</span>.<span style="color:#74531f;">Reserve</span>(<span style="color:#1f377f;">r</span>)); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;r&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#1f377f;">reservations</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">group</span>&nbsp;r&nbsp;<span style="color:blue;">by</span>&nbsp;r.At&nbsp;<span style="color:blue;">into</span>&nbsp;g &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">orderby</span>&nbsp;g.Key &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:#1f377f;">tables</span>.<span style="color:#74531f;">At</span>(g.Key); }</pre> </p> <p> The implementation of <code>Schedule</code> still cheats because it 'knows' that no tests (except for the degenerate test where there are no reservations) have surplus tables in the configuration. It takes advantage of that knowledge to zip the two collections, which is really not appropriate. </p> <p> Still, it seems that things are moving in the right direction. </p> <h3 id="5891a00f231f46b68afb0b6aff43b0b0"> Generated SUT <a href="#5891a00f231f46b68afb0b6aff43b0b0" title="permalink">#</a> </h3> <p> Until now, <code>ScheduleImp</code> has been using a hard-coded <code>sut</code>. It's time to change that. </p> <p> To keep my steps as small as possible, I decided to start with the <code>SeatingDuration</code> since it was currently not being used by the implementation. This meant that I could start randomising it without affecting the SUT. Since this was a code change of middling complexity in the test code, I found it most prudent to move in such a way that I didn't have to change the SUT as well. </p> <p> I completely extracted the initialisation of the <code>sut</code> to a method argument of the <code>ScheduleImp</code> method, and adjusted it accordingly: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="color:#74531f;">ScheduleImp</span>(<span style="color:#2b91af;">MaitreD</span>&nbsp;<span style="color:#1f377f;">sut</span>,&nbsp;<span style="color:#2b91af;">Reservation</span>[]&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="color:#1f377f;">sut</span>.<span style="color:#74531f;">Schedule</span>(<span style="color:#1f377f;">reservations</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">r</span>.At).<span style="color:#74531f;">Distinct</span>().<span style="color:#74531f;">Count</span>(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Count</span>()); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">o</span>.At).<span style="color:#74531f;">OrderBy</span>(<span style="color:#1f377f;">d</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">d</span>), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">o</span>.At)); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">All</span>(<span style="color:#1f377f;">actual</span>,&nbsp;<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#74531f;">AssertTables</span>(<span style="color:#1f377f;">sut</span>.Tables,&nbsp;<span style="color:#1f377f;">o</span>.Value)); }</pre> </p> <p> This meant that I also had to adjust the calling property: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">Property</span>&nbsp;<span style="color:#74531f;">Schedule</span>() { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:#2b91af;">Prop</span>.<span style="color:#74531f;">ForAll</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GenReservation &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="color:#74531f;">ArrayOf</span>() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="color:#74531f;">SelectMany</span>(<span style="color:#1f377f;">rs</span>&nbsp;=&gt;&nbsp;<span style="color:#74531f;">GenMaitreD</span>(<span style="color:#1f377f;">rs</span>).<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">m</span>&nbsp;=&gt;&nbsp;(<span style="color:#1f377f;">m</span>,&nbsp;<span style="color:#1f377f;">rs</span>))) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="color:#74531f;">ToArbitrary</span>(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">t</span>&nbsp;=&gt;&nbsp;<span style="color:#74531f;">ScheduleImp</span>(<span style="color:#1f377f;">t</span>.m,&nbsp;<span style="color:#1f377f;">t</span>.rs)); }</pre> </p> <p> You've already seen <code>GenReservation</code>, but <code>GenMaitreD</code> is new: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">MaitreD</span>&gt;&nbsp;<span style="color:#74531f;">GenMaitreD</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;Create&nbsp;a&nbsp;table&nbsp;for&nbsp;each&nbsp;reservation,&nbsp;to&nbsp;ensure&nbsp;that&nbsp;all</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;reservations&nbsp;can&nbsp;be&nbsp;allotted&nbsp;a&nbsp;table.</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">tables</span>&nbsp;=&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Standard</span>(<span style="color:#1f377f;">r</span>.Quantity)); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;seatingDuration&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Choose</span>(1,&nbsp;6) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">MaitreD</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(18), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(21), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(seatingDuration), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">tables</span>); }</pre> </p> <p> The only difference from before is that the new <code>MaitreD</code> object is now initialised from within a generator expression. The duration is randomly picked from the range of one to six hours (those numbers are my arbitrary choices). </p> <p> Notice that it's possible to base one generator on values randomly generated by another generator. Here, <code>reservations</code> are randomly produced by <code>GenReservation</code> and merged to a tuple with <code>SelectMany</code>, as you can see above. </p> <p> This in itself didn't impact the SUT, but set up the code for my next move, which was to generate <em>more</em> tables than reservations, so that there'd be some free tables left after the schedule allocation. I first added a more complex table generator: </p> <p> <pre><span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;</span><span style="color:gray;">summary</span><span style="color:gray;">&gt;</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;Generate&nbsp;a&nbsp;table&nbsp;configuration&nbsp;that&nbsp;can&nbsp;at&nbsp;minimum&nbsp;accomodate&nbsp;all</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;reservations.</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;/</span><span style="color:gray;">summary</span><span style="color:gray;">&gt;</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;</span><span style="color:gray;">param</span><span style="color:gray;">&nbsp;name</span><span style="color:gray;">=</span><span style="color:gray;">&quot;</span><span style="color:#1f377f;">reservations</span><span style="color:gray;">&quot;</span><span style="color:gray;">&gt;</span><span style="color:green;">The&nbsp;reservations&nbsp;to&nbsp;accommodate</span><span style="color:gray;">&lt;/</span><span style="color:gray;">param</span><span style="color:gray;">&gt;</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;</span><span style="color:gray;">returns</span><span style="color:gray;">&gt;</span><span style="color:green;">A&nbsp;generator&nbsp;of&nbsp;valid&nbsp;table&nbsp;configurations.</span><span style="color:gray;">&lt;/</span><span style="color:gray;">returns</span><span style="color:gray;">&gt;</span> <span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&nbsp;<span style="color:#74531f;">GenTables</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;Create&nbsp;a&nbsp;table&nbsp;for&nbsp;each&nbsp;reservation,&nbsp;to&nbsp;ensure&nbsp;that&nbsp;all</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:green;">//&nbsp;reservations&nbsp;can&nbsp;be&nbsp;allotted&nbsp;a&nbsp;table.</span> &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">tables</span>&nbsp;=&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Standard</span>(<span style="color:#1f377f;">r</span>.Quantity)); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;moreTables&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Choose</span>(1,&nbsp;12).<span style="color:#74531f;">Select</span>(<span style="color:#2b91af;">Table</span>.<span style="color:#74531f;">Standard</span>).<span style="color:#74531f;">ArrayOf</span>() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;allTables&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Shuffle</span>(<span style="color:#1f377f;">tables</span>.<span style="color:#74531f;">Concat</span>(moreTables)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;allTables.<span style="color:#74531f;">AsEnumerable</span>(); }</pre> </p> <p> This function first creates standard tables that exactly accommodate each reservation. It then generates an array of <code>moreTables</code>, each fitting between one and twelve people. It then mixes those tables together with the ones that fit a reservation and returns the sequence. Since <code>moreTables</code> can be empty, it's possible that the entire sequence of tables only just accommodates the <code>reservations</code>. </p> <p> I then modified <code>GenMaitreD</code> to use <code>GenTables</code>: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">MaitreD</span>&gt;&nbsp;<span style="color:#74531f;">GenMaitreD</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;seatingDuration&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Choose</span>(1,&nbsp;6) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;tables&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#74531f;">GenTables</span>(<span style="color:#1f377f;">reservations</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">MaitreD</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(18), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(21), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromHours</span>(seatingDuration), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tables); }</pre> </p> <p> This provoked a change in the SUT: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;r&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#1f377f;">reservations</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">group</span>&nbsp;r&nbsp;<span style="color:blue;">by</span>&nbsp;r.At&nbsp;<span style="color:blue;">into</span>&nbsp;g &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">orderby</span>&nbsp;g.Key &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:#74531f;">Allocate</span>(g).<span style="color:#74531f;">At</span>(g.Key); }</pre> </p> <p> The <code>Schedule</code> method now calls a private helper method called <code>Allocate</code>. This method already existed, since it supports the algorithm used to decide whether or not to accept a reservation request. </p> <h3 id="79e43322721b45a390c68caeaa1a3dcf"> Rinse and repeat <a href="#79e43322721b45a390c68caeaa1a3dcf" title="permalink">#</a> </h3> <p> I hope that a pattern starts to emerge. I kept adding more and more randomisation to the data generators, while I also added more and more assertions to the property. Here's what it looked like after a few more iterations: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:blue;">void</span>&nbsp;<span style="color:#74531f;">ScheduleImp</span>(<span style="color:#2b91af;">MaitreD</span>&nbsp;<span style="color:#1f377f;">sut</span>,&nbsp;<span style="color:#2b91af;">Reservation</span>[]&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">actual</span>&nbsp;=&nbsp;<span style="color:#1f377f;">sut</span>.<span style="color:#74531f;">Schedule</span>(<span style="color:#1f377f;">reservations</span>); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">r</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">r</span>.At).<span style="color:#74531f;">Distinct</span>().<span style="color:#74531f;">Count</span>(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Count</span>()); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">Equal</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">o</span>.At).<span style="color:#74531f;">OrderBy</span>(<span style="color:#1f377f;">d</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">d</span>), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>.<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">o</span>.At)); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">All</span>(<span style="color:#1f377f;">actual</span>,&nbsp;<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#74531f;">AssertTables</span>(<span style="color:#1f377f;">sut</span>.Tables,&nbsp;<span style="color:#1f377f;">o</span>.Value)); &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2b91af;">Assert</span>.<span style="color:#74531f;">All</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">actual</span>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">o</span>&nbsp;=&gt;&nbsp;<span style="color:#74531f;">AssertRelevance</span>(<span style="color:#1f377f;">reservations</span>,&nbsp;<span style="color:#1f377f;">sut</span>.SeatingDuration,&nbsp;<span style="color:#1f377f;">o</span>)); }</pre> </p> <p> While <code>AssertTables</code> didn't change further, I added another helper assertion called <code>AssertRelevance</code>. I'm not going to show it here, but it checks that each occurrence only contains reservations that overlaps that point in time, give or take the <code>SeatingDuration</code>. </p> <p> I also made the reservation generator more sophisticated. If you consider the one defined above, one flaw is that it generates reservations at random dates. The chance that it'll generate two reservations that are actually adjacent in time is minimal. To counter this problem, I added a function that would return a generator of adjacent reservations: </p> <p> <pre><span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;</span><span style="color:gray;">summary</span><span style="color:gray;">&gt;</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;Generate&nbsp;an&nbsp;adjacant&nbsp;reservation&nbsp;with&nbsp;a&nbsp;25%&nbsp;chance.</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;/</span><span style="color:gray;">summary</span><span style="color:gray;">&gt;</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;</span><span style="color:gray;">param</span><span style="color:gray;">&nbsp;name</span><span style="color:gray;">=</span><span style="color:gray;">&quot;</span><span style="color:#1f377f;">reservation</span><span style="color:gray;">&quot;</span><span style="color:gray;">&gt;</span><span style="color:green;">The&nbsp;candidate&nbsp;reservation</span><span style="color:gray;">&lt;/</span><span style="color:gray;">param</span><span style="color:gray;">&gt;</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;</span><span style="color:gray;">returns</span><span style="color:gray;">&gt;</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;A&nbsp;generator&nbsp;of&nbsp;an&nbsp;array&nbsp;of&nbsp;reservations.&nbsp;The&nbsp;generated&nbsp;array&nbsp;is</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;either&nbsp;a&nbsp;singleton&nbsp;or&nbsp;a&nbsp;pair.&nbsp;In&nbsp;75%&nbsp;of&nbsp;the&nbsp;cases,&nbsp;the&nbsp;input</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;</span><span style="color:gray;">paramref</span><span style="color:gray;">&nbsp;name</span><span style="color:gray;">=</span><span style="color:gray;">&quot;</span><span style="color:#1f377f;">reservation</span><span style="color:gray;">&quot;</span><span style="color:gray;">&nbsp;/&gt;</span><span style="color:green;">&nbsp;is&nbsp;returned&nbsp;as&nbsp;a&nbsp;singleton&nbsp;array.</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;In&nbsp;25%&nbsp;of&nbsp;the&nbsp;cases,&nbsp;the&nbsp;array&nbsp;contains&nbsp;two&nbsp;reservations:&nbsp;the&nbsp;input</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;reservation&nbsp;as&nbsp;well&nbsp;as&nbsp;another&nbsp;reservation&nbsp;adjacent&nbsp;to&nbsp;it.</span> <span style="color:gray;">///</span><span style="color:green;">&nbsp;</span><span style="color:gray;">&lt;/</span><span style="color:gray;">returns</span><span style="color:gray;">&gt;</span> <span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">Reservation</span>[]&gt;&nbsp;<span style="color:#74531f;">GenAdjacentReservations</span>(<span style="color:#2b91af;">Reservation</span>&nbsp;<span style="color:#1f377f;">reservation</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;adjacent&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#74531f;">GenReservationAdjacentTo</span>(<span style="color:#1f377f;">reservation</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;useAdjacent&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Frequency</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">WeightAndValue</span>&lt;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:blue;">bool</span>&gt;&gt;(3,&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Constant</span>(<span style="color:blue;">false</span>)), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">WeightAndValue</span>&lt;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:blue;">bool</span>&gt;&gt;(1,&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Constant</span>(<span style="color:blue;">true</span>))) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;rs&nbsp;=&nbsp;useAdjacent&nbsp;? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>[]&nbsp;{&nbsp;<span style="color:#1f377f;">reservation</span>,&nbsp;adjacent&nbsp;}&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">new</span>[]&nbsp;{&nbsp;<span style="color:#1f377f;">reservation</span>&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;rs; } <span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#74531f;">GenReservationAdjacentTo</span>(<span style="color:#2b91af;">Reservation</span>&nbsp;<span style="color:#1f377f;">reservation</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;minutes&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Choose</span>(-6&nbsp;*&nbsp;4,&nbsp;6&nbsp;*&nbsp;4)&nbsp;<span style="color:green;">//&nbsp;4:&nbsp;quarters/h</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;r&nbsp;<span style="color:blue;">in</span>&nbsp;GenReservation &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;r.<span style="color:#74531f;">WithDate</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">reservation</span>.At&nbsp;<span style="color:#74531f;">+</span>&nbsp;<span style="color:#2b91af;">TimeSpan</span>.<span style="color:#74531f;">FromMinutes</span>(minutes)); }</pre> </p> <p> Now that I look at it again, I wonder whether I could have expressed this in a simpler way... It gets the job done, though. </p> <p> I then defined a generator that would either create entirely random reservations, or some with some adjacent ones mixed in: </p> <p> <pre><span style="color:blue;">private</span>&nbsp;<span style="color:blue;">static</span>&nbsp;<span style="color:#2b91af;">Gen</span>&lt;<span style="color:#2b91af;">Reservation</span>[]&gt;&nbsp;GenReservations { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">get</span> &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">normalArrayGen</span>&nbsp;=&nbsp;GenReservation.<span style="color:#74531f;">ArrayOf</span>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">var</span>&nbsp;<span style="color:#1f377f;">adjacentReservationsGen</span>&nbsp;=&nbsp;GenReservation.<span style="color:#74531f;">ArrayOf</span>() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="color:#74531f;">SelectMany</span>(<span style="color:#1f377f;">rs</span>&nbsp;=&gt;&nbsp;<span style="color:#2b91af;">Gen</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="color:#74531f;">Sequence</span>(<span style="color:#1f377f;">rs</span>.<span style="color:#74531f;">Select</span>(<span style="color:#74531f;">GenAdjacentReservations</span>)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="color:#74531f;">SelectMany</span>(<span style="color:#1f377f;">rss</span>&nbsp;=&gt;&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">Shuffle</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">rss</span>.<span style="color:#74531f;">SelectMany</span>(<span style="color:#1f377f;">rs</span>&nbsp;=&gt;&nbsp;<span style="color:#1f377f;">rs</span>)))); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:#2b91af;">Gen</span>.<span style="color:#74531f;">OneOf</span>(<span style="color:#1f377f;">normalArrayGen</span>,&nbsp;<span style="color:#1f377f;">adjacentReservationsGen</span>); &nbsp;&nbsp;&nbsp;&nbsp;} }</pre> </p> <p> I changed the property to use this generator instead: </p> <p> <pre>[<span style="color:#2b91af;">Property</span>] <span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">Property</span>&nbsp;<span style="color:#74531f;">Schedule</span>() { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span>&nbsp;<span style="color:#2b91af;">Prop</span>.<span style="color:#74531f;">ForAll</span>( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GenReservations &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="color:#74531f;">SelectMany</span>(<span style="color:#1f377f;">rs</span>&nbsp;=&gt;&nbsp;<span style="color:#74531f;">GenMaitreD</span>(<span style="color:#1f377f;">rs</span>).<span style="color:#74531f;">Select</span>(<span style="color:#1f377f;">m</span>&nbsp;=&gt;&nbsp;(<span style="color:#1f377f;">m</span>,&nbsp;<span style="color:#1f377f;">rs</span>))) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<span style="color:#74531f;">ToArbitrary</span>(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#1f377f;">t</span>&nbsp;=&gt;&nbsp;<span style="color:#74531f;">ScheduleImp</span>(<span style="color:#1f377f;">t</span>.m,&nbsp;<span style="color:#1f377f;">t</span>.rs)); }</pre> </p> <p> I could have kept at it longer, but this turned out to be good enough to bring about the change in the SUT that I was looking for. </p> <h3 id="f34220b7400d464c9fce7c2b65454971"> Implementation <a href="#f34220b7400d464c9fce7c2b65454971" title="permalink">#</a> </h3> <p> These incremental changes iteratively brought me closer and closer to an implementation that I think has the correct behaviour: </p> <p> <pre><span style="color:blue;">public</span>&nbsp;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Occurrence</span>&lt;<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Table</span>&gt;&gt;&gt;&nbsp;<span style="color:#74531f;">Schedule</span>(<span style="color:#2b91af;">IEnumerable</span>&lt;<span style="color:#2b91af;">Reservation</span>&gt;&nbsp;<span style="color:#1f377f;">reservations</span>) { &nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#8f08c4;">return</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">from</span>&nbsp;r&nbsp;<span style="color:blue;">in</span>&nbsp;<span style="color:#1f377f;">reservations</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">group</span>&nbsp;r&nbsp;<span style="color:blue;">by</span>&nbsp;r.At&nbsp;<span style="color:blue;">into</span>&nbsp;g &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">orderby</span>&nbsp;g.Key &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;seating&nbsp;=&nbsp;<span style="color:blue;">new</span>&nbsp;<span style="color:#2b91af;">Seating</span>(SeatingDuration,&nbsp;g.Key) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">let</span>&nbsp;overlapping&nbsp;=&nbsp;<span style="color:#1f377f;">reservations</span>.<span style="color:#74531f;">Where</span>(seating.<span style="color:#74531f;">Overlaps</span>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:blue;">select</span>&nbsp;<span style="color:#74531f;">Allocate</span>(overlapping).<span style="color:#74531f;">At</span>(g.Key); }</pre> </p> <p> Contrary to my initial expectations, I managed to keep the implementation to a single query expression all the way through. </p> <h3 id="c64408017700494a808fae9388341e87"> Conclusion <a href="#c64408017700494a808fae9388341e87" title="permalink">#</a> </h3> <p> This was a problem that I was stuck on for a couple of days. I could describe the properties I wanted the function to have, but I had a hard time coming up with a good set of examples for unit tests. </p> <p> You may think that using property-based testing looks even more complicated, and I admit that it's far from trivial. The problem itself, however, isn't easy, and while the property-based approach may look daunting, it turned an intractable problem into a manageable one. That's a win in my book. </p> <p> It's also worth noting that this would all have looked more elegant in F#. There's an object-oriented tax to be paid when using FsCheck from C#. </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/2021/02/15/when-properties-are-easier-than-examples Accountability and free speech https://blog.ploeh.dk/2021/02/09/accountability-and-free-speech/ Tue, 09 Feb 2021 07:53:00 UTC <div id="post"> <p> <em>A most likely naive suggestion.</em> </p> <p> A few years ago, my mother (born 1940) went to Paris on vacation with her older sister. She was a little concerned if she'd be able to navigate the <a href="https://en.wikipedia.org/wiki/Paris_M%C3%A9tro">Métro</a>, so she asked me to print out all sorts of maps in advance. I wasn't keen on another encounter with my nemesis, the printer, so I instead showed her how she could use Google Maps to get on-demand routes. Google Maps now include timetables and line information for many metropolitan subway lines around the world. I've successfully used it to find my way around London, Paris, New York, Tokyo, Sydney, and Melbourne. </p> <p> It even works in my backwater home-town: </p> <p> <img src="/content/binary/cph-metro-map.png" alt="Snapshot of Copenhagen Metro route generated by Google Maps."> </p> <p> It's rapidly turning into indispensable digital infrastructure, and that's beginning to trouble me. </p> <p> You can still get paper maps of the various rapid transit systems around the world, but for how long? </p> <h3 id="e5296cbd33f04db3b79890c09d8e3146"> Digital infrastructure <a href="#e5296cbd33f04db3b79890c09d8e3146" title="permalink">#</a> </h3> <p> If you're old enough, you may remember <a href="https://en.wikipedia.org/wiki/Telephone_directory">phone books</a>. In the days of land lines and analogue phones, you'd look up a number and then dial it. As the internet became increasingly ubiquitous, phone directories went online as well. Paper phone books were seen as waste, and ultimately disappeared from everyday life. </p> <p> You can think of paper phone books as a piece of infrastructure that's now gone. I don't miss them, but it's worth reflecting on what impact their disappearing has. Today, if I need to find a phone number, Google is often the place I go. The physical infrastructure is gone, replaced by a digital infrastructure. </p> <p> Google, in particular, now provides important infrastructure for modern society. Not only web search, but also maps, video sharing, translation, emails, and much more. </p> <p> Other companies offer other services that verge on being infrastructure. Facebook is more than just updates to friends and families. Many organisations, including schools and universities, coordinate activities via Facebook, and the political discourse increasingly happens there and on Twitter. </p> <p> We've come to rely on these 'free' services to a degree that resembles our reliance on physical infrastructure like the power grid, running water, roads, telephones, etcetera. </p> <h3 id="bf364e0f0ca84fbbb0536b462743993b"> TANSTAAFL <a href="#bf364e0f0ca84fbbb0536b462743993b" title="permalink">#</a> </h3> <p> <a href="https://en.wikipedia.org/wiki/Robert_A._Heinlein">Robert A. Heinlein</a> coined the phrase <em>There ain't no such thing as a free lunch</em> (TANSTAAFL) in his excellent book <a href="https://amzn.to/3pWi7aM">The Moon is a Harsh Mistress</a>. Indeed, the digital infrastructure isn't free. </p> <p> Recent events have magnified some of the cost we're paying. In January, Facebook and Twitter suspended the then-president of the United States from the platforms. I've little sympathy for Donald Trump, who strikes me as an uncouth narcissist, but since I'm a Danish citizen living in Denmark, I don't think that I ought to have much of an opinion about American politics. </p> <p> I do think, on the other hand, that the suspension sets an uncomfortable precedent. </p> <p> Should we let a handful of tech billionaires control essential infrastructure? This time, the victim was someone half the world was glad to see go, but who's next? Might these companies suspend the accounts of politicians who work against them? </p> <p> Never in the history of the world has decision power over so many people been so concentrated. I'll remind my readers that Facebook, Twitter, Google, etcetera are in worldwide use. The decisions of a handful of majority shareholders can now affect billions of people. </p> <p> If you're suspended from one of these platforms, you may lose your ability to participate in school activities, or from finding your way through a foreign city, or from taking part of the democratic discussion. </p> <h3 id="23e71b25789c465e9530a51a1cceac21"> The case for regulation <a href="#23e71b25789c465e9530a51a1cceac21" title="permalink">#</a> </h3> <p> In this article, I mainly want to focus on the free-speech issue related mostly to Facebook and Twitter. These companies make money from ads. The longer you stay on the platform, the more ads they can show you, and they've discovered that nothing pulls you in like anger. These incentives are incredibly counter-productive for society. </p> <p> Users are implicitly encouraged to create or spread anger, yet few are held accountable. One reason is that you can easily create new accounts without disclosing your real-world identity. This makes it difficult to hold users accountable for their utterances. </p> <p> Instead of clear rules, users are suspended for inexplicable and arbitrary reasons. It seems that these are mostly the verdicts of algorithms, but as we've seen in the case of Donald Trump, it can also be the result of an undemocratic, but political decision. </p> <p> Everyone can lose their opportunities for self-expression for arbitrary reasons. This is a free-speech issue. </p> <p> Yes, free speech. </p> <p> I'm well aware that Facebook and Twitter are private companies, and no-one has any <em>right</em> to an account on those platforms. That's why I started this essay by discussing how these services are turning into infrastructure. </p> <p> More than a century ago, the telephone was new technology operated by private companies. I know the Danish history best, but it serves well as an example. <a href="https://da.wikipedia.org/wiki/KTAS">KTAS</a>, one of the world's first telephone companies, was a private company. Via mergers and acquisitions, it still is, but as it grew and became the backbone of the country's electronic communications network, the government introduced legislation. For decades, it and its sister companies were regional monopolies. </p> <p> The government allowed the monopoly in exchange for various obligations. Even when the monopoly ended in 1996, the original monopoly companies inherited these legal obligations. For instance, every Danish citizen has the right to get a land-line installed, even if that installation by itself is a commercial loss for the company. This could be the case on certain remote islands or other rural areas. The Danish state compensates the telephone operator for this potential loss. </p> <p> Many other utility companies run in a similar fashion. Some are semi-public, some are private, but common to water, electricity, garbage disposal, heating, and other operators is that they are regulated by government. </p> <p> When a utility becomes important to the functioning of society, a sensible government steps in to regulate it to ensure the further smooth functioning of society. </p> <p> I think that the services offered by Google, Facebook, and Twitter are fast approaching a level of significance that ought to trigger government regulation. </p> <p> I don't say that lightly. I'm actually quite libertarian in my views, but I'm no anarcho-libertarian. I do acknowledge that a state offers essential services such as protection of property rights, a judicial system, and so on. </p> <h3 id="f4c78c79e1eb46d2941611d443f89ea1"> Accountability <a href="#f4c78c79e1eb46d2941611d443f89ea1" title="permalink">#</a> </h3> <p> How should we regulate social media? I think we should start by exchanging accountability for the right to post. </p> <p> Let's take another step back for a moment. For generations, it's been possible to send a letter to the editor of a regular newspaper. If the editor deems it worthy for publication, it'll be printed in the next issue. You don't have any right to get your letter published; this happens at the discretion of the editor. </p> <p> Why does it work that way? It works that way because the editor is accountable for what's printed in the paper. Ultimately, he or she can go to jail for what's printed. </p> <p> Freedom of speech is more complicated than it looks at first glance. For instance, censorship in Denmark was abolished with the 1849 constitution. This doesn't mean that you can freely say whatever you'd like; it only means that government has no right to <em>prevent</em> you from saying or writing something. You can still be prosecuted after the fact if you say or write something libellous, or if you incite violence, or if you disclose secrets that you've agreed to keep, etcetera. </p> <p> This is accountability. It works when the person making the utterance is known and within reach of the law. </p> <p> Notice, particularly, that an editor-in-chief is accountable for a newspaper's contents. Why isn't Facebook or Twitter accountable for content? </p> <p> These companies have managed to spin a story that they're <em>platforms</em> rather than publishers. This argument might have had some legs ten years ago. When I started using Twitter in 2009, the algorithm was easy to understand: My feed showed the tweets from the accounts that I followed, in the order that they were published. This was easy to understand, and Twitter didn't, as far as I could tell, edit the feed. Since no editing took place, I find the platform argument applicable. </p> <p> Later, the social networks began editing the feeds. No humans were directly involved, but today, some posts are amplified while others get little attention. Since this is done by 'algorithms' rather than editors, the companies have managed to convince lawmakers that they're still only platforms. Let's be real, though. Apparently, the public needs a programmer to say the following, and I'm a programmer. </p> <p> Programmers, employees of those companies, wrote the algorithms. They experimented and tweaked those algorithms to maximise 'engagement'. Humans are continually involved in this process. Editing takes place. </p> <p> I think it's time to stop treating social media networks as platforms, and start treating them as publishers. </p> <h3 id="ab23d2f377db45bf99970479238dd982"> Practicality <a href="#ab23d2f377db45bf99970479238dd982" title="permalink">#</a> </h3> <p> Facebook and Twitter will protest that it's practically impossible for them to 'edit' what happens on the networks. I find this argument unconvincing, since editing already takes place. </p> <p> I'd like to suggest a partial way out, though. This brings us back to regulation. </p> <p> I think that each country or jurisdiction should make it possible for users to opt in to being accountable. Users should be able to verify their accounts as real, legal persons. If they do that, their activity on the platform should be governed by the jurisdiction in which they reside, instead of by the arbitrary and ill-defined 'community guidelines' offered by the networks. You'd be accountable for your utterances according to local law where you live. The advantage, though, is that this accountability buys you the <em>right</em> to be present on the platform. You can be sued for your posts, but you can't be kicked off. </p> <p> I'm aware that not everyone lives in a benign welfare state such as Denmark. This is why I suggest this as an option. Even if you live in a state that regulates social media as outlined above, the option to stay anonymous should remain. This is how it already works, and I imagine that it should continue to work like that for this group of users. The cost of staying anonymous, though, is that you submit to the arbitrary and despotic rules of those networks. For many people, including minorities and citizens of oppressive states, this is likely to remain a better trade-off. </p> <h3 id="84eccfad9fe649c3b38d9e4d6ddb2698"> Problems <a href="#84eccfad9fe649c3b38d9e4d6ddb2698" title="permalink">#</a> </h3> <p> This suggestion is in no way perfect. I can already identify one problem with it. </p> <p> A country could grant its citizens the right to conduct infowar on an adversary; think troll armies and the like. If these citizens are verified and 'accountable' to their local government, but this government encourages rather than punishes incitement to violence in a foreign country, then how do we prevent that? </p> <p> I have a few half-baked ideas, but I'd rather leave the problem here in the hope that it might inspire other people to start thinking about it, too. </p> <h3 id="f25f8486eed54d3d89fd607ef41e3ac7"> Conclusion <a href="#f25f8486eed54d3d89fd607ef41e3ac7" title="permalink">#</a> </h3> <p> This is a post that I've waited for a long time for someone else to write. If someone already did, I'm not aware of it. I can think of three reasons: <ul> <li>It's a really stupid idea.</li> <li>It's a common idea, but no-one talks about it because of <a href="https://en.wikipedia.org/wiki/Pluralistic_ignorance">pluralistic ignorance</a>.</li> <li>It's an original idea that no-one else have had.</li> </ul> I don't believe much in the last option, and I'm afraid that the first is the most likely. I've no desire to look stupid, but on the other hand, I can't help keep thinking about this. </p> <p> The idea is, in short, to make it optional for users to 'buy' the right to stay on a social network for the price of being held legally accountable. This requires some national as well as international regulation of the digital infrastructure. </p> <p> Could it work? I don't know, but isn't it worth discussing? </p> </div> <div id="comments"> <hr> <h2 id="comments-header"> Comments </h2> <div class="comment" id="c9bf9249f05342dcae02d9581b7e7e5c"> <div class="comment-author"><a href="https://jeremiahflaga.github.io/">Jboy Flaga</a></div> <div class="comment-content"> <p> Hi Mark, I would just like to say that I like the idea :) </p> <p> Thank you for writing this. </p> </div> <div class="comment-date">2021-02-18 13:34 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/2021/02/09/accountability-and-free-speech