﻿<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Habitable Code]]></title><description><![CDATA[How to write software that's easier to maintain]]></description><link>https://habitablecode.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!e2Jp!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc186f12a-58c9-4f5e-a7f0-5a9c284e6e9b_512x512.png</url><title>Habitable Code</title><link>https://habitablecode.substack.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 15 Jun 2026 17:53:51 GMT</lastBuildDate><atom:link href="https://habitablecode.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Kevin Rutherford]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[habitablecode@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[habitablecode@substack.com]]></itunes:email><itunes:name><![CDATA[kevin rutherford]]></itunes:name></itunes:owner><itunes:author><![CDATA[kevin rutherford]]></itunes:author><googleplay:owner><![CDATA[habitablecode@substack.com]]></googleplay:owner><googleplay:email><![CDATA[habitablecode@substack.com]]></googleplay:email><googleplay:author><![CDATA[kevin rutherford]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Chasing an assumption]]></title><description><![CDATA[Exploring a few cycles of outside-in development]]></description><link>https://habitablecode.substack.com/p/chasing-an-assumption</link><guid isPermaLink="false">https://habitablecode.substack.com/p/chasing-an-assumption</guid><dc:creator><![CDATA[kevin rutherford]]></dc:creator><pubDate>Mon, 26 Aug 2024 07:23:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!e2Jp!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc186f12a-58c9-4f5e-a7f0-5a9c284e6e9b_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello again! Sorry it&#8217;s been a while since I last wrote. This may, or may not, be the start of more regular posts. Let&#8217;s see&#8230;</p><p>Yesterday I finally got a tricky bit of code working. It&#8217;s a spike, helping me to figure out how a complicated distributed algorithm will all hang together.</p><p>And when I say &#8220;working&#8221;, I mean that it worked on my laptop :-). I tried deploying it to my production server and it didn&#8217;t work there. But that&#8217;s because part of it makes a post to <code>http://localhost:44002</code>, which doesn&#8217;t exist in production. Not a surprise.</p><p>So my job for the next few cycles will be to expand on this code, removing the assumption about where it runs. Notice that I said &#8220;expand&#8221; rather than &#8220;fix&#8221;. The code isn&#8217;t broken. It definitely works, but only under certain circumstances. It is tested, but it includes an assumption. So I consider the job of the next few cycles to fall into a bit of a grey area between feature writing and refactoring, and here&#8217;s what I plan to do&#8230;</p><p>My domain model &#8212; and my architectural assumptions &#8212; tell me that I should be getting that URL from user profile data held elsewhere in my network. And in fact there should be a list of such URLs, instead of just one as in the current spike. That is, I&#8217;ll need to replace that hardcoded string <code>&#8220;http://localhost:44002&#8220;</code> with an API call that should return an array of profiles, each of which includes an attribute whose value is the appropriate URL. That API call could also fail. So I&#8217;m planning to replace a string value with a call to an endpoint that will return some sort of Promise of either a list of profiles or one of several kinds of error. Oh, and that endpoint doesn&#8217;t yet exist.</p><p>I&#8217;ll outline my plan below, but before continuing, maybe take a moment to think about how you would approach this <em>while keeping the code working</em>&#8230;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>I could start by writing the new endpoint. After all, I &#8220;know&#8221; what its signature should be. But then it will sit around, not being called, while I reshape the current code to cope with errors, arrays, profiles, and promises. The client-side code knows about none of those things currently, and they each represent a little risk to the application&#8217;s current fragile working state.</p><p>So instead I plan to do the opposite. I&#8217;m going to apply the following refactorings, possibly in this order, possibly not:</p><ol><li><p>Wrap the hardcoded URL in a function call. This gives it a name, which will help me to remember why it exists. And it creates a &#8220;seam&#8221;, hiding some of the details of what happens next.</p></li><li><p>Refactor the client to have an array containing the single hardcoded URL. This will force the downstream code to deal with multiple URLs, but the code will be easy to keep working.</p></li><li><p>Wrap the hardcoded URL in a user profile object, so that my client-side code knows how to unpack such a thing, and so that I know what it needs to look like.</p></li><li><p>Wrap the hardcoded data in a Promise and test for error conditions. I don&#8217;t really know yet what that looks like, and I expect I&#8217;ll have to revisit this once the API call is being made for real.</p></li></ol><p>Each of these refactorings should result in code that still works, and can be committed to main without changing existing behaviour. Now, finally, I can write a simple API endpoint that just returns exactly the same hardcoded data (an array containing a single made-up profile whose URL is still the hardcoded localhost value), and call it from the client. At this point I&#8217;m making the network call, and the code dealing with Promises and errors is being exercised. If all goes to plan, this is still releasable with no change to current functionality.</p><p>Something very important has now happened, though: I&#8217;ve pushed the hardcoded value back towards where it will eventually originate &#8212; <em>without changing any existing, tested functionality</em>. The hardcoding is now inside the server API endpoint, and no longer in the client. The client has been generalised, and should in future just do what the server tells it to do.</p><p>This is the essence of outside-in development, and the foundation of the <a href="https://mikadomethod.info">Mikado method</a> too. Each cycle pushes an assumption towards an edge of the application until it disappears. Each cycle can be committed to main and deployed. And all the while, the entire application keeps working.</p><div><hr></div><p>Does your team work this way? If not, and you would like to learn how to apply outside-in development in your work, message me and let&#8217;s chat about whether some of my training or coaching could work for you.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/chasing-an-assumption?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! If you liked this post, please share it with someone who might also like it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/chasing-an-assumption?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/chasing-an-assumption?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p><br></p><p></p>]]></content:encoded></item><item><title><![CDATA[Javascript Checkout -- Pausing for breath]]></title><description><![CDATA[Please help me by answering a question about these articles]]></description><link>https://habitablecode.substack.com/p/javascript-checkout-pausing-for-breath</link><guid isPermaLink="false">https://habitablecode.substack.com/p/javascript-checkout-pausing-for-breath</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 14 Oct 2022 07:00:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Perc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is part of a series in which I&#8217;m doing a well-known code kata in the &#8220;TDD as if you meant it&#8221; style. I&#8217;m also strictly following the 4 rules of simple design and looking for opportunities to use implicit coupling to drive refactoring under the Once And Only Once rule. (If you missed the start of this series you can catch up with part 1 <a href="https://habitablecode.substack.com/p/javascript-checkout-1">here</a>.)</p><p>I&#8217;m going to take a break for the next couple of weeks.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Perc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Perc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Perc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Perc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Perc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Perc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg" width="1456" height="968" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:968,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:328252,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Perc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Perc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Perc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Perc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fae6f5db2-2055-4134-a66b-bc7821d171c4_2048x1362.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://flic.kr/p/YmqMd5">John Brinn</a></figcaption></figure></div><p>And before I do that, I want to ask you a question: Is this kata series useful enough to continue, or would you prefer me to revert to the more varied content I created previously?</p><p>On the one hand, these articles give us a chance to dive deep into writing code via TDD and refactoring. By taking the time to unpick even the tiniest moments, I&#8217;m finding a surprising amount of design thinking to discuss. Admittedly the code isn&#8217;t changing particularly quickly across these articles &#8212; but that&#8217;s because each week I&#8217;m expanding a few seconds&#8217; thought into a thousand words of analysis and exploration. And in the course of that expansion I&#8217;m discovering heuristics that even I didn&#8217;t realise were in play. You can find a list of many of them at the end of this article, as a kind of recap of what I&#8217;ve learned from the 7 articles so far.</p><p>But on the other hand, this one very simple example is taking a loooooong time to go anywhere, and it shows no signs of finishing any time soon. So by focusing so deeply on such a simple example we&#8217;re losing the opportunity to explore more widely.  I have ideas for other katas too &#8212; for example following the lead of Kent Beck&#8217;s book <em>Test-driven Development by Example</em> by TDD-ing a unit testing tool, or doing something in a functional language, or trying the auction sniper kata from Freeman and Pryce&#8217;s <em>Growing Object-Orient Software Guided by Tests</em>. There are also more general discussions to be tackled, such as continuing to explore specific cases of implicit coupling in more of a &#8220;solution catalogue&#8221; style.</p><p>There is a lot to explore, yet I only have 2 hours per week for writing. So where should I focus?</p><div class="poll-embed" data-attrs="{&quot;id&quot;:13770}" data-component-name="PollToDOM"></div><p>To provide a little more context for your decision, I&#8217;ve collected together below all of the &#8220;<em>Things to try</em>&#8221; sections from this series of articles so far. This list represents a whole bunch of things I tend to do instinctively, without thought, but which have occurred to me consciously because I&#8217;m writing these articles. I hope you find them useful!</p><ol><li><p>Take half an hour to do a (different) kata using the TDDAIYMI style. What did you learn about your usual programming style? Or about how much &#8220;design&#8221; you do without consciously calling it out?</p></li><li><p>Make a list of problems you can see in your own code, and prioritise them according to the 4 Rules.</p></li><li><p>Make sure the names you use in the code reflect the vocabulary you use when talking about that code.</p></li><li><p>Find a place where your code doesn&#8217;t tell the story you and your Customer intend; refactor until it does.</p></li><li><p>When you&#8217;re assessing whether your code tells its story, start at the outside and work inwards only when the outer layers of abstraction communicate extremely well.</p></li><li><p>Next time you have to refactor, consciously cycle around the 4 Rules. In particular each time you change anything, start again with a new review of the names and the story they tell.</p></li><li><p>Take a break after any period of concentrated effort. When you return you&#8217;re likely to see things with fresh eyes.</p></li><li><p>Next time you&#8217;re getting from RED to GREEN jot down as many alternative code changes as you can think of. Which one do you choose to move forward with, and why?</p></li><li><p>Look for opportunities to increase the symmetry and self-similarity in your code. Does this always help with readability?</p></li><li><p>Next time you have a choice between depth-first and breadth-first tree walking, try breadth-first and look out for symmetries appearing sooner.</p></li><li><p>Explore property-based testing: is it appropriate for the code you&#8217;re currently writing?</p></li><li><p>Find a function in your own code that has two parameters of the same type. Try following Fowler&#8217;s mechanical steps for <em>Introduce Parameter Object</em>. How did that feel, compared to using an IDE to accomplish the same thing?</p></li><li><p>Look for places in your own code where you could increase the symmetry. What happens to understandability when you do?</p></li><li><p>Do the names used <em>inside</em> your functions reflect the function&#8217;s internal context, or are they coupled to the names used by the callers?</p></li><li><p>Before you add the next test, make an explicit list of the implicit coupling you can see in the area of code you&#8217;re working on. What should you fix before proceeding?</p></li><li><p>Think about how you decide whether to prioritise new functionality or refactoring. What kinds of coupling do you defer, and why?</p></li></ol><p>I hadn&#8217;t realised there were so many!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Javascript Checkout -- Triangulation 4]]></title><description><![CDATA[Decisions, decisions ...]]></description><link>https://habitablecode.substack.com/p/javascript-checkout-triangulation-4aa</link><guid isPermaLink="false">https://habitablecode.substack.com/p/javascript-checkout-triangulation-4aa</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 07 Oct 2022 07:01:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!DS6O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is part 7 in a series in which I&#8217;m doing a well-known code kata in the &#8220;TDD as if you meant it&#8221; style. I&#8217;m also strictly following the 4 rules of simple design and looking for opportunities to use implicit coupling to drive refactoring under the Once And Only Once rule. (If you missed the start of this series you can catch up with part 1 <a href="https://habitablecode.substack.com/p/javascript-checkout-1">here</a>.)</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe here to see how this worked example plays out and to support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>This is how we left things last time:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DS6O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DS6O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png 424w, https://substackcdn.com/image/fetch/$s_!DS6O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png 848w, https://substackcdn.com/image/fetch/$s_!DS6O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png 1272w, https://substackcdn.com/image/fetch/$s_!DS6O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DS6O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png" width="576" height="378" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:378,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:54202,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DS6O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png 424w, https://substackcdn.com/image/fetch/$s_!DS6O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png 848w, https://substackcdn.com/image/fetch/$s_!DS6O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png 1272w, https://substackcdn.com/image/fetch/$s_!DS6O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F02f55166-249d-4d8a-98cd-53c69dc4b9dd_576x378.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Coming back to this code after a couple of days away, I have the scary feeling that I&#8217;ve let a few problems build up. Before I continue, make a note of which violations of the 4 Rules you can see.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/javascript-checkout-triangulation-4aa/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/javascript-checkout-triangulation-4aa/comments"><span>Leave a comment</span></a></p><p>What I see (in no particular order) are these:</p><ol><li><p><code>totalPriceOf</code> still has two parameters, and the caller can&#8217;t know which order they should be passed.</p></li><li><p>By changing the price list keys to match the product names, I introduced those product names into the code of the function. It shouldn&#8217;t know about them.</p></li><li><p>The code and the test are coupled together by the two assumptions that prices are expressed as integers and product names/keys are expressed as strings. (This is Connascence of Convention, aka Connascence of Meaning; in code smell terms we might call it Primitive Obsession or Open Secret.)</p></li></ol><p>I now have to make a decision: do I address any or all of these, or do I move on to add the next test? This is the kind of decision I &#8212; and all of us &#8212; make numerous times each day, often instinctively and with little or no conscious thought. Sometimes we&#8217;ll rush forward with the next test, sometimes we&#8217;ll fix whichever of those smells we&#8217;re attuned to on that particular day. Does it matter? Is there a &#8220;best&#8221; thing to do here? Or will we always converge on the same design eventually, regardless of which route we take?</p><p>A big part of me wants to move forward with the next test<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. That's because I often like to allow the problem to get a little bigger before I clean up. As this code grows and evolves, the coupling I identified above will grow and evolve too, and often the solution patterns become easier to see when their "surface area" is larger. Or maybe I'm kidding myself here: perhaps I just simply enjoy solving bigger, hairier problems, and so I have a personal incentive to let the coupling get out of hand before tackling it.</p><p>Part of me also thinks that fixing these smells now could be gilding the lily: maybe I don't yet have "enough" code to be worrying about coupling -- after all, it's only 25 lines and I can see all the way across it from end to end. Surely I need more code to make the refactoring worthwhile?</p><p>Running counter to these thoughts, this series of articles is about refactoring, and so I <em>am</em> going to address those smells before moving on. Would I do this in &#8220;real life&#8221;? Let&#8217;s answer that case by case:</p><ol><li><p>I feel that the two parameters to <code>totalPriceOf</code> play different roles in our story, because they change at different times. I can imagine &#8212; although I would need Customer confirmation of this &#8212; using the same price list to cost numerous baskets of items. And in fact the metaphor I unconsciously used in that previous sentence might suggest <em>asking</em> the price list to cost the basket<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. Whichever way I choose to tackle this, I&#8217;m going to be altering the tested API. So I want to do that soon &#8212; partly because the code is small now and so there&#8217;s less to change, and partly so that I get early feedback on whatever design I choose. I&#8217;m going to fix this one now, to maximise my learning and avoid the potentially higher cost of doing it later.</p></li><li><p>In order to eradicate knowledge of the product names from the code I suspect I will have to rewrite the algorithm. And with only the two tests I have currently, that feels like a risky enterprise. So I will leave this smell in the code until I have more tests &#8212; and maybe the addition of those tests will drive out those algorithm changes anyway.</p></li><li><p>In Javascript I don&#8217;t have static types, and so it&#8217;s really not obvious how best to cope with these assumptions about primitives. I guess I could wrap the integers, strings and arrays in objects of specific classes, and doing so would make those types explicit in the caller. Would that be too clunky, making the caller&#8217;s code less elegant and expressive? Well, given that I&#8217;m going to change the tested API anyway, maybe this would be a good thing to fix now too.</p></li></ol><p>So I talked myself into immediately fixing two of the three problems I&#8217;ve identified, and while doing so I realised that there was one more example of Connascence of Convention that I hadn&#8217;t noticed earlier. Making lists turns out to be a valuable exercise yet again!</p><p>Does it seem as if I&#8217;m over-thinking all of this? What I&#8217;m trying to do is to unpick those micro-decisions we all make without much thought. Next time, I promise I&#8217;ll actually do some refactoring &#128522;.</p><h2>Things to try</h2><ul><li><p>Before you add the next test, make an explicit list of the implicit coupling you can see in the area of code you&#8217;re working on. What should you fix before proceeding?</p></li><li><p>Think about how you decide whether to prioritise new functionality or refactoring. What kinds of coupling do you defer, and why?</p></li></ul><p>As always, please leave a comment if you try any of these.</p><h2>And finally&#8230;</h2><p>Just a quick mention that I recently recorded an episode of the <em>Mob Mentality</em> podcast to talk about rhythm and cadence in both ensemble programming and TDD. The podcast is on YouTube: </p><div id="youtube2-6i8Jcvo-4BE" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;6i8Jcvo-4BE&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/6i8Jcvo-4BE?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Interesting metaphor there: &#8220;move forward&#8221;. Is that impatience? It&#8217;s been a couple of weeks since I added a new test, which feels like a long time. But if this exercise were playing out in real time only a couple of minutes would have elapsed.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I also note that I haven&#8217;t used the &#8220;basket&#8221; metaphor before. And in writing this I realise that the array of items is also a primitive, subject to the same Connascence of Convention coupling that I&#8217;ve noticed elsewhere.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Javascript Checkout -- Triangulation 3]]></title><description><![CDATA[In which I consider various conflicts between multiple domains]]></description><link>https://habitablecode.substack.com/p/javascript-checkout-triangulation-47c</link><guid isPermaLink="false">https://habitablecode.substack.com/p/javascript-checkout-triangulation-47c</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Tue, 04 Oct 2022 07:00:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/h_600,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is part 6 in a series in which I&#8217;m doing a well-known code kata in the &#8220;TDD as if you meant it&#8221; style. I&#8217;m also strictly following the 4 rules of simple design and looking for opportunities to use implicit coupling to drive refactoring under the Once And Only Once rule. (If you missed the start of this series you can catch up with part 1 <a href="https://habitablecode.substack.com/p/javascript-checkout-1">here</a>.)</p><p>Last time, I decoupled the code from the prices of A and B.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe here to see how this worked example plays out and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Currently on the branch we have this code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d9MA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d9MA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png 424w, https://substackcdn.com/image/fetch/$s_!d9MA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png 848w, https://substackcdn.com/image/fetch/$s_!d9MA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png 1272w, https://substackcdn.com/image/fetch/$s_!d9MA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d9MA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png" width="579" height="303" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:303,&quot;width&quot;:579,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47878,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!d9MA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png 424w, https://substackcdn.com/image/fetch/$s_!d9MA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png 848w, https://substackcdn.com/image/fetch/$s_!d9MA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png 1272w, https://substackcdn.com/image/fetch/$s_!d9MA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e3c3528-7e79-4b6a-84cb-2a46695b3b4f_579x303.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The tests pass, so I move straight on to readability &#8212; does this code tell the domain&#8217;s story clearly? I&#8217;ve not looked at this code for a couple of days, and so I&#8217;m reviewing it again today with somewhat fresh eyes. What jumps out at me right away is the two length checks on lines 3 and 5: based on what we know of the domain, they surely can&#8217;t stay like that for long (in the &#8220;real world&#8221;, not every shopping cart that has only one item will contain an A, for example). But I&#8217;m shooting for TDD, and right now I don&#8217;t have a test that requires those checks to change. They currently do the job I need them to do, and I know I can rely on future tests to drive out a more realistic algorithm.</p><p>This is an interesting point of tension, particularly for folks who are new to test-driven development. We &#8220;know&#8221; that the current code is an incomplete representation of the &#8220;real world&#8221; domain. But it is also the simplest way to make the current set of tests pass. So the code is in fact a highly faithful model of <em>the domain as defined by the tests</em>. That&#8217;s an important distinction: there are <em>two</em> domains in play at any moment. The current set of tests defines one domain, and we&#8217;re gradually incrementing that to be closer and closer to the &#8220;real world&#8221; domain.</p><p>On another day I could be easily tempted to say that those length checks are so obviously &#8220;wrong&#8221; that I would immediately look for another test or two to allow me to drive them away. That would definitely be a legitimate course of action, and there&#8217;s a lot to discuss in regard to the idea of deferring a few REFACTOR steps. Remind me to come back to that concept in a few weeks? But the purpose of this series is to push hard on refactoring away the coupling as soon as it appears, so let&#8217;s move on to that next.</p><p>(Another interesting point &#8212; at least for me &#8212; is that I wasn&#8217;t expecting to talk about this topic today. I don&#8217;t have a plan for this series of articles, and so I&#8217;m being completely carried along by the current. Whatever I see today is what I put down here. It&#8217;s not quite stream of consciousness, but I&#8217;m finding this level of deep introspection quite fascinating. I hope you&#8217;re enjoying that aspect too&#8230;)</p><p>And so on to rule 3. Does anything in this code violate Once And Only Once? I don&#8217;t think so. And yet there is Connascence of Position, because nothing prevents the caller from passing those three arguments &#8212; <code>items, priceOfA, priceOfB</code> &#8212; in the wrong order. This is exactly the situation I unpicked in <a href="https://habitablecode.substack.com/p/functions-with-multiple-parameters">Functions with Multiple Parameters</a> a couple of weeks back: there is no way to write the caller&#8217;s code such that it is obvious which is the correct parameter order.</p><p>So, following my own advice from that earlier article, I&#8217;m going to replace the pair <code>priceOfA, priceOfB</code> with a containing structure:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LNIK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LNIK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png 424w, https://substackcdn.com/image/fetch/$s_!LNIK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png 848w, https://substackcdn.com/image/fetch/$s_!LNIK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png 1272w, https://substackcdn.com/image/fetch/$s_!LNIK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LNIK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png" width="579" height="378" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/cb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:378,&quot;width&quot;:579,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56031,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LNIK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png 424w, https://substackcdn.com/image/fetch/$s_!LNIK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png 848w, https://substackcdn.com/image/fetch/$s_!LNIK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png 1272w, https://substackcdn.com/image/fetch/$s_!LNIK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb5bc0e6-7c55-43cd-a7c5-a513574f346b_579x378.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The tests pass, so I commit: <code>Replace two parameters with a structure</code>.</p><p>I want to note a couple of things about this step. Firstly, aficionados of code smells might call this Long Parameter List. And in my book<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, our recommended remedy is to use Martin Fowler&#8217;s <em>Introduce Parameter Object</em> refactoring. Here, I have no evidence (yet) that an object is necessary, so a structure will suffice.</p><p>And secondly, this still leaves the function having two parameters. And because Javascript offers no static types in the source code, I still can&#8217;t know in the caller which order is correct. So I&#8217;ve improved the situation a little, but not yet completely eradicated the problem.</p><p>But first, I made a change and so by the rules of these articles I have to go back around the 4 rules of Simple Design. The tests pass (rule 1), but does this code express everything in the best way possible (rule 2)? Well, it seems to me that <code>prices.priceOfA</code> is not only clumsy but also contains duplication. Instead I can use the product name as the key into the lookup table:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aDNM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aDNM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png 424w, https://substackcdn.com/image/fetch/$s_!aDNM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png 848w, https://substackcdn.com/image/fetch/$s_!aDNM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png 1272w, https://substackcdn.com/image/fetch/$s_!aDNM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aDNM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png" width="576" height="378" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/244160fd-3e74-470d-9205-52e1be01d89e_576x378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:378,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53491,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aDNM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png 424w, https://substackcdn.com/image/fetch/$s_!aDNM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png 848w, https://substackcdn.com/image/fetch/$s_!aDNM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png 1272w, https://substackcdn.com/image/fetch/$s_!aDNM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F244160fd-3e74-470d-9205-52e1be01d89e_576x378.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The tests pass, and I&#8217;m happy that this expresses my intention. Commit: <code>Improve relationship between prices and products.</code></p><p>I note that Javascript would allow me to say <code>prices.A</code> at line 4. But <code>prices[&#8216;A&#8217;]</code> expresses my intention better, I feel, because of the symmetry with line 13. If the product name contained spaces, or weren&#8217;t a string, the approach I&#8217;ve used is the only workable one; but even in the simple current case I prefer the approach of expressing the lookup key in the same way everywhere it occurs. I&#8217;ve noted before that self-symmetry is a powerful tool for me: symmetries make the code easier to read (maybe something to do with having less to remember?). Symmetries also offer clues to various kinds of coupling, so I seek them out and highlight them whenever I can. So even though my programming language offers me a more succinct, idiomatic, option I prefer to expose the symmetry and express the domain a little more faithfully.</p><p>And so let&#8217;s look again at how well this code tells the story my Customer told me. I just introduced the name <code>prices</code>, so I re-read all of those changed lines. There&#8217;s something not quite right in the story-telling, and I finally spot what it is. The little structure defined on line 12 doesn&#8217;t just contain prices, so the name is wrong. And looking at line 22 I can now see that <code>priceList</code> would be much better:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Fe9v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Fe9v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png 424w, https://substackcdn.com/image/fetch/$s_!Fe9v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png 848w, https://substackcdn.com/image/fetch/$s_!Fe9v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png 1272w, https://substackcdn.com/image/fetch/$s_!Fe9v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Fe9v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png" width="576" height="378" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/95c47d04-84b3-40af-9512-301a934a43b7_576x378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:378,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:54028,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Fe9v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png 424w, https://substackcdn.com/image/fetch/$s_!Fe9v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png 848w, https://substackcdn.com/image/fetch/$s_!Fe9v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png 1272w, https://substackcdn.com/image/fetch/$s_!Fe9v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F95c47d04-84b3-40af-9512-301a934a43b7_576x378.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>That feels much better. Commit: <code>Express the domain more clearly</code>.</p><p>Two thoughts strike me now, both triggered by making that change. Firstly, that structure obviously isn&#8217;t a &#8220;list&#8221; in the data structure sense. But that is what we tend to call them in the real world. Could that cause confusion? Only if the reader brings along with them expectations of programming style. Because shoot me if I ever include a language type in the name of a local variable or constant. Hungarian notation creates coupling between implementation and intention, so it&#8217;s generally a bad idea. And as with <code>prices.A</code> above,</p><blockquote><p>whenever there&#8217;s a conflict between expressing the domain and writing idiomatic code, the domain should win every time.</p></blockquote><p>Secondly, I chose to change the name in both the code and the test, even though they are strictly independent of each other.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s3PR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s3PR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg 424w, https://substackcdn.com/image/fetch/$s_!s3PR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg 848w, https://substackcdn.com/image/fetch/$s_!s3PR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!s3PR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s3PR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg" width="640" height="480" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:640,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:119740,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!s3PR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg 424w, https://substackcdn.com/image/fetch/$s_!s3PR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg 848w, https://substackcdn.com/image/fetch/$s_!s3PR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!s3PR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7b850c-a720-469f-8747-2eb89e4a6724_640x480.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Colin Smith&nbsp;/&nbsp;Formal Garden, Drumlanrig</figcaption></figure></div><p>But I can&#8217;t think of different names that might work better, so I&#8217;m happy to leave it for now. Something to be mindful of as we proceed, maybe.</p><p>Next time: is it time for the next test, or do those references to product names (lines 4, 6, 12, 13) represent coupling that we want to fix?</p><h2>Things to try</h2><ul><li><p>Find a function in your own code that has two parameters of the same type. Try following Fowler&#8217;s mechanical steps for <em>Introduce Parameter Object</em>. How did that feel, compared to using an IDE to accomplish the same thing?</p></li><li><p>Look for places in your own code where you could increase the symmetry. What happens to understandability when you do?</p></li><li><p>Do the names used <em>inside</em> your functions reflect the function&#8217;s internal context, or are they coupled to the names used by the callers?</p></li></ul><p>As always, if you try anything here please let your fellow readers know how it went by leaving a comment.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/javascript-checkout-triangulation-47c/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/javascript-checkout-triangulation-47c/comments"><span>Leave a comment</span></a></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Wake, Rutherford: <em>Refactoring in Ruby</em>. Addison-Wesley, 2009. ISBN 978-0321545046. On amazon.co.uk: <a href="https://amzn.to/3RKPpHT">https://amzn.to/3RKPpHT</a> (affiliate link).</p></div></div>]]></content:encoded></item><item><title><![CDATA[Javascript Checkout - Triangulation 2]]></title><description><![CDATA[In which I agonise over how much duplication to remove]]></description><link>https://habitablecode.substack.com/p/javascript-checkout-triangulation</link><guid isPermaLink="false">https://habitablecode.substack.com/p/javascript-checkout-triangulation</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 30 Sep 2022 07:00:04 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1f5f92b6-6de9-439d-a77b-97e7d171ce61_1003x250.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is part 5 in a series in which I&#8217;m doing a well-known code kata in the &#8220;TDD as if you meant it&#8221; style. I&#8217;m also strictly following the 4 rules of simple design and looking for opportunities to use implicit coupling to drive refactoring under the Once And Only Once rule. (If you missed the start of this series you can catch up with part 1 <a href="https://habitablecode.substack.com/p/javascript-checkout-1">here</a>.)</p><p>Last time I decided to compare two different approaches to test-driving this kata. We&#8217;re currently working on a branch while we explore triangulation, and then we&#8217;ll go back to main to explore the alternative approach of fixing the coupling first.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe here to see how this worked example plays out and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Currently on the branch we have this code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HXqt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HXqt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png 424w, https://substackcdn.com/image/fetch/$s_!HXqt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png 848w, https://substackcdn.com/image/fetch/$s_!HXqt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png 1272w, https://substackcdn.com/image/fetch/$s_!HXqt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HXqt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png" width="577" height="302" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:45908,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HXqt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png 424w, https://substackcdn.com/image/fetch/$s_!HXqt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png 848w, https://substackcdn.com/image/fetch/$s_!HXqt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png 1272w, https://substackcdn.com/image/fetch/$s_!HXqt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5c12cd26-bd08-46e8-b250-6d81b8899667_577x302.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I&#8217;m satisfied that this tells the Customer&#8217;s story well enough for now, so it&#8217;s time to move on to rule 3 and look at coupling issues. A quick glance shows me the following:</p><ol><li><p>The price of an A is 50, which is known by lines 4, 14, and 15.</p></li><li><p>The price of a B is 30, which is known by lines 6 and 15.</p></li><li><p>Lines 3-6 are coupled to the lengths of the test arrays somehow.</p></li></ol><p>There may be more, but I don&#8217;t feel it matters if we don&#8217;t see it all now. After we&#8217;ve done some cleaning up we&#8217;ll regularly look at the code again and again, and I think we&#8217;ll be more likely to spot other coupling (if it&#8217;s there) when we have somewhat cleaner code.</p><p>So, which to fix first. Again I&#8217;m not sure it matters, so I&#8217;m going after that 50, simply because it&#8217;s the most obvious.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ssDe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ssDe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png 424w, https://substackcdn.com/image/fetch/$s_!ssDe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png 848w, https://substackcdn.com/image/fetch/$s_!ssDe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png 1272w, https://substackcdn.com/image/fetch/$s_!ssDe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ssDe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png" width="344" height="85.76373626373626" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:363,&quot;width&quot;:1456,&quot;resizeWidth&quot;:344,&quot;bytes&quot;:88278,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ssDe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png 424w, https://substackcdn.com/image/fetch/$s_!ssDe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png 848w, https://substackcdn.com/image/fetch/$s_!ssDe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png 1272w, https://substackcdn.com/image/fetch/$s_!ssDe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F399e4d9b-97e0-4066-95da-0e0f7c629325_2003x499.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The value 50 is arbitrary, but something somewhere must know it; so we can&#8217;t remove it altogether and it needs to be defined somewhere. So I can see five options:</p><ol><li><p>Define the price of A in the code and let the test access it.</p></li><li><p>Define the price of A in the test and let the code access it.</p></li><li><p>Define the price of A in the code and pass it to the test.</p></li><li><p>Define the price of A in the test and pass it to the code.</p></li><li><p>Define the price of A somewhere else and access it from both the code and the test.</p></li></ol><p>Options 2 &amp; 3 would create a dependency from the code to the test, so we rule them out right away. Option 1 violates the intent of the kata (the pricing rules should be easily changeable without changing code). And for option 5 I don&#8217;t yet have anywhere else available. So option 4 feels the lightest touch for now.</p><p>I add a parameter:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bwpQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bwpQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png 424w, https://substackcdn.com/image/fetch/$s_!bwpQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png 848w, https://substackcdn.com/image/fetch/$s_!bwpQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png 1272w, https://substackcdn.com/image/fetch/$s_!bwpQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bwpQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png" width="579" height="303" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:303,&quot;width&quot;:579,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47397,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bwpQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png 424w, https://substackcdn.com/image/fetch/$s_!bwpQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png 848w, https://substackcdn.com/image/fetch/$s_!bwpQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png 1272w, https://substackcdn.com/image/fetch/$s_!bwpQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8777266e-2610-4ebd-a119-0dc42cebd8e2_579x303.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The tests pass, so I commit: <code>uncouple the code from the price of A</code>. And to stick with my intended discipline, I now return to the 4 Rules again.</p><p>Does this code express my intention? Actually, for now I think it does, so I move on to rule 3 again. The code is now explicitly coupled to the price of A, which is a clear improvement; but it is still implicitly coupled to that 30 for the price of B. And what do you make of the several places in the test that mention 50? What would you do about that? Take a moment to consider the options before reading on &#8212; and please leave a comment explaining your reasoning if you have the time.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/javascript-checkout-triangulation/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/javascript-checkout-triangulation/comments"><span>Leave a comment</span></a></p><p>My preference is to leave the test as it is &#8212; at least for now &#8212; for a couple of reasons. Firstly, all of the 50 instances are now in one function; so although lines 14, 15, and 17 are implicitly coupled together, they are all within a single <em>encapsulation unit</em> and so the risk of something breaking is low and the cost of fixing it is also low. We should make a mental note to review this decision if the test gets much bigger, or if it gets broken up into helper functions or suchlike. But for now, the potential problem is contained and localised, so I&#8217;m not concerned about it.</p><p>Secondly, I feel there&#8217;s more mileage in addressing the coupled 30 instances first. Because when I&#8217;ve done that I may begin to see patterns of similarity that link the 50s and the 30s, so my next round of refactoring could have more information to build on. That is, if I fix similar problems twice in a row (the 50s, then the 30s) I&#8217;m hoping I may have more self-similarity to shoot for afterwards; whereas if I press on with the 50s I may not see some nice symmetries until I&#8217;ve expended a lot of effort. In general I have a preference for breadth-first tree walks &#8212; fix the 50s a little, fix the 30s a little, fix the 50s a little more, fix the 30s a little more, see the patterns that emerge, &#8230;</p><p>But there are trade-offs here, as always. Let&#8217;s imagine for a second that I &#8220;fix&#8221; the duplication by defining the price of A in exactly one place:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZAT1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZAT1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png 424w, https://substackcdn.com/image/fetch/$s_!ZAT1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png 848w, https://substackcdn.com/image/fetch/$s_!ZAT1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png 1272w, https://substackcdn.com/image/fetch/$s_!ZAT1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZAT1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png" width="578" height="198" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:198,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32582,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZAT1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png 424w, https://substackcdn.com/image/fetch/$s_!ZAT1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png 848w, https://substackcdn.com/image/fetch/$s_!ZAT1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png 1272w, https://substackcdn.com/image/fetch/$s_!ZAT1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F75bf9a70-5810-4f47-b9e9-86b6467d708e_578x198.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Line 17 gives me cause for concern, because now it explicitly duplicates the algorithm from the code. Look ahead at the remaining tests in the kata and you&#8217;l see that later test cases will become more and more complicated and I&#8217;ll have dozens of lines of test code that effectively duplicate the code&#8217;s algorithm. So I have to make a trade-off: do I explicitly document how the test values were derived, or do I explicitly document the expected outcomes, and expect the reader to do the calculations in their head? The second variant above would have the advantage of allowing me to replace the static 50 with an arbitrary &#8212; maybe even randomly generated &#8212; value. I feel that would give me better coverage, and would be a step on the road to property-based testing this code. So maybe as the forces within this code change I&#8217;ll reconsider, but right now I like the clarity of having the explicit 50 in the test expectation.</p><p>Reverting back to the committed code, I make a similar change and inject the 30 as a parameter:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cFkq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cFkq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png 424w, https://substackcdn.com/image/fetch/$s_!cFkq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png 848w, https://substackcdn.com/image/fetch/$s_!cFkq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png 1272w, https://substackcdn.com/image/fetch/$s_!cFkq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cFkq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png" width="578" height="303" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/add43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:303,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:48077,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cFkq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png 424w, https://substackcdn.com/image/fetch/$s_!cFkq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png 848w, https://substackcdn.com/image/fetch/$s_!cFkq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png 1272w, https://substackcdn.com/image/fetch/$s_!cFkq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadd43bf5-d521-4eb7-83c8-6366458a51cb_578x303.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Commit: <code>uncouple the code from the price of B</code>.</p><p>As per usual, it&#8217;s now time to sit back and reflect on how well this code tells its story, and whether I&#8217;ve introduced any (more) implicit coupling. For example, we can now clearly see additional symmetries caused by the introduction of <code>priceOfB</code>. Do they help us or hinder us in understanding the code? What would you change next?</p><h2>Things to try</h2><ul><li><p>Next time you have a choice between depth-first and breadth-first tree walking, try breadth-first and look out for symmetries appearing sooner.</p></li><li><p>Explore property-based testing: is it appropriate for the code you&#8217;re currently writing?</p></li></ul><p>As always, if you try these please let me and your fellow readers know.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/javascript-checkout-triangulation/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/javascript-checkout-triangulation/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Javascript Checkout 4]]></title><description><![CDATA[In which we consider self-similarity, and a branch is created!]]></description><link>https://habitablecode.substack.com/p/javascript-checkout-4</link><guid isPermaLink="false">https://habitablecode.substack.com/p/javascript-checkout-4</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Tue, 27 Sep 2022 07:01:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/h_600,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is part 4 in a series in which I&#8217;m doing a well-known code kata in the &#8220;TDD as if you meant it&#8221; style. I&#8217;m also strictly following the 4 rules of simple design and looking for opportunities to use implicit coupling to drive refactoring under the Once And Only Once rule. (If you missed the start of this series you can catch up with part 1 <a href="https://habitablecode.substack.com/p/javascript-checkout-1">here</a>.)</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This is looking like being a long series of articles, so make sure you subscribe (it&#8217;s free!) so you don&#8217;t miss anything.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Last time I spent quite a bit of effort getting my code and tests readable (in the sense that they tell my Customer&#8217;s story). I arrived at a point where I felt it was time to introduce the next failing test, but I promised to review the code one last time before making that big step.</p><p>So here's where we are right now:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5SJx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5SJx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png 424w, https://substackcdn.com/image/fetch/$s_!5SJx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png 848w, https://substackcdn.com/image/fetch/$s_!5SJx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png 1272w, https://substackcdn.com/image/fetch/$s_!5SJx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5SJx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png" width="579" height="259" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:259,&quot;width&quot;:579,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:39115,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5SJx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png 424w, https://substackcdn.com/image/fetch/$s_!5SJx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png 848w, https://substackcdn.com/image/fetch/$s_!5SJx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png 1272w, https://substackcdn.com/image/fetch/$s_!5SJx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3a6c85f9-957d-4c95-9a9f-5484358a23b9_579x259.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Coming back to this now, I can see that there&#8217;s still some coupling that I should address.</p><p>Firstly, zero appears three times (lines 2, 3, and 11). The instance on line 3 is clearly unique, but those other two &#8220;mean&#8221; the same: they represent the price of an empty basket. In past attempts at this kata I&#8217;ve never bothered about that, but I can definitely conceive of situations in which there could be a non-zero fee for engaging the purchasing process &#8212; perhaps a membership fee or reservation fee. But looking ahead at <a href="http://codekata.com/kata/kata09-back-to-the-checkout/">Pragmatic Dave&#8217;s tests</a> I can&#8217;t see any mention of such a thing for this kata, so I&#8217;m happy to let those zeroes stand as they are.</p><p>Am I &#8220;allowed&#8221; to look ahead? I think so &#8212; I suspect that&#8217;s what my Customer is doing much of the time. But what about YAGNI (You Ain&#8217;t Gonna Need It), I hear you cry? Well, I&#8217;m not deciding whether to add functionality; only how much to refactor. In terms of <em>implicit coupling</em>, I guess I&#8217;m deciding that it&#8217;s okay for the zero starting price to be implicit in this codebase, and that adding a constant or suchlike would be overkill based on what we know now. I don&#8217;t want to pre-load this code with every future I can possibly think of, and so I&#8217;m happy for now to assume that what we can see in the future tests is all we&#8217;ll have to cope with.</p><p>Next though, there are 50s on lines 4 and 12. This feels like an arbitrary value, and the kata description ends with this paragraph:</p><blockquote><p>&#8220;The challenge description doesn&#8217;t mention the format of the pricing rules. How can these be specified in such a way that the checkout doesn&#8217;t know about particular items and their pricing strategies? How can we make the design flexible enough so that we can add new styles of pricing rule in the future?&#8221;</p></blockquote><p>So my instincts are borne out by the Customer: the 50 is an arbitrary value and represents unwanted coupling between the code and the test. And I&#8217;d say that the coupling is <em>implicit</em>, because I see nothing in the <code>totalPriceOf</code> function that tells me how the 50 is likely to change.</p><p>The question is, what to do about it? As I&#8217;ve mentioned elsewhere, some folks would <em>triangulate</em> here, adding another failing test that demonstrates the coupling. Indeed many times in the past I&#8217;ve added a new test</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IBz0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IBz0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png 424w, https://substackcdn.com/image/fetch/$s_!IBz0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png 848w, https://substackcdn.com/image/fetch/$s_!IBz0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png 1272w, https://substackcdn.com/image/fetch/$s_!IBz0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IBz0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png" width="583" height="17" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:17,&quot;width&quot;:583,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1657,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IBz0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png 424w, https://substackcdn.com/image/fetch/$s_!IBz0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png 848w, https://substackcdn.com/image/fetch/$s_!IBz0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png 1272w, https://substackcdn.com/image/fetch/$s_!IBz0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f37ae41-b806-470a-a96d-f85fc2f5cff4_583x17.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>at this point. Pragmatic Dave takes a slightly different slant on the same idea:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eMup!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eMup!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png 424w, https://substackcdn.com/image/fetch/$s_!eMup!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png 848w, https://substackcdn.com/image/fetch/$s_!eMup!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png 1272w, https://substackcdn.com/image/fetch/$s_!eMup!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eMup!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png" width="579" height="17" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:17,&quot;width&quot;:579,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!eMup!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png 424w, https://substackcdn.com/image/fetch/$s_!eMup!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png 848w, https://substackcdn.com/image/fetch/$s_!eMup!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png 1272w, https://substackcdn.com/image/fetch/$s_!eMup!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8e2f4b4-819f-40c8-bb2d-d91a92ad9457_579x17.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Me, I&#8217;m always nervous about triangulation. I don&#8217;t like the thought of adding more complexity to code that is already coupled &#8212; it seems like an added maintenance burden and we still need to fix that coupling.</p><p>But that&#8217;s a purely subjective view, so let&#8217;s put it to the test. At this point I&#8217;m going to branch: I&#8217;ll triangulate on one branch and then come back to trunk and fix the coupling instead of triangulating. Then we can compare the two approaches and see what benefits each gave us.</p><p>So I create a branch <code>triangulate-first</code> and add Pragmatic Dave&#8217;s next test. It fails, so I quickly make it pass:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!awzp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!awzp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png 424w, https://substackcdn.com/image/fetch/$s_!awzp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png 848w, https://substackcdn.com/image/fetch/$s_!awzp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png 1272w, https://substackcdn.com/image/fetch/$s_!awzp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!awzp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png" width="580" height="304" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:304,&quot;width&quot;:580,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:46077,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!awzp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png 424w, https://substackcdn.com/image/fetch/$s_!awzp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png 848w, https://substackcdn.com/image/fetch/$s_!awzp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png 1272w, https://substackcdn.com/image/fetch/$s_!awzp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c417556-4851-4c94-a743-5dcb0597f9f4_580x304.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Commit: <code>calculate price for basket with A and B</code>.</p><p>There are, of course, plenty of ways I could have changed the code to make this test pass, so why did I choose this one? I don&#8217;t honestly know. I also considered something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Diwt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Diwt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png 424w, https://substackcdn.com/image/fetch/$s_!Diwt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png 848w, https://substackcdn.com/image/fetch/$s_!Diwt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png 1272w, https://substackcdn.com/image/fetch/$s_!Diwt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Diwt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png" width="576" height="123" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:123,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18064,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Diwt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png 424w, https://substackcdn.com/image/fetch/$s_!Diwt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png 848w, https://substackcdn.com/image/fetch/$s_!Diwt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png 1272w, https://substackcdn.com/image/fetch/$s_!Diwt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fded68a96-12e3-48d8-b935-10bf3c5c17e4_576x123.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Both variants have the advantage that they are pure <em>additions</em>, leaving the code around them unchanged. And arguably the second variant is a direct, naive interpretation of the new test, whereas in order to get to the first variant I must have done subtraction in my head. So in some sense the &#8220;distance&#8221; from the new test to the second variant is shorter, and maybe that&#8217;s a better habit to have.</p><p>That said, the option I chose does reflect the pricing rules from the original kata description (the price of a B is 30). More importantly though, it also extends the structural pattern of the original code. I think I have a strong personal preference for designs that are expressed through symmetry and self-similarity. This may also be why I like my test cases organised in a table. Nevertheless, I took a design step while getting from RED to GREEN, and in general I try to caution against doing that.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rmB0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rmB0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rmB0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rmB0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rmB0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rmB0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg" width="622" height="466.5" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1024,&quot;resizeWidth&quot;:622,&quot;bytes&quot;:57919,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rmB0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rmB0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rmB0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rmB0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F89d0819e-a2b6-471a-a69a-184c4830272b_1024x768.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Created by Wolfgang Beyer with the program Ultra Fractal 3., CC BY-SA 3.0, via Wikimedia Commons</figcaption></figure></div><p>Anyway, we are where we are, so let&#8217;s stick with it and see where it takes us. It&#8217;s time to refactor. Following the 4 Rules, I need to start with readability. And if I want to tell a story I should begin at the outside &#8212; in this case that means with the tests. I didn&#8217;t change any names, but I did violate the layout we introduced to help deal with all those brackets. So I change lines 13-14 to return to that standard:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vLMF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vLMF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png 424w, https://substackcdn.com/image/fetch/$s_!vLMF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png 848w, https://substackcdn.com/image/fetch/$s_!vLMF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png 1272w, https://substackcdn.com/image/fetch/$s_!vLMF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vLMF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png" width="577" height="167" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26771,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vLMF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png 424w, https://substackcdn.com/image/fetch/$s_!vLMF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png 848w, https://substackcdn.com/image/fetch/$s_!vLMF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png 1272w, https://substackcdn.com/image/fetch/$s_!vLMF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5420bdea-3a8e-46e7-90a1-12a9826f7d88_577x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This is probably going to become tiresome, so I may need to think of something better if it does. Commit: <code>ensure consistent layout of test cases</code>.</p><p>I feel those tests are (still) pretty readable, so let&#8217;s look at the code. If I forget everything I know about future requirements (ie. the remaining tests in the kata description), then the code as it stands seems reasonably clear. I can&#8217;t think of a way to improve its story-telling ability.</p><p>So I feel it&#8217;s time to move on to rule 3 &#8212; does this codebase say everything once and only once? We&#8217;ll find out next time&#8230;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This is probably going to be quite a long series of articles! To make sure you don&#8217;t miss anything, subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Things to try</h2><ul><li><p>Take a break after any period of concentrated effort. When you return you&#8217;re likely to see things with fresh eyes.</p></li><li><p>Next time you&#8217;re getting from RED to GREEN jot down as many alternative code changes as you can think of. Which one do you choose to move forward with, and why?</p></li><li><p>Look for opportunities to increase the symmetry and self-similarity in your code. Does this always help with readability?</p></li></ul><p>As always, why not let your fellow readers know how you get on when you try these&#8230;</p>]]></content:encoded></item><item><title><![CDATA[Javascript Checkout 3]]></title><description><![CDATA[In which my tests become explicitly coupled and names change many times]]></description><link>https://habitablecode.substack.com/p/javascript-checkout-3</link><guid isPermaLink="false">https://habitablecode.substack.com/p/javascript-checkout-3</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 23 Sep 2022 07:00:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/h_600,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is part 3 in a series in which I&#8217;m doing a well-known code kata in the &#8220;TDD as if you meant it&#8221; style. I&#8217;m also strictly following the 4 rules of simple design and looking for opportunities to use implicit coupling to drive refactoring under the Once And Only Once rule. (If you missed the start of this series you can catch up with part 1 <a href="https://habitablecode.substack.com/p/javascript-checkout-1">here</a>.)</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This is looking like being a long series of articles, so make sure you subscribe (it&#8217;s free!) so you don&#8217;t miss anything.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>In <a href="https://habitablecode.substack.com/p/javascript-checkout-2">part 2</a> I <em>increased</em> the amount of duplication, so that my tests both told the same story consistently. So currently I have this code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CjMt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CjMt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png 424w, https://substackcdn.com/image/fetch/$s_!CjMt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png 848w, https://substackcdn.com/image/fetch/$s_!CjMt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png 1272w, https://substackcdn.com/image/fetch/$s_!CjMt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CjMt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png" width="577" height="318" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:318,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:51494,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CjMt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png 424w, https://substackcdn.com/image/fetch/$s_!CjMt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png 848w, https://substackcdn.com/image/fetch/$s_!CjMt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png 1272w, https://substackcdn.com/image/fetch/$s_!CjMt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4938c86-bbd6-4deb-bffb-9d5705738fe9_577x318.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Let&#8217;s review this from the point of view of the 4 Rules: Firstly, these tests are passing. And there is no other code, so by definition everything must be covered by tests (another benefit of TDD As If You Meant It). Second, do these tests clearly tell the story my Customer told me? Honestly, I can&#8217;t really tell; they <em>look</em> as if they probably do, but code this verbose is quite hard to review for readability. The noise from that duplication is so loud that I can&#8217;t get past it &#8212; and so I think I have to fix it before I can do any more.</p><p>Speaking of noisy duplication&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!efeE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!efeE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!efeE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!efeE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!efeE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!efeE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg" width="477" height="715.9474671669793" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:533,&quot;resizeWidth&quot;:477,&quot;bytes&quot;:95261,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!efeE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!efeE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!efeE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!efeE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5be2bb4-b4cc-4fdd-a69e-93af2c6d87b7_533x800.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Michael Dorausch from Venice, USA, CC BY-SA 2.0, via Wikimedia Commons</figcaption></figure></div><p>The only difference between the two tests is that <code>&#8216;A&#8217;</code> in the <code>itemsScanned</code> array. That difference should be standing out loud and proud, informing the reader that it is the entire reason for the existence of the second test. But it is currently buried in the mass of code, and so the tests look too similar to be useful. But that <code>&#8216;A&#8217;</code> is the clue that tells me I need to <strong>Extract Method</strong> and give it a parameter. I&#8217;ll extract into this test file for now, because until I&#8217;ve done that I won&#8217;t really know what to call it. So:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NkN6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NkN6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png 424w, https://substackcdn.com/image/fetch/$s_!NkN6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png 848w, https://substackcdn.com/image/fetch/$s_!NkN6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png 1272w, https://substackcdn.com/image/fetch/$s_!NkN6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NkN6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png" width="576" height="318" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:318,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49278,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NkN6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png 424w, https://substackcdn.com/image/fetch/$s_!NkN6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png 848w, https://substackcdn.com/image/fetch/$s_!NkN6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png 1272w, https://substackcdn.com/image/fetch/$s_!NkN6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F15c7e989-5bad-4dd5-99da-bd164ee620f2_576x318.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Commit: <code>Extract checkout function</code>. (I named it <code>checkout</code> for now, because that&#8217;s the name of the kata we&#8217;re doing.)</p><p>The good news here is that these tests are now explicitly coupled: they are clearly testing the same thing, and if it changes they will both test the changed thing. What was previously implicit &#8212; our intention that these tests should be coupled &#8212; is now explicit, and we can read that in the code locally.</p><p>So now it&#8217;s back around the 4 Rules. Well, the tests are still passing, so that&#8217;s good. But in extracting this function I&#8217;ve added a new name (<code>checkout</code>) to our domain model and I&#8217;ve changed the nature of <code>itemsScanned</code> from being a constant to being a function parameter. This is the &#8220;dynamo&#8221; that Joe Rainsberger talks about: every time we fix a Once And Only Once violation we change the set of names we&#8217;re using. So rules 2 and 3 go round and round.</p><p>All of which means that I must now review the names I&#8217;m using and the story they are telling. It would be tempting to start at the top of the source code and read down, looking at the names in turn. But the names are only &#8220;good&#8221; or &#8220;bad&#8221; in context; I need to start with the story and adjust the names until they work as a narrative. So I begin at the &#8220;outside&#8221;, with the tests.</p><p>The first thing I notice is that lines 10, 12, and 13 are <em>intended</em> to refer to the same domain concept, but use two different names for it. I think this is another subtle case of implicit coupling: I want the reader to make a connection between the description of the test and its implementation, but that link is currently only implied at best. The description &#8220;total price&#8221; feels more correct (subjective application of domain knowledge?), so I rename the variable in both tests to match:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!a-gp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!a-gp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png 424w, https://substackcdn.com/image/fetch/$s_!a-gp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png 848w, https://substackcdn.com/image/fetch/$s_!a-gp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png 1272w, https://substackcdn.com/image/fetch/$s_!a-gp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!a-gp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png" width="577" height="167" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/22a5e80e-6220-425f-b329-b1891749b028_577x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:28383,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!a-gp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png 424w, https://substackcdn.com/image/fetch/$s_!a-gp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png 848w, https://substackcdn.com/image/fetch/$s_!a-gp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png 1272w, https://substackcdn.com/image/fetch/$s_!a-gp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22a5e80e-6220-425f-b329-b1891749b028_577x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Commit: <code>Rename variable to match the domain</code>.</p><p>I read these tests again and now I&#8217;m not sure that <code>checkout</code> is right. Would <code>scan</code> be a better fit? It&#8217;s cheap to find out:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iysO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iysO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png 424w, https://substackcdn.com/image/fetch/$s_!iysO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png 848w, https://substackcdn.com/image/fetch/$s_!iysO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png 1272w, https://substackcdn.com/image/fetch/$s_!iysO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iysO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png" width="580" height="169" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:169,&quot;width&quot;:580,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:28206,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iysO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png 424w, https://substackcdn.com/image/fetch/$s_!iysO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png 848w, https://substackcdn.com/image/fetch/$s_!iysO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png 1272w, https://substackcdn.com/image/fetch/$s_!iysO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fabce15-8ae6-44da-a04b-db7ce4d89d30_580x169.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Yes, that feels better: I scan a list of items and get back a total price. Commit: <code>Rename function to tell a clearer story</code>.</p><p>Now I notice that totalPrice could be a <code>const</code>. And in fact, as it doesn&#8217;t change and is used only once it could be inlined. Do I want to lose the expressive power of having the extra name here? Only one way to find out:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UeQl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UeQl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png 424w, https://substackcdn.com/image/fetch/$s_!UeQl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png 848w, https://substackcdn.com/image/fetch/$s_!UeQl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png 1272w, https://substackcdn.com/image/fetch/$s_!UeQl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UeQl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png" width="578" height="137" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:137,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21936,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UeQl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png 424w, https://substackcdn.com/image/fetch/$s_!UeQl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png 848w, https://substackcdn.com/image/fetch/$s_!UeQl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png 1272w, https://substackcdn.com/image/fetch/$s_!UeQl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe38f54dd-3a82-4026-b50f-2542509c8fcd_578x137.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Hmmm. Each test now has three closing brackets together, which definitely makes me slow down when attempting to parse the code. But I have a general distrust of temporary variables (even though this one is a <code>const</code>), so right now I feel quite conflicted. This code now feels more &#8220;technical&#8221; and thus harder to read; but it has one fewer variable, and that&#8217;s something I usually strive for.</p><p>If I were to keep this version I feel the name <code>scan</code> now doesn&#8217;t help as much as <code>totalPrice</code> used to; I&#8217;m inclined to press on without the <code>const</code>, but with the previous vocabulary. How about this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZPCY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZPCY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png 424w, https://substackcdn.com/image/fetch/$s_!ZPCY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png 848w, https://substackcdn.com/image/fetch/$s_!ZPCY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png 1272w, https://substackcdn.com/image/fetch/$s_!ZPCY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZPCY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png" width="577" height="138" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:138,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23074,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZPCY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png 424w, https://substackcdn.com/image/fetch/$s_!ZPCY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png 848w, https://substackcdn.com/image/fetch/$s_!ZPCY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png 1272w, https://substackcdn.com/image/fetch/$s_!ZPCY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F97cb6c4d-00a6-4044-b351-093d28d50c5c_577x138.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>That definitely reads better (tells the story to my Customer), but those nested brackets are still irksome. Actually, the innermost pair of brackets could be removed from those expressions (lines 12 and 16) if the list of items had a name. But that would introduce another temporary variable, which is something I&#8217;m trying to avoid. Unless I look at the two tests together and realise that they are incredibly similar. Could I replace them with a single parameterized test? A quick Google tells me I can do this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cLOb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cLOb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png 424w, https://substackcdn.com/image/fetch/$s_!cLOb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png 848w, https://substackcdn.com/image/fetch/$s_!cLOb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png 1272w, https://substackcdn.com/image/fetch/$s_!cLOb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cLOb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png" width="578" height="122" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/fc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:122,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20042,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cLOb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png 424w, https://substackcdn.com/image/fetch/$s_!cLOb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png 848w, https://substackcdn.com/image/fetch/$s_!cLOb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png 1272w, https://substackcdn.com/image/fetch/$s_!cLOb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc87bee8-5c3e-4642-a7e8-43613d114677_578x122.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And when this runs, the output looks like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QSOv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QSOv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png 424w, https://substackcdn.com/image/fetch/$s_!QSOv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png 848w, https://substackcdn.com/image/fetch/$s_!QSOv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png 1272w, https://substackcdn.com/image/fetch/$s_!QSOv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QSOv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png" width="572" height="213" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:213,&quot;width&quot;:572,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29372,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QSOv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png 424w, https://substackcdn.com/image/fetch/$s_!QSOv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png 848w, https://substackcdn.com/image/fetch/$s_!QSOv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png 1272w, https://substackcdn.com/image/fetch/$s_!QSOv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F986f1d97-8e67-4d56-b09e-8005b50335d3_572x213.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I definitely like the test output, and I think line 15 reads better than either test did in the previous version. I still have to pause when reading those arrays on lines 12-13 though, so I wonder whether I can use whitespace to help:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1Shz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1Shz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png 424w, https://substackcdn.com/image/fetch/$s_!1Shz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png 848w, https://substackcdn.com/image/fetch/$s_!1Shz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png 1272w, https://substackcdn.com/image/fetch/$s_!1Shz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1Shz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png" width="577" height="123" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/aaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:123,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20036,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1Shz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png 424w, https://substackcdn.com/image/fetch/$s_!1Shz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png 848w, https://substackcdn.com/image/fetch/$s_!1Shz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png 1272w, https://substackcdn.com/image/fetch/$s_!1Shz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa51f73-bfe4-4308-9a49-4c7620ace92e_577x123.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Yes, I think I can tolerate that. It&#8217;s really line 15 that is the big attraction of this approach, I suspect because I have extra names (the test parameters) without having extra temporary variables. Commit: <code>Replace the tests with a table of cases</code>.</p><p>So now I&#8217;m happy that the tests tell their story fairly well, let&#8217;s drill down one level of abstraction and look at the function we&#8217;re testing:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aF-W!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aF-W!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png 424w, https://substackcdn.com/image/fetch/$s_!aF-W!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png 848w, https://substackcdn.com/image/fetch/$s_!aF-W!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png 1272w, https://substackcdn.com/image/fetch/$s_!aF-W!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aF-W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png" width="574" height="109" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:109,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16406,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aF-W!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png 424w, https://substackcdn.com/image/fetch/$s_!aF-W!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png 848w, https://substackcdn.com/image/fetch/$s_!aF-W!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png 1272w, https://substackcdn.com/image/fetch/$s_!aF-W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3a7dd74-1532-449a-967f-f93301a1b8a7_574x109.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Two problems strike me here: First, the domain concept of &#8220;scanning&#8221; isn&#8217;t mentioned anywhere else now; and second, there&#8217;s a wee bit of friction between the names <code>currentPrice</code> and <code>totalPriceOf</code>. I&#8217;m cavalier enough to think that I can fix both of these in one edit:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GcJh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GcJh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png 424w, https://substackcdn.com/image/fetch/$s_!GcJh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png 848w, https://substackcdn.com/image/fetch/$s_!GcJh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png 1272w, https://substackcdn.com/image/fetch/$s_!GcJh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GcJh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png" width="574" height="108" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:108,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16258,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GcJh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png 424w, https://substackcdn.com/image/fetch/$s_!GcJh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png 848w, https://substackcdn.com/image/fetch/$s_!GcJh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png 1272w, https://substackcdn.com/image/fetch/$s_!GcJh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98d18518-6b75-4feb-9b44-88721b6cd0a3_574x108.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>For once my cockiness pays off. Commit: <code>Change local names to match the domain</code>. And now that my attention isn&#8217;t diverted by those names, I see that line 5 looks like overkill. Do I really need a ternary just to add 50 to 0?</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pZEi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pZEi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png 424w, https://substackcdn.com/image/fetch/$s_!pZEi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png 848w, https://substackcdn.com/image/fetch/$s_!pZEi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png 1272w, https://substackcdn.com/image/fetch/$s_!pZEi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pZEi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png" width="571" height="93" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:93,&quot;width&quot;:571,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13942,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pZEi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png 424w, https://substackcdn.com/image/fetch/$s_!pZEi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png 848w, https://substackcdn.com/image/fetch/$s_!pZEi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png 1272w, https://substackcdn.com/image/fetch/$s_!pZEi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0cbe3a4a-48c3-4d6e-8115-89f0c59d9977_571x93.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>That&#8217;s better, and I think it tells the story more clearly too. Commit: <code>Clarify the totalling algorithm</code>.</p><p>That feels like a lot for today, so it&#8217;s time to quickly recap. I began by fixing a violation of the Once And Only Once rule; but I think it&#8217;s more important to say that I explicitly coupled the tests to each other, as intended by both the Developer (me) and the Customer (also me).</p><p>I then spent quite a few moves on telling the story; and once or twice I found that simplifying the story and/or the names also allowed me to see other duplication or superfluous elements that I had previously missed. Reader Walter Nuccio commented on <a href="https://habitablecode.substack.com/p/runtime-and-compile-time">Runtime and compile time</a> suggesting that we could view the second Rule (expresses intent) in terms of explicit coupling too: The names we use should be explicitly coupled to domain concepts, and the story told by the Customer should be explicitly represented in the code. This is what I&#8217;ve tried to do with these naming moves today.</p><p>Right now I&#8217;m pretty happy with this code, so next time I plan to move along and add the next test. But I will nevertheless begin with a read through the code to check how well it communicates; because currently my perception is heavily influenced by the fact that I just spent a couple of hours right here in this context, and so I&#8217;m biased by today&#8217;s momentum.</p><p>Does all of this feel too slow to you? I think it only <em>seems</em> slow because I&#8217;m calling out my thinking as we go along. Try it yourself and let us know how it feels.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/javascript-checkout-3/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/javascript-checkout-3/comments"><span>Leave a comment</span></a></p><h2>Things to try</h2><ul><li><p>When you&#8217;re assessing whether your code tells its story, start at the outside and work inwards only when the outer layers of abstraction communicate extremely well.</p></li><li><p>Next time you have to refactor, consciously cycle around the 4 Rules. In particular each time you change anything, start again with a new review of the names and the story they tell.</p></li></ul><p>As always, please share your results by leaving a comment if you try these.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Javascript Checkout 2]]></title><description><![CDATA[In which I use the 4 Rules of Simple Design to prioritise my refactoring]]></description><link>https://habitablecode.substack.com/p/javascript-checkout-2</link><guid isPermaLink="false">https://habitablecode.substack.com/p/javascript-checkout-2</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Tue, 20 Sep 2022 07:00:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6Byl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is part 2 in a series in which I&#8217;m doing a well-known code kata in the &#8220;TDD as if you meant it&#8221; style. I&#8217;m also strictly following the 4 rules of simple design and looking for opportunities to use implicit coupling to drive refactoring under the Once And Only Once rule.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This is looking like a long series of articles, so make sure you subscribe (it&#8217;s free!) so you don&#8217;t miss anything.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>A the end of <a href="https://habitablecode.substack.com/p/javascript-checkout-1">part 1</a> we had this code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!O4V6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!O4V6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png 424w, https://substackcdn.com/image/fetch/$s_!O4V6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png 848w, https://substackcdn.com/image/fetch/$s_!O4V6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png 1272w, https://substackcdn.com/image/fetch/$s_!O4V6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!O4V6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png" width="578" height="245" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/a4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:245,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34487,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!O4V6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png 424w, https://substackcdn.com/image/fetch/$s_!O4V6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png 848w, https://substackcdn.com/image/fetch/$s_!O4V6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png 1272w, https://substackcdn.com/image/fetch/$s_!O4V6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4da64ff-9bbe-4b9a-8774-8862cf956326_578x245.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It&#8217;s now time to REFACTOR, which I consider to be very much the hardest part of TDD. How should we proceed?</p><p>Well, first let&#8217;s make a list of the problems I can see in this code.</p><ol><li><p>Our intention is that these two tests should be testing the same thing. That is, we expect them to be coupled, but they aren&#8217;t. There&#8217;s nothing preventing me changing the tests independently.</p></li><li><p>The story told by the first test now seems out of date compared to the second, because in the first test there is no mention (in the code) that no items have been scanned.</p></li><li><p>There are zeroes on lines 3, 4, 5, and 9 &#8212; they are all the same zero, but the code does nothing to hint at that.</p></li><li><p>There are 50s on lines 8, 11, and 12. Again, these are all the same 50.</p></li></ol><p>I&#8217;ve probably missed some places where our intention isn&#8217;t expressed explicitly, or where some coupling is not explicit. Did you see any I missed?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/javascript-checkout-2/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/javascript-checkout-2/comments"><span>Leave a comment</span></a></p><p>Let&#8217;s assume that my list above is reasonably complete. I don&#8217;t think it matters if it isn&#8217;t, because my perception of the code will change as soon as I make any changes. So we&#8217;ll be constantly revisiting and refining our list until we decide it&#8217;s time to move on. The important thing now is just to make a start at improving this code. So, where to begin?</p><p>At this point I find myself hesitating. Does it matter which order I make these refactorings? If I change A then B, will I get the same code as if I had changed B then A? Is there a &#8220;better&#8221; choice? If I do A first, will that back me into a corner such that it will later be harder to do B? Is there an &#8220;optimal&#8221; sequence in which to make these changes?</p><p>I do this all the time, and it&#8217;s mostly futile. I think it&#8217;s a personal hangover from the days before TDD &#8212; I still haven&#8217;t completely lost the habit of wanting to &#8220;solve&#8221; the problem before I write any code. What would you tackle first? Make a note before reading any further.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/javascript-checkout-2/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/javascript-checkout-2/comments"><span>Leave a comment</span></a></p><p>So, a quick slap on the wrist and I remember to go back to the 4 Rules. My top priority &#8212; at least according to my personal reading of the 4 Rules &#8212; should be to express intent. There are several ways in which the current code doesn&#8217;t do that, and I&#8217;m going to pick <strong>consistency</strong> first. Both tests should be telling the same basic story, with the only differences being that <code>&#8216;A&#8217;</code> and the corresponding 50. So I want to change both tests so that they tell the same &#8220;shape&#8221; of story using the same terms.</p><p>First, I change the second test so that <code>itemsScanned</code> reflects the plurality of its name:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KHjc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KHjc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png 424w, https://substackcdn.com/image/fetch/$s_!KHjc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png 848w, https://substackcdn.com/image/fetch/$s_!KHjc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png 1272w, https://substackcdn.com/image/fetch/$s_!KHjc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KHjc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png" width="574" height="92" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:92,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14814,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!KHjc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png 424w, https://substackcdn.com/image/fetch/$s_!KHjc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png 848w, https://substackcdn.com/image/fetch/$s_!KHjc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png 1272w, https://substackcdn.com/image/fetch/$s_!KHjc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7f8519-365e-426d-a3f2-041c3eb0f858_574x92.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now I can change the first test to tell a more similar story:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xCJ-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xCJ-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png 424w, https://substackcdn.com/image/fetch/$s_!xCJ-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png 848w, https://substackcdn.com/image/fetch/$s_!xCJ-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png 1272w, https://substackcdn.com/image/fetch/$s_!xCJ-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xCJ-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png" width="580" height="76" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c098a45e-3700-46ac-8771-1b522f6b5769_580x76.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:76,&quot;width&quot;:580,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12447,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xCJ-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png 424w, https://substackcdn.com/image/fetch/$s_!xCJ-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png 848w, https://substackcdn.com/image/fetch/$s_!xCJ-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png 1272w, https://substackcdn.com/image/fetch/$s_!xCJ-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc098a45e-3700-46ac-8771-1b522f6b5769_580x76.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The tests are green, so I commit: <code>Make the tests more similar shapes</code>.</p><p>This feels clearer, but I&#8217;m still not happy that our intention is being well expressed. I find my eye repeatedly drawn to line 11, which has no counterpart in the first test. And because of that, I&#8217;ve just had an idea; an idea that I really like&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Byl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Byl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg 424w, https://substackcdn.com/image/fetch/$s_!6Byl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg 848w, https://substackcdn.com/image/fetch/$s_!6Byl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!6Byl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Byl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg" width="586" height="390.39835164835165" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:970,&quot;width&quot;:1456,&quot;resizeWidth&quot;:586,&quot;bytes&quot;:544262,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6Byl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg 424w, https://substackcdn.com/image/fetch/$s_!6Byl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg 848w, https://substackcdn.com/image/fetch/$s_!6Byl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!6Byl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb08d677f-ae7b-40de-8d0c-8d028b487a52_2048x1365.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://www.flickr.com/photos/misteraitch/2660963679">Stuart Heath</a></figcaption></figure></div><p></p><p>I want to follow the 4 Rules, so I want to change this code to express my intention <em>before</em> I tackle any violations of the Once And Only Once rule. In fact, for the sake of intentionality I&#8217;m going to make the duplication <em>worse</em> now. And all because line 11 is an asymmetry between the two tests.</p><p>Another way to read line 11 is that it adds 50 to the current price if there&#8217;s an <code>&#8216;A&#8217;</code> in the scanned items list &#8212; in fact, if there&#8217;s anything at all in that list. So first I rename that <code>price</code> variable to reflect the verbal language I&#8217;m using when I discuss the code:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iwsD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iwsD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png 424w, https://substackcdn.com/image/fetch/$s_!iwsD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png 848w, https://substackcdn.com/image/fetch/$s_!iwsD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png 1272w, https://substackcdn.com/image/fetch/$s_!iwsD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iwsD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png" width="579" height="92" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:92,&quot;width&quot;:579,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15897,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iwsD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png 424w, https://substackcdn.com/image/fetch/$s_!iwsD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png 848w, https://substackcdn.com/image/fetch/$s_!iwsD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png 1272w, https://substackcdn.com/image/fetch/$s_!iwsD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6207fb21-8037-4147-9c52-013a9727e5ab_579x92.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>(This is an important step, because it helps to reduce friction and cognitive load. If we&#8217;re using one set of vocabulary when discussing the domain, the code shouldn&#8217;t be using a different set of vocabulary.)</p><p>Next, I tell the story above in code:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1Gb6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1Gb6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png 424w, https://substackcdn.com/image/fetch/$s_!1Gb6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png 848w, https://substackcdn.com/image/fetch/$s_!1Gb6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png 1272w, https://substackcdn.com/image/fetch/$s_!1Gb6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1Gb6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png" width="580" height="123" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/da65e3aa-01a2-447f-b328-61382f49e11f_580x123.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:123,&quot;width&quot;:580,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21428,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1Gb6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png 424w, https://substackcdn.com/image/fetch/$s_!1Gb6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png 848w, https://substackcdn.com/image/fetch/$s_!1Gb6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png 1272w, https://substackcdn.com/image/fetch/$s_!1Gb6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fda65e3aa-01a2-447f-b328-61382f49e11f_580x123.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I think this test now tells the story we want, and does it reasonably simply. And now I can tell the same story in the first test:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sXhZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sXhZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png 424w, https://substackcdn.com/image/fetch/$s_!sXhZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png 848w, https://substackcdn.com/image/fetch/$s_!sXhZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png 1272w, https://substackcdn.com/image/fetch/$s_!sXhZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sXhZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png" width="578" height="124" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:124,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20249,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sXhZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png 424w, https://substackcdn.com/image/fetch/$s_!sXhZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png 848w, https://substackcdn.com/image/fetch/$s_!sXhZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png 1272w, https://substackcdn.com/image/fetch/$s_!sXhZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8e7aa810-4fe1-4f5f-afef-16dd341c250b_578x124.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Commit: <code>Tell the same story in both tests</code>.</p><p>It&#8217;s worth noting that I&#8217;m leaning quite heavily here on the fact that the 4 Rules are a set of priority calls. I&#8217;ve added unnecessary stuff to the first test (violates the 4th rule) and I have apparently increased the duplication between the two tests (violates the 3rd rule). But because the 2nd rule takes precedence I&#8217;m allowed, nay encouraged, to do that. And what&#8217;s more, we can now see the implicit coupling between the tests quite clearly, expressed as duplicated code. That duplication was always there, but previously it was hidden somewhat by the different ways those two tests told their stories.</p><p>Next time I&#8217;ll probably invoke the Once And Only Once rule on these tests. Although it&#8217;s often foolish to make predictions&#8230;</p><h2>Things to try</h2><ul><li><p>Make a list of problems you can see in your own code, and prioritise them according to the 4 Rules.</p></li><li><p>Make sure the names you use in the code reflect the vocabulary you use when talking about that code.</p></li><li><p>Find a place where your code doesn&#8217;t tell the story you and your Customer intend; refactor until it does.</p></li></ul><p>As always, if you try these please share your experience with us all by leaving a comment.</p>]]></content:encoded></item><item><title><![CDATA[Javascript Checkout 1]]></title><description><![CDATA[In which you get to read along while I work on a popular code kata]]></description><link>https://habitablecode.substack.com/p/javascript-checkout-1</link><guid isPermaLink="false">https://habitablecode.substack.com/p/javascript-checkout-1</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 16 Sep 2022 07:00:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!DT7o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Back in early 2015, on my old blog, I ran a series of articles in which I implemented a solution to a popular code kata. I followed the strict test-driven development (TDD) cycle, and when it came to the REFACTOR step I tried to drive all of my choices using connascence. After 7 or 8 articles we (me and the regular commenters) ended up quibbling over which kinds of connascence I had, which should be tackled first, etc. It was a useful exercise, because we all learned a lot about connascence and how to deal with it.</p><p>So now, like a glutton for punishment, I&#8217;m going to do something similar again.</p><p>I&#8217;m going to tackle <a href="http://codekata.com/kata/kata09-back-to-the-checkout/">Dave Thomas&#8217;s Back to the Checkout kata</a> (again). I&#8217;m going to show you every step of the way while documenting my thinking as openly and as accurately as I can. I want to explore TDD&#8217;s REFACTOR step again, this time from the point of view of the 4 rules of simple design and with a particular focus on making the implicit explicit. And because this will be quite a long series of articles I&#8217;ll be chucking them at you twice each week instead of the usual once. (You lucky people.)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DT7o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DT7o!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg 424w, https://substackcdn.com/image/fetch/$s_!DT7o!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg 848w, https://substackcdn.com/image/fetch/$s_!DT7o!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!DT7o!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DT7o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg" width="544" height="308.125" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:580,&quot;width&quot;:1024,&quot;resizeWidth&quot;:544,&quot;bytes&quot;:76607,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DT7o!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg 424w, https://substackcdn.com/image/fetch/$s_!DT7o!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg 848w, https://substackcdn.com/image/fetch/$s_!DT7o!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!DT7o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3c0283ff-b5b0-431e-a41c-225960f16779_1024x580.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://www.flickr.com/photos/britsinvade/4761163712">Rob Taylor</a></figcaption></figure></div><p>And if it goes well &#8212; and maybe also if it doesn&#8217;t &#8212; I&#8217;ll probably do it again in a different (kind of) programming language. Because I think an important part of knowing how to refactor is also knowing how language affordances enable or disable the various solution patterns we might consider.</p><p>For this first run through I want to use a popular language, and one in which types are not explicitly visible in the source code. In 2015 I used Java, and thus the explicit types helped make some kinds of coupling easier to see and easier to fix. This time I&#8217;m going with Javascript, and I hypothesise here and now that I&#8217;ll find fewer solution options when attempting to eradicate Connascence of Position, for example (if it arises). No doubt we&#8217;ll see.</p><p>I&#8217;m going to follow Dave Thomas&#8217;s lead from the original kata statement and implement my tests strictly in the order he presents them.</p><p>So without further ado, here&#8217;s my first test:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IURm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IURm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png 424w, https://substackcdn.com/image/fetch/$s_!IURm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png 848w, https://substackcdn.com/image/fetch/$s_!IURm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png 1272w, https://substackcdn.com/image/fetch/$s_!IURm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IURm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png" width="575" height="94" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:94,&quot;width&quot;:575,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12680,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IURm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png 424w, https://substackcdn.com/image/fetch/$s_!IURm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png 848w, https://substackcdn.com/image/fetch/$s_!IURm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png 1272w, https://substackcdn.com/image/fetch/$s_!IURm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F07fb0a37-b2dc-41ae-a8c6-62fa6e625bd9_575x94.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And when I run it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e_hn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e_hn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png 424w, https://substackcdn.com/image/fetch/$s_!e_hn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png 848w, https://substackcdn.com/image/fetch/$s_!e_hn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png 1272w, https://substackcdn.com/image/fetch/$s_!e_hn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e_hn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png" width="571" height="420" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/a87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:420,&quot;width&quot;:571,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53768,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!e_hn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png 424w, https://substackcdn.com/image/fetch/$s_!e_hn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png 848w, https://substackcdn.com/image/fetch/$s_!e_hn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png 1272w, https://substackcdn.com/image/fetch/$s_!e_hn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa87c6e20-1763-47d7-a6f6-18118ccf16ad_571x420.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>(I&#8217;m using ES6, and Jest, and make. Because those are the tools I&#8217;m comfortable with.)</p><p>Some might say that a test that doesn&#8217;t compile isn&#8217;t a &#8220;failing test&#8221; in the terms of TDD. I beg to differ, and we&#8217;ll explore that topic a little more in a moment.</p><p>But first I&#8217;m going to commit this: <code>Install toolchain and write first failing test</code>. You can follow along with these commits via the public git repository at <a href="https://github.com/kevinrutherford/hc-js-checkout">https://github.com/kevinrutherford/hc-js-checkout</a>, where you can also look into my <code>Makefile</code> and other details of my toolchain. (For the most part I expect that stuff to not be relevant to the problem we&#8217;re exploring here, so I probably won&#8217;t mention it again.) Note that due to holiday and work commitments I&#8217;m writing these articles in batches a few weeks ahead of publication time; so in the repo you&#8217;ll already be able to see where this is going, if you want to look ahead.</p><p>Now, what to do about that failing test&#8230;</p><p>I&#8217;m going to adopt Keith Braithwaite&#8217;s <a href="https://cumulative-hypotheses.org/2011/08/30/tdd-as-if-you-meant-it/">TDD as if you meant it</a> style. TDDAIYMI has the following, stricter, rules:</p><ol><li><p>Write <em>exactly one</em> new test, the smallest test you can that seems to point in the direction of a solution</p></li><li><p>See it fail</p></li><li><p>Make the test from (1) pass by writing the least implementation code you can <em>in the test method.&nbsp;</em></p></li><li><p>Refactor to remove duplication, and otherwise as required to improve the design.&nbsp;Be strict about using these moves:</p><ol><li><p><strong>you want a new method&#8212;wait until refactoring time, then&#8230;&nbsp;</strong>create new (non-test) methods by doing one of these, and in no other way:</p><ol><li><p>preferred: do Extract Method on implementation code created as per (3) to create a new method in the test class, or</p></li><li><p>if you must: move implementation code as per (3) into an existing implementation method</p></li></ol></li><li><p><strong>you want a new class&#8212;wait until refactoring time, then&#8230;&nbsp;</strong>create non-test classes to provide a destination for a Move&nbsp;Method and for no other reason</p><ol><li><p>populate implementation classes with methods by doing Move Method, and no other way</p></li></ol></li></ol></li></ol><p>Keith doesn&#8217;t recommend that we do this in our day job, but in my context here it feels like exactly the right choice. By following these rules I will be forced to refactor my solution into existence, without the aid of any magical starting design that I would then need to justify.</p><p>So I change my failing test as per Keith&#8217;s rule 3:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pQjM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pQjM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png 424w, https://substackcdn.com/image/fetch/$s_!pQjM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png 848w, https://substackcdn.com/image/fetch/$s_!pQjM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png 1272w, https://substackcdn.com/image/fetch/$s_!pQjM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pQjM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png" width="572" height="108" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:108,&quot;width&quot;:572,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14799,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pQjM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png 424w, https://substackcdn.com/image/fetch/$s_!pQjM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png 848w, https://substackcdn.com/image/fetch/$s_!pQjM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png 1272w, https://substackcdn.com/image/fetch/$s_!pQjM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9a496cc-4714-41f4-a1e8-e98ce7c04e86_572x108.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And viol&#224;:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!97xq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!97xq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png 424w, https://substackcdn.com/image/fetch/$s_!97xq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png 848w, https://substackcdn.com/image/fetch/$s_!97xq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png 1272w, https://substackcdn.com/image/fetch/$s_!97xq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!97xq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png" width="567" height="179" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:179,&quot;width&quot;:567,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24145,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!97xq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png 424w, https://substackcdn.com/image/fetch/$s_!97xq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png 848w, https://substackcdn.com/image/fetch/$s_!97xq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png 1272w, https://substackcdn.com/image/fetch/$s_!97xq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4bf9a520-2733-4ae7-b4af-54ed7eef29ff_567x179.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Commit: <code>Pass the test in TDDAIYMI style</code>.</p><p>Does this feel like &#8220;cheating&#8221;? It&#8217;s thought-provoking though, isn&#8217;t it? I have a passing test, and yet I&#8217;ve done much less &#8220;design&#8221; than I might usually have done. And hopefully the point of this will become clear after the next couple of tests and refactoring steps.</p><p>Speaking of which&#8230; Can you see any refactoring that needs to be done? Actually, now you mention it, I&#8217;m looking at the test description in the <code>make</code> output and thinking that &#8220;back to the checkout has zero price before items are scanned&#8221; doesn&#8217;t make a lot of sense. I go back to Dave Thomas&#8217;s Ruby example and realise I haven&#8217;t quite transliterated his intention correctly. So I refactor the test to be this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5K2I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5K2I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png 424w, https://substackcdn.com/image/fetch/$s_!5K2I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png 848w, https://substackcdn.com/image/fetch/$s_!5K2I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png 1272w, https://substackcdn.com/image/fetch/$s_!5K2I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5K2I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png" width="575" height="140" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:140,&quot;width&quot;:575,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19235,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5K2I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png 424w, https://substackcdn.com/image/fetch/$s_!5K2I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png 848w, https://substackcdn.com/image/fetch/$s_!5K2I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png 1272w, https://substackcdn.com/image/fetch/$s_!5K2I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3d5888c3-38b7-446c-b050-5f91ef64acf2_575x140.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now the test run tells a better story:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ftr2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ftr2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png 424w, https://substackcdn.com/image/fetch/$s_!ftr2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png 848w, https://substackcdn.com/image/fetch/$s_!ftr2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png 1272w, https://substackcdn.com/image/fetch/$s_!ftr2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ftr2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png" width="569" height="194" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:194,&quot;width&quot;:569,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25388,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ftr2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png 424w, https://substackcdn.com/image/fetch/$s_!ftr2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png 848w, https://substackcdn.com/image/fetch/$s_!ftr2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png 1272w, https://substackcdn.com/image/fetch/$s_!ftr2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3200fe5c-7b1a-4402-b00c-c027711ce01e_569x194.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I wish this output had less noise, so please drop in a comment if you have Jest tooling that can do that. For now, I can commit: <code>Tell a better story when the test runs</code>.</p><p>I think that&#8217;s it for refactoring at this stage. So let&#8217;s move onto Dave&#8217;s next test:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9pUC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9pUC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png 424w, https://substackcdn.com/image/fetch/$s_!9pUC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png 848w, https://substackcdn.com/image/fetch/$s_!9pUC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png 1272w, https://substackcdn.com/image/fetch/$s_!9pUC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9pUC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png" width="577" height="62" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:62,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8647,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9pUC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png 424w, https://substackcdn.com/image/fetch/$s_!9pUC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png 848w, https://substackcdn.com/image/fetch/$s_!9pUC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png 1272w, https://substackcdn.com/image/fetch/$s_!9pUC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F37feae5e-a43c-4ae7-b4ee-1421d02dcecc_577x62.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>So, this is where TDDAIYMI really kicks us hard. To get this to pass I&#8217;m going to have to somehow represent <em>in the test</em> that I scan an &#8220;A&#8221; and get a price of 50. Well, this is still TDD, so I should be getting this to pass without doing much &#8212; if indeed, any &#8212; design in my head. How about this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Xr-2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Xr-2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png 424w, https://substackcdn.com/image/fetch/$s_!Xr-2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png 848w, https://substackcdn.com/image/fetch/$s_!Xr-2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png 1272w, https://substackcdn.com/image/fetch/$s_!Xr-2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Xr-2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png" width="580" height="109" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:109,&quot;width&quot;:580,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15334,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Xr-2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png 424w, https://substackcdn.com/image/fetch/$s_!Xr-2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png 848w, https://substackcdn.com/image/fetch/$s_!Xr-2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png 1272w, https://substackcdn.com/image/fetch/$s_!Xr-2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8b9a6f-5e26-4343-b2f9-34b5c4b64f11_580x109.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This feels like it tells the story intended by the test: We begin with a zero total, then we scan an &#8220;A&#8221; and then the total price becomes 50. (The const <code>itemsScanned</code> is highlighted because vim is helpfully telling me that it isn&#8217;t used.)</p><p>All tests pass:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lUVg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lUVg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png 424w, https://substackcdn.com/image/fetch/$s_!lUVg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png 848w, https://substackcdn.com/image/fetch/$s_!lUVg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png 1272w, https://substackcdn.com/image/fetch/$s_!lUVg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lUVg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png" width="571" height="209" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:209,&quot;width&quot;:571,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29410,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lUVg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png 424w, https://substackcdn.com/image/fetch/$s_!lUVg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png 848w, https://substackcdn.com/image/fetch/$s_!lUVg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png 1272w, https://substackcdn.com/image/fetch/$s_!lUVg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4834b5e-6a5e-431d-b3d5-0b258a5c1eed_571x209.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>So I commit: <code>Get the correct price when scanning an A</code>.</p><p>Now it&#8217;s time to refactor, and this is the moment when TDDAIYMI pays off. This code now violates the 4 rules &#8212; in particular the Once And Only Once rule. <a href="https://habitablecode.substack.com/p/javascript-checkout-2">Next time</a> we&#8217;ll fix that &#8212; but in the meantime drop me a comment: what would you refactor now, and why?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/javascript-checkout-1/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/javascript-checkout-1/comments"><span>Leave a comment</span></a></p><h2>Things to try</h2><p>Take half an hour to do a (different) kata using the TDDAIYMI style. What did you learn about your usual programming style? Or about how much &#8220;design&#8221; you do without consciously calling it out?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Incoming: The coupling that wasn't there]]></title><description><![CDATA[Expressing intentions via explicit coupling.]]></description><link>https://habitablecode.substack.com/p/incoming-the-coupling-that-wasnt</link><guid isPermaLink="false">https://habitablecode.substack.com/p/incoming-the-coupling-that-wasnt</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 09 Sep 2022 07:00:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!daWK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As you may know from earlier articles, I have a side project to build a wiki. There is an API, which won&#8217;t concern us today, and a single page application (SPA), which will. The SPA is written in Typescript and React. Wiki page contents are written in Markdown, to which I&#8217;ve added two bespoke extensions:</p><ol><li><p>Every occurrence of text such as <code>[[Habitable Code]]</code> is replaced in the rendered page by a hyperlink; when the link is clicked, it opens the wiki page with that title. Fairly standard for a wiki.</p></li><li><p>A wiki page can also contain content that is calculated dynamically, at the time the page is rendered. This occurs whenever the page&#8217;s Markdown content includes text of the form <code>[macro: f]</code>, where <em>f</em> is one of <code>Incoming</code>, <code>Search</code>, <code>MissingPages</code>, <code>Orphans</code>, <code>RecentChanges</code> and a few others. <code>Incoming</code> is particularly useful for <a href="https://wiki.c2.com/?CategoryCategory">Category pages</a>, for example.</p></li></ol><p>This is the top part of a rendered page:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4DZA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4DZA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png 424w, https://substackcdn.com/image/fetch/$s_!4DZA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png 848w, https://substackcdn.com/image/fetch/$s_!4DZA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png 1272w, https://substackcdn.com/image/fetch/$s_!4DZA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4DZA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png" width="511" height="207" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:207,&quot;width&quot;:511,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21835,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4DZA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png 424w, https://substackcdn.com/image/fetch/$s_!4DZA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png 848w, https://substackcdn.com/image/fetch/$s_!4DZA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png 1272w, https://substackcdn.com/image/fetch/$s_!4DZA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F152e8f43-e8a8-4aa2-8e69-62a2a4217540_511x207.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Everything below the title is rendered by a <code>Hypercard</code> React component. Here&#8217;s a CRC card for <code>Hypercard</code>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!daWK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!daWK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png 424w, https://substackcdn.com/image/fetch/$s_!daWK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png 848w, https://substackcdn.com/image/fetch/$s_!daWK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png 1272w, https://substackcdn.com/image/fetch/$s_!daWK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!daWK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png" width="556" height="300.70640176600443" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:735,&quot;width&quot;:1359,&quot;resizeWidth&quot;:556,&quot;bytes&quot;:114627,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!daWK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png 424w, https://substackcdn.com/image/fetch/$s_!daWK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png 848w, https://substackcdn.com/image/fetch/$s_!daWK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png 1272w, https://substackcdn.com/image/fetch/$s_!daWK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1e705b-25db-42bd-8925-2ece69635779_1359x735.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>And if the reader clicks the page&#8217;s title, that <code>Hypercard</code> is replaced by a <code>PageMetadata</code> component, which among other things displays a list of the pages that link to this page:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8RHA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8RHA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png 424w, https://substackcdn.com/image/fetch/$s_!8RHA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png 848w, https://substackcdn.com/image/fetch/$s_!8RHA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png 1272w, https://substackcdn.com/image/fetch/$s_!8RHA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8RHA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png" width="509" height="232" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:232,&quot;width&quot;:509,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14349,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8RHA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png 424w, https://substackcdn.com/image/fetch/$s_!8RHA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png 848w, https://substackcdn.com/image/fetch/$s_!8RHA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png 1272w, https://substackcdn.com/image/fetch/$s_!8RHA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2c45e1f-1229-4c23-90e8-2a796f0d4561_509x232.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>Here&#8217;s a CRC card for <code>PageMetadata</code>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WBZy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WBZy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png 424w, https://substackcdn.com/image/fetch/$s_!WBZy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png 848w, https://substackcdn.com/image/fetch/$s_!WBZy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png 1272w, https://substackcdn.com/image/fetch/$s_!WBZy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WBZy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png" width="536" height="289.88962472406183" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:735,&quot;width&quot;:1359,&quot;resizeWidth&quot;:536,&quot;bytes&quot;:89526,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WBZy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png 424w, https://substackcdn.com/image/fetch/$s_!WBZy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png 848w, https://substackcdn.com/image/fetch/$s_!WBZy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png 1272w, https://substackcdn.com/image/fetch/$s_!WBZy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35d783e1-92f3-47a6-8818-2a0b2c823806_1359x735.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>The problem</h2><p>We can see that <code>Hypercard</code> and <code>PageMetadata</code> share a responsibility and at least one collaborator.</p><p>Here&#8217;s the current source code of the <code>PageMetadata</code> component:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0CVB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0CVB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png 424w, https://substackcdn.com/image/fetch/$s_!0CVB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png 848w, https://substackcdn.com/image/fetch/$s_!0CVB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png 1272w, https://substackcdn.com/image/fetch/$s_!0CVB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0CVB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png" width="575" height="154" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:154,&quot;width&quot;:575,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20506,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0CVB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png 424w, https://substackcdn.com/image/fetch/$s_!0CVB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png 848w, https://substackcdn.com/image/fetch/$s_!0CVB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png 1272w, https://substackcdn.com/image/fetch/$s_!0CVB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32e4af4-1ea9-402a-81e1-c46924b24606_575x154.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>But reference to that <code>&lt;Incoming /&gt;</code> component represents knowledge of how a <code>Hypercard</code> renders incoming links. So <code>PageMetadata</code> knows how to insert a list of incoming wiki links into the display, and so does <code>Hypercard</code>; they both use the <code>Incoming</code> React component. <code>PageMetadata</code> has &#8220;borrowed&#8221; part of the internal implementation of <code>Hypercard</code>.</p><p>I find these problems quite difficult to think about, so I made a diagram to help me:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!h2sD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!h2sD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png 424w, https://substackcdn.com/image/fetch/$s_!h2sD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png 848w, https://substackcdn.com/image/fetch/$s_!h2sD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png 1272w, https://substackcdn.com/image/fetch/$s_!h2sD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!h2sD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png" width="502" height="327.9029911075182" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:808,&quot;width&quot;:1237,&quot;resizeWidth&quot;:502,&quot;bytes&quot;:63497,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!h2sD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png 424w, https://substackcdn.com/image/fetch/$s_!h2sD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png 848w, https://substackcdn.com/image/fetch/$s_!h2sD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png 1272w, https://substackcdn.com/image/fetch/$s_!h2sD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F59527104-02e8-4934-9d9d-1c2449ddd4c1_1237x808.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We can see why it&#8217;s a problem if we consider what might change and potentially break this code. <code>Hypercard</code> could replace its use of <code>Incoming</code> with something different, having a different display or using a different API endpoint. <code>PageMetadata</code> could do that too. And yet that&#8217;s not what my Customer wants. I checked with him (me), and he wants both <code>Hypercard</code> and <code>PageMetadata</code> to calculate and display the incoming links in the same way.</p><p>This is a very important observation, and probably the key takeaway from this article: The <em>intended</em> coupling in this code comes directly from the Customer. We have a <em>requirement</em> that these two components display the same set of incoming links, calculated the same way and displayed the same way; and we have a <em>requirement</em> that they continue to evolve together (at least for the foreseeable future). And so there must be a single place in the code that reflects that requirement. The code should say &#8220;here&#8217;s the one decision that dictates the behaviour of A and B&#8221;; whereas the code we have says &#8220;currently A and B are independently choosing to use the same helper&#8221;.</p><p>I get a huge amount of benefit when I can relate coupling directly back to something from the Customer. I wonder:</p><p><em><strong>Is it generally true that things should be coupled in the code if, and only if, the Customer wants them coupled in the application&#8217;s behaviour?</strong></em></p><p>Another way to say the same thing: We have explicit coupling, but it is of the implementations, not the intent. The Customer&#8217;s intended coupling is missing (or is implicit at best). There is no representation in the code of the coupling we wish we had.</p><h2>Solution options</h2><p>We can now see that the problem here is not the coupling <em>per se</em>, but the fact that the coupling we currently have is &#8220;accidental&#8221;.  So how can I change that? How can I guarantee that both <code>Hypercard</code> and <code>PageMetadata</code> use the same <code>Incoming</code> component? And could I write a test for that? I think there is a choice between two general approaches to problems such as this:</p><ol><li><p>Arrange for some other code to supply both <code>PageMetadata</code> and <code>Hypercard</code> with the tools to be used for displaying incoming links.</p></li><li><p>Have one thing use the other &#8212; in this case, <code>PageMetadata</code> could use <code>Hypercard</code>.</p></li></ol><p>In our case here, option 1 won&#8217;t scale. Based on the history of this codebase, it seems quite likely that my Customer will want <code>PageMetadata</code> to evolve and display other stuff. Injecting one common algorithm now feels like a short-term solution; soon I will probably need to inject more and more.</p><p>So instead I&#8217;m going to adopt the second approach. I rewrite <code>PageMetadata</code> to be this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jvQS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jvQS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png 424w, https://substackcdn.com/image/fetch/$s_!jvQS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png 848w, https://substackcdn.com/image/fetch/$s_!jvQS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png 1272w, https://substackcdn.com/image/fetch/$s_!jvQS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jvQS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png" width="577" height="199" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:199,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25247,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jvQS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png 424w, https://substackcdn.com/image/fetch/$s_!jvQS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png 848w, https://substackcdn.com/image/fetch/$s_!jvQS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png 1272w, https://substackcdn.com/image/fetch/$s_!jvQS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0af8f591-64db-43d6-a5e0-f9e666b83685_577x199.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>By making this change I have clearly and explicitly stated that <code>PageMetadata</code> delegates to <code>Hypercard</code>, and thereby makes use of all of its current and future capabilities.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!08r7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!08r7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png 424w, https://substackcdn.com/image/fetch/$s_!08r7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png 848w, https://substackcdn.com/image/fetch/$s_!08r7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png 1272w, https://substackcdn.com/image/fetch/$s_!08r7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!08r7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png" width="534" height="348.80517380759903" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:808,&quot;width&quot;:1237,&quot;resizeWidth&quot;:534,&quot;bytes&quot;:63440,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!08r7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png 424w, https://substackcdn.com/image/fetch/$s_!08r7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png 848w, https://substackcdn.com/image/fetch/$s_!08r7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png 1272w, https://substackcdn.com/image/fetch/$s_!08r7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7f974055-2576-4848-b1af-24b92db0d6a6_1237x808.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In connascence terms, I&#8217;ve replaced Connascence of Algorithm by Connascence of Name and Type. I don&#8217;t find that to be as helpful as saying this:</p><blockquote><p>I&#8217;ve represented the Customer&#8217;s intention explicitly, once and only once, in a single line of code.</p></blockquote><p>And now that the code looks like this, it seems to me that I don&#8217;t need a test. Unless I want to capture the Customer&#8217;s requirement, of course. Would you write a test here?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/incoming-the-coupling-that-wasnt/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/incoming-the-coupling-that-wasnt/comments"><span>Leave a comment</span></a></p><h2>Root causes</h2><p>Let&#8217;s step back for a moment and look at how this problem came to be in the code.</p><p>Obviously the first step would have been for me to ask the Customer how closely the <code>PageMetadata</code> display should be coupled to that of the <code>Hypercard</code>. This is something that software developers rarely do, and yet establishing the intended coupling in the requirements is an important part of the analysis of any user story, and getting it right can avoid huge amounts of future rework. It can be as simple as checking &#8220;Should these two domain concepts evolve together?&#8221; Of course, such questions weren&#8217;t necessary in the days when we perfected our requirements specification at the start of the project, and so I suspect we&#8217;ve simply forgotten to add it to our habits now that our software evolves iteratively and incrementally.</p><p>But there&#8217;s also another contributory factor in this case, and again it&#8217;s something I see in a lot of codebases: <code>Hypercard</code> and its helpers were all just sitting around, mixed in with all of the other React components in the same source folder. Even though the helpers are &#8212; conceptually and practically &#8212; <em>part of the implementation</em> of <code>Hypercard</code>, this was not reflected in the way these components were organised in the codebase. This problem is also evident in the CRC card shown above for <code>Hypercard</code>: those helper components should not be listed as collaborators, because the intention is that they are implementation details.</p><p>Again, the intended coupling &#8212; this time it&#8217;s the developer&#8217;s intention &#8212; was not represented explicitly in the codebase in any way. And this made it easy for <code>PageMetadata</code> to &#8220;reuse&#8221; the <code>Incoming</code> component, despite the intention that, logically, <code>Incoming</code> is &#8220;part of&#8221; the implementation of <code>Hypercard</code>.</p><p>In fact, this is how I noticed this problem. I was tired of having to sift through the huge, flat mess of components; I wanted to find groupings and patterns among them. As part of this effort I had decided that <code>Hypercard</code> and its helpers should form a single <em>encapsulation unit</em> and I was moving them all into a new source folder. And that meant I had to change the import statement in <code>PageMetadata</code>, which struck me as odd. And so here we are.</p><h2>Prevention</h2><p>So <code>PageMetadata</code> made use of <code>Incoming</code>, but should that even have been possible? The code is obviously not clear enough about the fact that <code>Incoming</code> is &#8220;part of&#8221; <code>Hypercard</code>, so should <code>Incoming</code> be invisible to any and all other components? And if so, how could I express that in Typescript?</p><p>Again, I can think of two options (I&#8217;m not a Typescript expert, so please let me know in the comments if I missed something):</p><ol><li><p>I could make <code>Hypercard</code> a class component and have the helpers be private members of that class. But <code>Hypercard</code> would then be huge. And private methods aren&#8217;t (easily) testable.</p></li><li><p>Or I could create a folder for <code>Hypercard</code> and its helpers, but export only <code>Hypercard</code> from the folder&#8217;s <code>index.ts</code>. That doesn&#8217;t enforce anything, but as a convention it has merits. The folder represents the encapsulation unit, and the <code>index.ts</code> represents its public interface. I could see at a glance if any source file imported from something like <code>&#8216;../Hypercard/Incoming&#8217;</code> so that would be a red flag.</p></li></ol><p>In fact I&#8217;ve chosen option 2 and it seems to be working so far. It&#8217;s an Explicit solution, but only by convention.</p><h2>Recapping</h2><p>So to recap, my code had two instances of Implicit Coupling: Firstly, the intention that two rendered components should in future evolve together. And secondly, that certain components were internal to the implementation of another and should not be used outside of that context. (How would you express those in the language of connascence? Or in terms of code smells?)</p><p>In both cases I&#8217;ve tried to find a way for the code to make that intended coupling Explicit, so that it can be read <em>locally</em>, once and only once in the codebase.</p><h2>Things to try</h2><ol><li><p>In your next user story conversation be sure to discuss how the various domain concepts are likely to evolve in relation to each other. Then try to express that intention in your code.</p></li><li><p>If you have a module like <code>Hypercard</code>, that consists of more than one encapsulation unit, find a way to encapsulate the whole lot very obviously in your codebase.</p></li></ol><p>Try fixing similar problems in your code and practices today; and please leave a comment sharing your results.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Functions with multiple parameters]]></title><description><![CDATA[Looking at one aspect of Connascence of Position]]></description><link>https://habitablecode.substack.com/p/functions-with-multiple-parameters</link><guid isPermaLink="false">https://habitablecode.substack.com/p/functions-with-multiple-parameters</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 02 Sep 2022 07:00:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!f8sJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Okay, it&#8217;s time for a survey article. This is the kind of article that I hinted at in <a href="https://habitablecode.substack.com/p/if-this-were-a-book">If this were a book</a>. The general plan of attack in articles like this will be:</p><ol><li><p>Outline a single simple example of implicit coupling.</p></li><li><p>Explore solution options in a wide variety of different (types of) programming languages.</p></li></ol><p>This could all go horribly wrong, so please bear with. I have no idea where this might take us. But I haven&#8217;t seen this done anywhere else before &#8212; not even Martin Fowler has written anything similar, so we&#8217;re on our own. I think it&#8217;s fairly inevitable that I&#8217;ll miss things, so please do chip in when you see something I haven&#8217;t thought to consider&#8230;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/functions-with-multiple-parameters/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/functions-with-multiple-parameters/comments"><span>Leave a comment</span></a></p><p>The example I want to use today is that of a function that takes two parameters of the same type or no type. The caller&#8217;s code is coupled to the parameter order, because passing them in the wrong order would mean that the function will probably do something unintended <em>at runtime</em>. The coupling is usually implicit, so how can we arrange the function&#8217;s signature so that it is obvious in the caller&#8217;s code how the values supplied map to the function&#8217;s parameters?</p><p>Note that even if the function checks the values it was passed and rejects them &#8212; for example by throwing an exception &#8212; when they are invalid, that&#8217;s a runtime check. It places nothing explicit in the <em>caller&#8217;s</em> code to clean up the coupling.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!f8sJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!f8sJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg 424w, https://substackcdn.com/image/fetch/$s_!f8sJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg 848w, https://substackcdn.com/image/fetch/$s_!f8sJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!f8sJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!f8sJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg" width="454" height="428.28515625" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/aa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:966,&quot;width&quot;:1024,&quot;resizeWidth&quot;:454,&quot;bytes&quot;:174210,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!f8sJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg 424w, https://substackcdn.com/image/fetch/$s_!f8sJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg 848w, https://substackcdn.com/image/fetch/$s_!f8sJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!f8sJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faa68e358-7509-4e02-ad46-cb61dd2718be_1024x966.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Annielogue, CC BY 3.0 &lt;https://creativecommons.org/licenses/by/3.0&gt;, via Wikimedia Commons</figcaption></figure></div><h2>Solution options</h2><p>Solutions to this problem naturally all involve changing the function signature. It seems to me that we have a few options, depending on what our programming language supports:</p><ol><li><p>Change the types of the parameters to be different.</p></li><li><p>Use named parameters.</p></li><li><p>Don&#8217;t pass two parameters: group them into a structure.</p></li><li><p>Don&#8217;t pass two parameters: split the call into parts.</p></li></ol><p>Let&#8217;s look at each of these options in turn&#8230;</p><h3>Parameters of different types</h3><p>This, of course, is only possible if our code is written in a language that has static typing. But it is also only possible if the parameters represent values taken from two different domain types. For example, in C# we might change</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!azBc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!azBc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png 424w, https://substackcdn.com/image/fetch/$s_!azBc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png 848w, https://substackcdn.com/image/fetch/$s_!azBc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png 1272w, https://substackcdn.com/image/fetch/$s_!azBc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!azBc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png" width="573" height="48" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/cac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:48,&quot;width&quot;:573,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7769,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!azBc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png 424w, https://substackcdn.com/image/fetch/$s_!azBc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png 848w, https://substackcdn.com/image/fetch/$s_!azBc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png 1272w, https://substackcdn.com/image/fetch/$s_!azBc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcac99037-3ebe-4f36-bc63-c501129f99f5_573x48.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>to</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!j2TR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j2TR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png 424w, https://substackcdn.com/image/fetch/$s_!j2TR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png 848w, https://substackcdn.com/image/fetch/$s_!j2TR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png 1272w, https://substackcdn.com/image/fetch/$s_!j2TR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j2TR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png" width="574" height="48" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e2f6287c-6d39-4308-911b-5e059652251c_574x48.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:48,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8073,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!j2TR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png 424w, https://substackcdn.com/image/fetch/$s_!j2TR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png 848w, https://substackcdn.com/image/fetch/$s_!j2TR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png 1272w, https://substackcdn.com/image/fetch/$s_!j2TR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2f6287c-6d39-4308-911b-5e059652251c_574x48.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>In this particular case this has the additional advantage that we&#8217;ve addressed some <strong>Primitive Obsession</strong>, but that won&#8217;t always be true.</p><p>But the most important aspect of this refactoring is whether we can now see the coupling explicitly in the caller&#8217;s code. And we can, because the caller must arrange to have instances of those new types available. So the caller will also change, to something like:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_wY0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_wY0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png 424w, https://substackcdn.com/image/fetch/$s_!_wY0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png 848w, https://substackcdn.com/image/fetch/$s_!_wY0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png 1272w, https://substackcdn.com/image/fetch/$s_!_wY0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_wY0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png" width="574" height="46" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:46,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14113,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_wY0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png 424w, https://substackcdn.com/image/fetch/$s_!_wY0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png 848w, https://substackcdn.com/image/fetch/$s_!_wY0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png 1272w, https://substackcdn.com/image/fetch/$s_!_wY0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1dfa2eef-4eca-487a-b4c7-b87e70143b92_574x46.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Thus at both ends of the coupling I can see the exactly what might break, without having to run a compiler or tests or the application itself.</p><p>However, if our language doesn&#8217;t allow for static types we could perhaps offer named parameters&#8230;</p><h3>Named parameters</h3><p>Some languages such as Ruby, C#, Clojure, Python etc allow the function to state that the caller must provide names when passing parameters.</p><p>So for example</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Iprp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Iprp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png 424w, https://substackcdn.com/image/fetch/$s_!Iprp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png 848w, https://substackcdn.com/image/fetch/$s_!Iprp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png 1272w, https://substackcdn.com/image/fetch/$s_!Iprp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Iprp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png" width="574" height="108" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ac327721-f505-49be-849d-fcb734cbb7f1_574x108.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:108,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15460,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Iprp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png 424w, https://substackcdn.com/image/fetch/$s_!Iprp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png 848w, https://substackcdn.com/image/fetch/$s_!Iprp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png 1272w, https://substackcdn.com/image/fetch/$s_!Iprp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac327721-f505-49be-849d-fcb734cbb7f1_574x108.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This allows the caller to pass the parameters in any order, and again the coupling has been made locally explicit in the caller&#8217;s code.</p><p>However, if our language doesn&#8217;t allow for static types or named parameters we&#8217;ll need to change the number of parameters instead.</p><p>Over the years I&#8217;ve observed that code that is more habitable tends to have very few functions with more than one parameter. So I do generally feel that my preferred option, regardless of the programming language facilities I have available, is to group parameters into a structure or split the call into parts that have only one parameter each.</p><h3>Pass a structure</h3><p>If we can&#8217;t statically type our parameters, or give them static names &#8212; as, for example, in Javascript &#8212; we have no option but to avoid having multiple parameters at all. Most languages allow us to group things into larger structures, so we could do this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rrv2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rrv2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png 424w, https://substackcdn.com/image/fetch/$s_!rrv2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png 848w, https://substackcdn.com/image/fetch/$s_!rrv2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png 1272w, https://substackcdn.com/image/fetch/$s_!rrv2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rrv2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png" width="576" height="137" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:137,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17979,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rrv2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png 424w, https://substackcdn.com/image/fetch/$s_!rrv2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png 848w, https://substackcdn.com/image/fetch/$s_!rrv2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png 1272w, https://substackcdn.com/image/fetch/$s_!rrv2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F98e33e0a-5bd9-4881-80c5-ab5bbb22cf9d_576x137.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>As with all of the other options, the caller has to change such that it explicitly names the parameters, and so the Connascence of Position goes away.</p><p>I suspect many programmers might object to the additional syntax and dereferencing needed here, saying that the two-parameter version is simpler. But for me, that&#8217;s not what &#8220;simple&#8221; means. In the <a href="https://habitablecode.substack.com/p/diving-into-the-4-rules-of-simple">4 Rules of Simple Design</a>, brevity is our <em>lowest</em> priority. Here I&#8217;m adding syntax in order to make some coupling explicit. So this code tells the story better, and also is kinder to the caller.</p><h3>Split the call</h3><p>The major alternative to passing a structure is to split the function into two functions, usually arranged such that the second function is called on something that has the first parameter as internal state. Think of the <strong>Builder</strong> pattern, which is common in the Java and C# worlds.</p><p>In the Customer example I&#8217;ve been using in this article I don&#8217;t need anything as sophisticated as a <strong>Builder</strong>, because I can easily (I assume) split this function into two like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SVWt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SVWt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png 424w, https://substackcdn.com/image/fetch/$s_!SVWt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png 848w, https://substackcdn.com/image/fetch/$s_!SVWt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png 1272w, https://substackcdn.com/image/fetch/$s_!SVWt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SVWt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png" width="575" height="136" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:136,&quot;width&quot;:575,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12767,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SVWt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png 424w, https://substackcdn.com/image/fetch/$s_!SVWt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png 848w, https://substackcdn.com/image/fetch/$s_!SVWt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png 1272w, https://substackcdn.com/image/fetch/$s_!SVWt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb72fdd0a-491d-4d1e-9d42-00849c33160b_575x136.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>(Example in Ruby, but would work in any other language similarly.)</p><p>But what if there is more of a semantic connection between the two values? We&#8217;ll usually need objects or Builders or monads in order to accomplish this. For example suppose I have this Javascript code:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CLNq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CLNq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png 424w, https://substackcdn.com/image/fetch/$s_!CLNq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png 848w, https://substackcdn.com/image/fetch/$s_!CLNq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png 1272w, https://substackcdn.com/image/fetch/$s_!CLNq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CLNq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png" width="578" height="152" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:152,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21203,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CLNq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png 424w, https://substackcdn.com/image/fetch/$s_!CLNq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png 848w, https://substackcdn.com/image/fetch/$s_!CLNq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png 1272w, https://substackcdn.com/image/fetch/$s_!CLNq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F294bec31-d2b7-44b2-817f-7530acee10a4_578x152.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I could consider refactoring like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e-Jq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e-Jq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png 424w, https://substackcdn.com/image/fetch/$s_!e-Jq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png 848w, https://substackcdn.com/image/fetch/$s_!e-Jq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png 1272w, https://substackcdn.com/image/fetch/$s_!e-Jq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e-Jq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png" width="576" height="271" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:271,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33236,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!e-Jq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png 424w, https://substackcdn.com/image/fetch/$s_!e-Jq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png 848w, https://substackcdn.com/image/fetch/$s_!e-Jq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png 1272w, https://substackcdn.com/image/fetch/$s_!e-Jq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1abb3f98-ccf4-4f61-8a3b-893fe1c43838_576x271.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Aficionados of code smells may look at this and cry &#8220;<strong>Method Chain</strong>!&#8221;, but note that the methods are received by two different objects of two different classes. In fact there&#8217;s a stronger case here for complaining about violation of the &#8220;law&#8221; of Demeter, because in the refactored code the caller is now coupled to the existence of shelves, and thereby possibly to implementation details of the Warehouse. Yes, I think that&#8217;s true in this case &#8212; so I would probably have been better taking a different route and introducing an object:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1lht!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1lht!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png 424w, https://substackcdn.com/image/fetch/$s_!1lht!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png 848w, https://substackcdn.com/image/fetch/$s_!1lht!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png 1272w, https://substackcdn.com/image/fetch/$s_!1lht!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1lht!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png" width="575" height="210" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:210,&quot;width&quot;:575,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:28335,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1lht!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png 424w, https://substackcdn.com/image/fetch/$s_!1lht!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png 848w, https://substackcdn.com/image/fetch/$s_!1lht!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png 1272w, https://substackcdn.com/image/fetch/$s_!1lht!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1ccb7e46-e286-4608-a34d-1c1e513dbee6_575x210.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>In most cases, where I can find reasonable domain terminology for the intermediate type(s) this approach can significantly improve the code&#8217;s ability to tell the customer&#8217;s story.</p><p>So that&#8217;s a very quick tour of some refactoring options for dealing with this one kind of Connascence of Position. I&#8217;ve probably missed a lot of possibilities, so please drop them in the comments where you see things I haven&#8217;t.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Things to try</h2><ul><li><p>Review your code for functions with more than one parameter and try each of the options above as an alternative design. What forces are at work to encourage you to pick one option over another? Is the cost of the refactoring worth the improvement in habitability?</p></li></ul><p>If you try this, please let us know in the comments. And please also point out those inevitable cases that I&#8217;ll likely have missed!</p>]]></content:encoded></item><item><title><![CDATA[TDD mistakes 3]]></title><description><![CDATA[Writing a dozen or more lines of code to get to GREEN]]></description><link>https://habitablecode.substack.com/p/tdd-mistakes-3</link><guid isPermaLink="false">https://habitablecode.substack.com/p/tdd-mistakes-3</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 26 Aug 2022 07:00:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Ygvm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Back in 2014 I wrote a blog post listing three mistakes often made by folks who are new to test-driven development (TDD). The three mistakes I identified are:</p><ol><li><p>Starting with error cases or null cases.</p></li><li><p>Writing tests for invented requirements.</p></li><li><p>Writing a dozen or more lines of code to get to GREEN.</p></li></ol><p>It was a very long post, so I&#8217;ve taken the three parts and expanded each into its own article, also incorporating the comments I received in 2014. This is part 3, and will deal with taking a step that&#8217;s too big&#8230;</p><p>When the bar is red and the path to green is long, TDD beginners often soldier on, writing an entire algorithm just to get one test to pass. This is highly risky, and also highly stressful. It is also not TDD.</p><p>Let&#8217;s look at an example. Suppose you have these tests (Java / JUnit):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cODD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cODD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png 424w, https://substackcdn.com/image/fetch/$s_!cODD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png 848w, https://substackcdn.com/image/fetch/$s_!cODD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png 1272w, https://substackcdn.com/image/fetch/$s_!cODD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cODD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png" width="578" height="241" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/a8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:241,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34890,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cODD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png 424w, https://substackcdn.com/image/fetch/$s_!cODD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png 848w, https://substackcdn.com/image/fetch/$s_!cODD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png 1272w, https://substackcdn.com/image/fetch/$s_!cODD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a39e30-eab4-4532-a16f-8efae2979bce_578x241.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>And suppose you have been writing the simplest possible thing that works, so your code looks something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ewg4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ewg4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png 424w, https://substackcdn.com/image/fetch/$s_!Ewg4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png 848w, https://substackcdn.com/image/fetch/$s_!Ewg4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png 1272w, https://substackcdn.com/image/fetch/$s_!Ewg4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ewg4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png" width="577" height="136" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:136,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15642,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Ewg4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png 424w, https://substackcdn.com/image/fetch/$s_!Ewg4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png 848w, https://substackcdn.com/image/fetch/$s_!Ewg4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png 1272w, https://substackcdn.com/image/fetch/$s_!Ewg4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1afe144a-7835-42b9-9c97-cf66f731fea9_577x136.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now imagine you picked this as the next test:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iEPm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iEPm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png 424w, https://substackcdn.com/image/fetch/$s_!iEPm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png 848w, https://substackcdn.com/image/fetch/$s_!iEPm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png 1272w, https://substackcdn.com/image/fetch/$s_!iEPm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iEPm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png" width="579" height="62" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:62,&quot;width&quot;:579,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12661,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iEPm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png 424w, https://substackcdn.com/image/fetch/$s_!iEPm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png 848w, https://substackcdn.com/image/fetch/$s_!iEPm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png 1272w, https://substackcdn.com/image/fetch/$s_!iEPm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8aafc9e7-3ab0-4cda-852f-6794cc60b290_579x62.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This is a huge leap from the current algorithm, as any attempt to code it up will demonstrate. Have a go yourself right now; go ahead, I&#8217;ll wait&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ygvm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ygvm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Ygvm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Ygvm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Ygvm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ygvm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg" width="566" height="375.859375" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:680,&quot;width&quot;:1024,&quot;resizeWidth&quot;:566,&quot;bytes&quot;:121050,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ygvm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Ygvm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Ygvm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Ygvm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F313a4673-3f4d-478f-b986-7c72a3d200c0_1024x680.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Libi Fishman, CC BY-SA 3.0 &lt;https://creativecommons.org/licenses/by-sa/3.0&gt;, via Wikimedia Commons</figcaption></figure></div><p>I think there are probably two fundamental reasons why the next test might take a lot of work to get passing: Firstly, the test may be genuinely a long way from the current functionality. In this case, maybe it&#8217;s worth looking for a smaller slice of the product to tackle.</p><p>Or secondly, there is probably a lot of coupling between the code and the existing tests. This is the situation in our example above, and our first priority should be to address that coupling.</p><p>So, what did you find when you tried to get the test above to GREEN? The simplest I could do was to write pretty much the whole algorithm. Why? Well, the code duplicates the tests at this point (<code>"happy"</code> occurs as a fixed string in several&nbsp;places), so we probably forgot the REFACTOR step! It is time to remove the duplication before proceeding.</p><p>Some TDDers would use the <em>triangulation</em> technique here by writing a new test that fails precisely because of the coupling in the existing code:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G6wh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G6wh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png 424w, https://substackcdn.com/image/fetch/$s_!G6wh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png 848w, https://substackcdn.com/image/fetch/$s_!G6wh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png 1272w, https://substackcdn.com/image/fetch/$s_!G6wh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G6wh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png" width="577" height="62" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:62,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!G6wh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png 424w, https://substackcdn.com/image/fetch/$s_!G6wh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png 848w, https://substackcdn.com/image/fetch/$s_!G6wh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png 1272w, https://substackcdn.com/image/fetch/$s_!G6wh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7bc260ca-3bf0-48c2-a588-9ca8cd2349b6_577x62.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>YMMV, but personally I find this failing test to be a distraction. I prefer to focus purely on the coupling and let that take my code to a better place. So, without writing any new tests, what should I refactor to fix that coupling?</p><p>Everything revolves around those seven instances of <code>&#8220;happy&#8221;</code>. So looking at this from the point of view of implicit coupling, I note that line 7 in the code will break if the test passes anything other than <code>&#8220;happy&#8221;</code>. But in that case the <code>happy</code> in my result string should simply be the same as the input <code>text</code>. So I can change the code to be this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jRmx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jRmx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png 424w, https://substackcdn.com/image/fetch/$s_!jRmx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png 848w, https://substackcdn.com/image/fetch/$s_!jRmx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png 1272w, https://substackcdn.com/image/fetch/$s_!jRmx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jRmx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png" width="575" height="137" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:137,&quot;width&quot;:575,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15653,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jRmx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png 424w, https://substackcdn.com/image/fetch/$s_!jRmx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png 848w, https://substackcdn.com/image/fetch/$s_!jRmx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png 1272w, https://substackcdn.com/image/fetch/$s_!jRmx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26a20871-45e6-40c0-a5f6-89321cd0e7a7_575x137.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Everything is still GREEN, and we now have only six instances of <code>&#8220;happy&#8221;</code>.</p><p>But the large step we had to take for the <code>&#8220;happy monday&#8221;</code> test was caused by line 5 in the code, so let&#8217;s look at that now. Let&#8217;s change it to this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3VNZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3VNZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png 424w, https://substackcdn.com/image/fetch/$s_!3VNZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png 848w, https://substackcdn.com/image/fetch/$s_!3VNZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png 1272w, https://substackcdn.com/image/fetch/$s_!3VNZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3VNZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png" width="577" height="167" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/f990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20448,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3VNZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png 424w, https://substackcdn.com/image/fetch/$s_!3VNZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png 848w, https://substackcdn.com/image/fetch/$s_!3VNZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png 1272w, https://substackcdn.com/image/fetch/$s_!3VNZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ff990ee90-f573-4e30-8b9c-12bbae14d06c_577x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This passes the tests, but it is still implicitly coupled to the test code because of that <code>2</code>. That&#8217;s simple to fix too:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J08n!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J08n!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png 424w, https://substackcdn.com/image/fetch/$s_!J08n!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png 848w, https://substackcdn.com/image/fetch/$s_!J08n!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png 1272w, https://substackcdn.com/image/fetch/$s_!J08n!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J08n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png" width="573" height="167" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:573,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20923,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!J08n!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png 424w, https://substackcdn.com/image/fetch/$s_!J08n!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png 848w, https://substackcdn.com/image/fetch/$s_!J08n!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png 1272w, https://substackcdn.com/image/fetch/$s_!J08n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F25d1a1c2-8c29-4dc4-8f88-452e84c6b1b1_573x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now only the tests mention <code>&#8220;happy&#8221;</code>, so I&#8217;m happy too!</p><p>Now let&#8217;s add back our difficult test:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Wrcj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Wrcj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png 424w, https://substackcdn.com/image/fetch/$s_!Wrcj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png 848w, https://substackcdn.com/image/fetch/$s_!Wrcj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png 1272w, https://substackcdn.com/image/fetch/$s_!Wrcj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Wrcj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png" width="576" height="64" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/43775cda-257c-4932-9635-fd49ee72aa98_576x64.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:64,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12881,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Wrcj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png 424w, https://substackcdn.com/image/fetch/$s_!Wrcj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png 848w, https://substackcdn.com/image/fetch/$s_!Wrcj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png 1272w, https://substackcdn.com/image/fetch/$s_!Wrcj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F43775cda-257c-4932-9635-fd49ee72aa98_576x64.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I can make this pass more easily now:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FeiB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FeiB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png 424w, https://substackcdn.com/image/fetch/$s_!FeiB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png 848w, https://substackcdn.com/image/fetch/$s_!FeiB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png 1272w, https://substackcdn.com/image/fetch/$s_!FeiB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FeiB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png" width="576" height="198" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/d3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:198,&quot;width&quot;:576,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26926,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FeiB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png 424w, https://substackcdn.com/image/fetch/$s_!FeiB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png 848w, https://substackcdn.com/image/fetch/$s_!FeiB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png 1272w, https://substackcdn.com/image/fetch/$s_!FeiB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3824199-862e-4a58-a305-514e7fb7b6b8_576x198.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>It ain&#8217;t pretty, but it passes the tests. And now I have some obvious coupling to attack, which will help me get closer to a complete working implementation.</p><p>I think the key point for me here is that by addressing the coupling during the REFACTOR step we are making the next RED-GREEN cycle easier. Refactoring on GREEN is much less stressful than trying to hack in a big change on RED, so that&#8217;s where I want to focus my energy.</p><p>One of the reasons this newsletter exists is that I want to explore the effects of addressing implicit coupling. So far, based on very few examples, it seems to me that most of the time (citation needed) converting implicit coupling into explicit coupling also adds some generality to the code. That&#8217;s what happened in our example above. And it seems to me that such generality usually helps to make it easier to add the next piece of functionality. Let&#8217;s find out together if those ideas hold&#8230;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>The step from red bar to green bar should be fast. If it isn't, you're writing code that is unlikely to be 100% tested, and&nbsp;which is&nbsp;prone to&nbsp;errors. Choose tests so that the steps are small, and make sure to refactor ALL of the duplication away before writing the next test, so that you don't have to code around it whilst at the same time trying to get to green.</p><h2>Things to try</h2><ul><li><p>If you notice that you need to write or change more than 3-4 lines of code while your tests are RED, stop! Revert back to GREEN. Now either refactor your code in the light of what just happened, so as to make that test easier to pass, or pick a different test that is closer to your current behaviour.</p></li><li><p>Review your existing tests &#8212; how coupled are they to your code?</p></li></ul><p></p>]]></content:encoded></item><item><title><![CDATA[TDD mistakes 2]]></title><description><![CDATA[Writing tests for invented requirements]]></description><link>https://habitablecode.substack.com/p/tdd-mistakes-2</link><guid isPermaLink="false">https://habitablecode.substack.com/p/tdd-mistakes-2</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 19 Aug 2022 07:00:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!T-V0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Back in 2014 I wrote a blog post listing three mistakes often made by folks who are new to test-driven development (TDD). The three mistakes I identified are:</p><ol><li><p>Starting with error cases or null cases.</p></li><li><p>Writing tests for invented requirements.</p></li><li><p>Writing a dozen or more lines of code to get to GREEN.</p></li></ol><p>It was a very long post, so I&#8217;ve taken the three parts and expanded each into its own article, also incorporating the comments I received in 2014. This is part 2, and will deal with writing tests for invented requirements&#8230;</p><p>Imagine you and I have to test-drive the design of an object that can&nbsp;count the number of occurrences of&nbsp;each&nbsp;word in a string. We&#8217;re doing TDD, but we have no code to test; we have nothing to hang our first test on, so we need to invent something, fast!</p><p>Luckily, our pre-test thinking tells us that our solution will decompose into certain pieces that do certain things, and so we begin by testing one of those and building upwards from there. For example, in the case of the word counter we may reason along the following lines:</p><p>YOU: "We know we'll need to split the string into words&#8221;</p><p>ME: &#8220;So we&#8217;ll need a method that can do the splitting&#8221;</p><p>YOU: &#8220;Great. How shall we test it?&#8221;</p><p>ME: &#8220;The simplest thing would be to count the words after the split?&#8221;</p><p>And so we write this as our first test:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GZTZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GZTZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png 424w, https://substackcdn.com/image/fetch/$s_!GZTZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png 848w, https://substackcdn.com/image/fetch/$s_!GZTZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png 1272w, https://substackcdn.com/image/fetch/$s_!GZTZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GZTZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png" width="575" height="121" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:121,&quot;width&quot;:575,&quot;resizeWidth&quot;:575,&quot;bytes&quot;:15681,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!GZTZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png 424w, https://substackcdn.com/image/fetch/$s_!GZTZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png 848w, https://substackcdn.com/image/fetch/$s_!GZTZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png 1272w, https://substackcdn.com/image/fetch/$s_!GZTZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6675fdd6-76c8-4ef1-b0c9-298dbb89bad2_575x121.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>What&#8217;s wrong with this? Well, no-one asked us to write a method that counts the words, so we're wasting the Customer's time. We might be able to ship real business value to our users sooner if we did something else instead.</p><p>Equally bad, we've invented new scope: a new requirement on our object's API, and locked it in place with a regression test.&nbsp;If this test breaks at some time in the future, how will someone looking at this code in a few months' time cope with that? A test is failing, but how do they know that it's only a &#8220;scaffolding&#8221; test, and should have been deleted long ago?</p><p>Working this way means that we often end up with code in which it&#8217;s difficult to tell what is necessary &#8212; ie. requested by our Customer &#8212; and what was invented purely for the sake of following the TDD mantra.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!T-V0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!T-V0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!T-V0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!T-V0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!T-V0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!T-V0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg" width="468" height="624" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:768,&quot;resizeWidth&quot;:468,&quot;bytes&quot;:441188,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!T-V0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!T-V0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!T-V0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!T-V0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fec2ed69f-06bd-49fb-a073-8f11caa8ce1e_768x1024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Sometimes it can be pragmatic to write &#8220;scaffolding&#8221; tests such as this, perhaps as a discovery exercise to get an idea of how it feels to work with a particular design. And if we do, it&#8217;s important to remember to go back and delete them as soon as possible.</p><p>Because even if this test never fails, its very existence makes it appear that <code>countWords</code> is a requirement. We&#8217;ll need to spend some time checking with someone before we can change this API or delete it.</p><p>So start at the outside, by writing tests for things that your code&#8217;s consumer (eg. the end user) actually asked for.</p><p>Next time: taking a slice that&#8217;s too big.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Things to try</h2><ul><li><p>Look around your codebase for tests like this. Delete as many as you can.</p></li><li><p>Next time you have to TDD something that doesn&#8217;t exist yet, start with a thin slice of genuine business value, and do as little design as you can. No, less than that!</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/tdd-mistakes-2/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/tdd-mistakes-2/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[TDD: Three easy mistakes]]></title><description><![CDATA[TL;DR Small increments of value]]></description><link>https://habitablecode.substack.com/p/tdd-three-easy-mistakes</link><guid isPermaLink="false">https://habitablecode.substack.com/p/tdd-three-easy-mistakes</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 12 Aug 2022 07:00:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BE00!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Back in 2014 I wrote a blog post listing three mistakes often made by folks who are new to test-driven development (TDD). It was a very long post, so I&#8217;ve taken the three parts and expanded each into its own article, also incorporating the comments I received in 2014. This is part 1.</p><p>Each time I visit a team that is relatively new to TDD I find the same basic mistakes cropping up every time. The three mistakes I see most often are:</p><ol><li><p>Starting with error cases or null cases.</p></li><li><p>Writing tests for invented requirements.</p></li><li><p>Writing a dozen or more lines of code to get to GREEN.</p></li></ol><p>This article will deal with the first of these...</p><p>Imagine you have to test-drive the design of an object that can&nbsp;count the number of occurrences of&nbsp;each&nbsp;word in a string. I will often see someone who is new to TDD start with tests such as these (example in Java/JUnit):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_V_L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_V_L!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png 424w, https://substackcdn.com/image/fetch/$s_!_V_L!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png 848w, https://substackcdn.com/image/fetch/$s_!_V_L!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png 1272w, https://substackcdn.com/image/fetch/$s_!_V_L!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_V_L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png" width="574" height="271" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:271,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44612,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_V_L!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png 424w, https://substackcdn.com/image/fetch/$s_!_V_L!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png 848w, https://substackcdn.com/image/fetch/$s_!_V_L!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png 1272w, https://substackcdn.com/image/fetch/$s_!_V_L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26805374-412e-469f-ac57-ec0f0a7bb309_574x271.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Tests like this are counter-productive for a number of reasons:</p><ol><li><p>They feel easy to write, and give a definite feeling&nbsp;of progress. But that is all they give: a <em>feeling</em>&nbsp;of progress. These tests really&nbsp;only&nbsp;prove to ourselves that we can write a test. When written first like this, they don't deliver any business value.</p></li><li><p>These tests don&#8217;t get us closer to validating the Customer<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>'s assumptions. Time spent writing them hasn&#8217;t allowed us to demo anything or ask for feedback. There is no business benefit and no learning benefit.</p></li><li><p>These edge-case tests increase the code&#8217;s cost of ownership; by putting this code into the codebase too early I find it just gets in the way. Chances are we&#8217;ll have to tiptoe around them while we build the actual business value, and that will slow us down even more. </p></li></ol><p>It is usually much better to begin by building a simple thin slice of positive business value (some folks call this a &#8220;happy path&#8221;, to remind themselves that no error cases have been dealt with yet). And when we&#8217;re successfully delivering some business value,&nbsp;that is the time for us to remind our Customer that we have some edge cases to consider.</p><p>So start with tests that represent business value and allow a thin, usable slice of the product to be built quickly. For example:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!a6vk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!a6vk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png 424w, https://substackcdn.com/image/fetch/$s_!a6vk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png 848w, https://substackcdn.com/image/fetch/$s_!a6vk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png 1272w, https://substackcdn.com/image/fetch/$s_!a6vk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!a6vk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png" width="616" height="161.99307958477507" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:152,&quot;width&quot;:578,&quot;resizeWidth&quot;:616,&quot;bytes&quot;:23921,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!a6vk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png 424w, https://substackcdn.com/image/fetch/$s_!a6vk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png 848w, https://substackcdn.com/image/fetch/$s_!a6vk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png 1272w, https://substackcdn.com/image/fetch/$s_!a6vk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9e4af269-9cd5-48ee-a900-a34b923f15fd_578x152.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This way you will get two major benefits:</p><p>Firstly, you can ask the Customer that vital question (&#8220;Is this what you meant?&#8221;) sooner, and they will invest less before they know whether they want to proceed. So the biggest payoff of leaving the edge cases until later is that they actually allow the Customer, should they decide to do so, to ship working code that provides benefit.  Sure it may have limited robustness, but that risk can be worth more than waiting until you have finished polishing every edge case that can be thought of.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BE00!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BE00!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg 424w, https://substackcdn.com/image/fetch/$s_!BE00!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg 848w, https://substackcdn.com/image/fetch/$s_!BE00!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!BE00!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BE00!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg" width="374" height="374" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:374,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Germinating_seedling.jpg (2200&#215;2200)&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Germinating_seedling.jpg (2200&#215;2200)" title="Germinating_seedling.jpg (2200&#215;2200)" srcset="https://substackcdn.com/image/fetch/$s_!BE00!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg 424w, https://substackcdn.com/image/fetch/$s_!BE00!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg 848w, https://substackcdn.com/image/fetch/$s_!BE00!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!BE00!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3b6a0f28-fa0e-407d-8bac-65484264b9b8_2200x2200.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>And secondly, you will likely have a simpler development job to do, both while developing the happy path and later when you come to add the edge cases. Because very often&nbsp;it will turn out to be much easier to add edge cases to an existing solution, after the happy path is done. In fact some of the edge cases may now already be dealt with "for free", as it were, simply by the natural shape of the algorithm we test drove. Others may be easy to implement by adding a <strong>Decorator</strong> or introducing a guard clause.</p><p>Now, you might object to me calling this a mistake, because tests such as those above allow us to define a class API without having to worry about the implementation. There are a number of design decisions that have been made as a result of writing some very quick tests, e.g. the name of the class (<code>WordCounter</code>), the name of the method that does the counting (<code>count</code>), whether the parameters are on the <code>count</code> method or the class constructor, etc. But I don&#8217;t see those as a benefit; to my mind they create risk because they haven't been checked in realistic scenarios. I would prefer to make those design decisions in code that is delivering business benefit so that, ultimately, they are required to support real users. In short, I want a correct algorithm first, followed by habitable code.</p><h2>Things to try</h2><ul><li><p>Next time you have to write the first test for something new, try to deliver positive business value from the happy path.</p></li><li><p>Review your existing edge-case and error-case logic: how much of it could be pushed out of your domain code and into decorators or <a href="http://checks.fed.wiki.org/view/about-checks-pattern-language">CHECKS</a>?</p></li></ul><p>Next time, another TDD rookie mistake&#8230;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I&#8217;ve decided to switch from Product Owner to the XP term Customer henceforward, because that&#8217;s the term I&#8217;m more comfortable with.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Shotgun surgery]]></title><description><![CDATA[Possibly my favourite code smell]]></description><link>https://habitablecode.substack.com/p/thinking-about-code-smells</link><guid isPermaLink="false">https://habitablecode.substack.com/p/thinking-about-code-smells</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 05 Aug 2022 07:15:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!YHZs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What&#8217;s your favourite code smell?</p><p>Daft question, I hope you&#8217;ll agree.</p><p>But I think I <em>do</em> have a favourite. It&#8217;s <strong>Shotgun Surgery</strong>. Why? Because it tells me so much about my design. Let me explain&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YHZs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YHZs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png 424w, https://substackcdn.com/image/fetch/$s_!YHZs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png 848w, https://substackcdn.com/image/fetch/$s_!YHZs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png 1272w, https://substackcdn.com/image/fetch/$s_!YHZs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YHZs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png" width="356" height="356" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:600,&quot;resizeWidth&quot;:356,&quot;bytes&quot;:47223,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YHZs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png 424w, https://substackcdn.com/image/fetch/$s_!YHZs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png 848w, https://substackcdn.com/image/fetch/$s_!YHZs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png 1272w, https://substackcdn.com/image/fetch/$s_!YHZs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F599e6200-05df-4359-8b6d-03aef4496e1b_600x600.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Firstly, many of the other code smells often feel quite ambiguous to me. Is this <strong>Feature Envy</strong> or is it a reasonable separation of responsibilities? Is this <strong>Primitive Obsession</strong> or simple value passing between close collaborators deep inside an encapsulated mechanism? Very often I spend too much energy debating questions like this, instead of making progress towards more habitable code.</p><p>But <strong>Shotgun Surgery</strong> is different. It says &#8220;You just added feature X and you had to change code at A, B and C&#8221;. This means that A, B, and C were coupled &#8212; and are now coupled even more.</p><p>Note the use of the past tense there. I don&#8217;t want to look for or fix Shotgun Surgery until the feature<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> increment is done. I want to wait so that I can see all of the damage I&#8217;m going to do, because that tells me the most about what the design problem was.</p><p><strong>Shotgun Surgery</strong> says &#8220;You ought to refactor so that you could have implemented that feature increment with a 1-line change to existing code&#8221;.</p><p>So here&#8217;s the process:</p><ol><li><p>Add a complete feature increment.</p></li><li><p>Step back and review all of the places in the code that had to change. There was implicit coupling between all of those places, because they all made some assumptions that had to be busted in light of our new feature.</p></li><li><p>Construct a design that would have allowed the feature to be added by instead changing only one place in the code.</p></li><li><p>Refactor to that design.</p></li></ol><p>Why would I want to do this? Because when I&#8217;m done, my code will now have a new &#8220;seam&#8221; &#8212; a new place at which extensions such as this can be inserted without changing too much.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Imagine that my code currently has the following design:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8rek!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8rek!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png 424w, https://substackcdn.com/image/fetch/$s_!8rek!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png 848w, https://substackcdn.com/image/fetch/$s_!8rek!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png 1272w, https://substackcdn.com/image/fetch/$s_!8rek!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8rek!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png" width="304" height="314.205493387589" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1016,&quot;width&quot;:983,&quot;resizeWidth&quot;:304,&quot;bytes&quot;:32075,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8rek!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png 424w, https://substackcdn.com/image/fetch/$s_!8rek!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png 848w, https://substackcdn.com/image/fetch/$s_!8rek!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png 1272w, https://substackcdn.com/image/fetch/$s_!8rek!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F39e7700d-c498-494d-a83c-dbe216924fd4_983x1016.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Without too much fuss I implement my feature increment. And now I have this (changes in red):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JwaM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JwaM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png 424w, https://substackcdn.com/image/fetch/$s_!JwaM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png 848w, https://substackcdn.com/image/fetch/$s_!JwaM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png 1272w, https://substackcdn.com/image/fetch/$s_!JwaM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JwaM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png" width="380" height="418.2791185729276" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/fa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1049,&quot;width&quot;:953,&quot;resizeWidth&quot;:380,&quot;bytes&quot;:42048,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JwaM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png 424w, https://substackcdn.com/image/fetch/$s_!JwaM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png 848w, https://substackcdn.com/image/fetch/$s_!JwaM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png 1272w, https://substackcdn.com/image/fetch/$s_!JwaM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa96cca9-55da-40d2-afea-bbe7238f2c81_953x1049.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>What if, instead, I had first refactored my design to make room for the new feature:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eRO0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eRO0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png 424w, https://substackcdn.com/image/fetch/$s_!eRO0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png 848w, https://substackcdn.com/image/fetch/$s_!eRO0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png 1272w, https://substackcdn.com/image/fetch/$s_!eRO0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eRO0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png" width="478" height="313.37277147487845" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:809,&quot;width&quot;:1234,&quot;resizeWidth&quot;:478,&quot;bytes&quot;:32585,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eRO0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png 424w, https://substackcdn.com/image/fetch/$s_!eRO0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png 848w, https://substackcdn.com/image/fetch/$s_!eRO0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png 1272w, https://substackcdn.com/image/fetch/$s_!eRO0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7d04aed7-1179-472d-aec7-2e9b734a0c3d_1234x809.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So that I can now implement my feature with little or no change to existing code (new feature in green):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!31uf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!31uf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png 424w, https://substackcdn.com/image/fetch/$s_!31uf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png 848w, https://substackcdn.com/image/fetch/$s_!31uf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png 1272w, https://substackcdn.com/image/fetch/$s_!31uf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!31uf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png" width="460" height="301.57212317666125" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:809,&quot;width&quot;:1234,&quot;resizeWidth&quot;:460,&quot;bytes&quot;:31460,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!31uf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png 424w, https://substackcdn.com/image/fetch/$s_!31uf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png 848w, https://substackcdn.com/image/fetch/$s_!31uf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png 1272w, https://substackcdn.com/image/fetch/$s_!31uf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4f64e56d-347b-43fe-8347-832bac88af1e_1234x809.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Of course, I&#8217;m not claiming that any of this is <em>easy</em>, but I do think it&#8217;s <em>valuable</em>. That&#8217;s because fixing the <strong>Shotgun Surgery</strong> in this way prepares the codebase for the future in a number of ways:</p><ol><li><p>The code for this whole feature is now collected together in one place, and likely has a name. That&#8217;s got to be good for our ability to comprehend the code: It is now obvious where to look for anything related to this feature.</p></li><li><p>The fact that we were asked to add this feature to an existing, working application suggests that similar changes will be asked for in the future [citation needed]. By taking this &#8220;open-closed&#8221; approach we have likely made the code more amenable to adding alternative options along the same axis. </p></li><li><p>Even if nothing similar crops up again in the future, by making this change we have ensured that the rest of the codebase isn&#8217;t infected with knowledge of this feature. So the rest of the codebase is cleaner and not burdened with this responsibility.</p></li><li><p>Deleting this feature will be really easy, if it comes to that.</p></li><li><p>There&#8217;s likely little or no implicit coupling related to this feature now. So there will be fewer surprises if it evolves.</p></li><li><p>The part of the codebase that had to be modified to accommodate this feature is now a more stable abstraction, parameterised by the new feature and its alternatives. And the more we do this, the more generalised and stable the core of our codebase will become. This is expected to be good for the long term extensibility.</p></li></ol><p>It seems to me that the benefits to the code of fixing <strong>Shotgun Surgery</strong> like this are huge and long-lived. But there are also benefits in terms of our mindset: making this change will influence how we make future changes, and how we structure our design to support future change.</p><p>Feels like I should write up a worked example someday&#8230;</p><h2>Things to try</h2><ul><li><p>Have a go at Matteo Vaccari&#8217;s <a href="http://matteo.vaccari.name/blog/archives/293.html">OCP Kata</a>, which was the inspiration for many of the above ideas. This kata tells you to refactor in this way <em>every time you have a failing test</em>.</p></li><li><p>When you finish your next feature increment, do the design exercise above: work out a design in which all of the feature&#8217;s code could have been added in one place.</p></li><li><p>If you have time, actually change the code to that design.</p></li><li><p>Try do the kata on a &#8220;real&#8221; production codebase, refactoring on RED so that you can make the next test pass without changing code. Which works best for you, bigger steps or smaller steps?</p></li></ul><p>As always, please leave a comment if you try this exercise. Does the codebase <em>feel</em> substantively different afterwards? Could you have implemented the feature like this in the first place? Will you do anything differently for your next feature?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/thinking-about-code-smells/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/thinking-about-code-smells/comments"><span>Leave a comment</span></a></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>What do I mean by &#8220;feature&#8221; in this article? I guess it&#8217;s anything that is big enough to be asked for by your Product Owner, and therefore also releasable to users.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Diving into the 4 rules of simple design]]></title><description><![CDATA[A little light holiday reading]]></description><link>https://habitablecode.substack.com/p/diving-into-the-4-rules-of-simple</link><guid isPermaLink="false">https://habitablecode.substack.com/p/diving-into-the-4-rules-of-simple</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 29 Jul 2022 07:15:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_Hzr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ll be taking a break from writing during the summer, so these weekly articles may contain slightly less deep content for a few weeks. When I&#8217;m back I have big plans for this newsletter, so make sure you&#8217;re subscribed so you don&#8217;t miss anything!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>This week I thought I&#8217;d take a somewhat more detailed look into the 4 Rules of Simple Design. I&#8217;ve mentioned them quite a few times in my early articles, so let&#8217;s look a little more closely.</p><p>To recap the 4 rules, code that is &#8220;simple&#8221; (ie. habitable) must satisfy the following criteria:</p><ol><li><p>Passes all its tests</p></li><li><p>Expresses our intention</p></li><li><p>Says everything once and only once</p></li><li><p>Has nothing superfluous</p></li></ol><p>The first thing to note is that many people list rules 2 and 3 in the opposite order than I have. I actually don&#8217;t think there&#8217;s a difference &#8212; I&#8217;d say that rules 2 and 3, in practical terms, feed off each other so much that they may as well be parts of a single rule. I&#8217;ll come back to this point a bit later, but first I want to talk about what the ordering of the rules means.</p><p>In an ideal world, all of our code would satisfy all four rules simultaneously. In which case their order doesn&#8217;t matter.</p><p>The order of the rules comes into play when we have code that <em>doesn&#8217;t </em>already satisfy them &#8212; code that, by this definition at least, isn&#8217;t habitable. In this case, the order of the four rules tells us <em>how to behave</em>.</p><p>First, they say, get the code working and tested. Nothing else matters. If the code doesn&#8217;t work, nobody cares how habitable it is; the other rules don&#8217;t come into focus. (Actually, in practical terms that&#8217;s not quite true. If the code used to satisfy the 4 rules, and then we broke a test, that code will likely be much easier to fix than if we have a broken test of code that is a tangled mess of unreadable, duplicated logic.) Nevertheless, regardless of the prior state of the code, the 4 rules say that our first priority is the get the code working and tested again. <em>And we&#8217;re allowed to break the other rules, if necessary, in order to get back to working and tested.</em></p><p>This mirrors the rules of test-driven development: After the RED step we have a failing test, so we want the GREEN step to be completed quickly. In getting back to GREEN we&#8217;re actively encouraged to Do The Simplest Thing That Could Possibly Work. Don&#8217;t spend time thinking about code quality or readability; don&#8217;t worry about introducing duplication or coupling; and don&#8217;t worry about leaving unused code in your wake. Just do what you have to do in order to get that test passing again.</p><p>It&#8217;s worth mentioning that it&#8217;s no accident that test-driven development&#8217;s RED-GREEN-REFACTOR cycle starts the same way as the 4 rules of simple design. That&#8217;s because <em>they are the same rules</em>. It&#8217;s just that the 4 rules give us a more helpful guide as to how to direct our refactoring effort. Which brings us neatly to rules 2, 3, and 4.</p><p>After our code is working and tested, TDD tells us to &#8220;refactor&#8221;, but stops there, before telling us how to go about it. And this is where rules 2, 3, and 4 step in.</p><p>First, make the code understandable by anyone who understands the domain. And if you need to introduce duplication in order to do that, that&#8217;s fine. The 4 rules say &#8220;make it readable first&#8221;; then fix the duplication; and only then shoot for minimalism. But you&#8217;re not allowed to remove duplication if doing so would make the code unreadable. And you&#8217;re not allowed to minimise the code if that would render it unreadable or introduce duplication.</p><p>So what do &#8220;readable&#8221; and &#8220;understandable&#8221; mean? We want to have the code express the Product Owner&#8217;s and the developer&#8217;s intentions. In all of the programming languages I can think of, the only tools we have for expressing ideas are the names we give to things. So we need to ensure that every code construct that we create has a meaningful, domain-related name. But we also need to ensure that we choose the &#8220;right&#8221; things to make nameable. As we break down our algorithm into functions, parameters, variables, classes, modules etc it&#8217;s important that those entities map onto the domain, so that the story told by the code makes sense in terms of the major concepts of that domain. I want my code to &#8220;tell the story&#8221; that my Product Owner told me when explaining their intention for this feature.</p><p>Next, on to rule 3. Once we have working tested code that tells the Product Owner&#8217;s story, we should ensure that every idea in that story is represented in the code exactly once and no more. And my working hypothesis &#8212; the question I&#8217;m exploring through these articles &#8212; is that this is best accomplished by looking for implicit coupling and making it explicit. My mission here is to see if we can develop a clearer sense of how to apply the Once And Only Once rule in practical day-to-day programming.</p><p>As I mentioned above, many (perhaps most) authors prioritise rules 2 and 3 the opposite way around from my list here. The reason I prefer to fix expressiveness first is that I&#8217;ve seen huge amounts of unreadable code produced in the name of removing duplication. And since we read each line of code much more often than we change it, I think there&#8217;s quite a productivity payoff in having expressiveness prioritised more highly than duplication.</p><p>And in practice rules 2 and 3 usually play off each other. Most of the time when we remove some duplication, that activity involves introducing one or more new nameable components into the code. So we have to go back around to rule 2 to ensure that the new names &#8212; and the new nameable things &#8212; tell the story at least as well as before. So rules 2 and 3 form what Joe Rainsberger has called a &#8220;dynamo&#8221;; they feed off each other and influence each other. And so it may be that their order doesn&#8217;t really matter if we&#8217;re being thorough. Be that as it may, I&#8217;m sticking with the order above; I want to ensure that if, say, I run out of time, my code a readable first and foremost.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_Hzr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_Hzr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png 424w, https://substackcdn.com/image/fetch/$s_!_Hzr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png 848w, https://substackcdn.com/image/fetch/$s_!_Hzr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!_Hzr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_Hzr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png" width="520" height="371.42857142857144" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1000,&quot;width&quot;:1400,&quot;resizeWidth&quot;:520,&quot;bytes&quot;:40932,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_Hzr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png 424w, https://substackcdn.com/image/fetch/$s_!_Hzr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png 848w, https://substackcdn.com/image/fetch/$s_!_Hzr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!_Hzr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0d03c770-42cc-4739-bdcd-2a3745c183f8_1400x1000.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Finally, there&#8217;s the fourth rule: be a minimalist. If something becomes unused while you&#8217;re following the other rules, just delete it. If there&#8217;s a simpler way of achieving something, do it that way &#8212; but make sure the code still tells the story at least as well as before.</p><p>So, that&#8217;s a whistle-stop tour of the 4 rules of simple design, including a little insight into where I think this newsletter fits in the grand scheme of things.  Following these rules keeps your code habitable, and therefore also keeps the cost of change lower. But they aren&#8217;t easy &#8212; and rule 2 in particular is somewhat subjective. Expressing intention is hard!</p><h2>Things to try</h2><ol><li><p>Can you completely let go of your &#8220;sense of smell&#8221; when you&#8217;re writing the code to get that test to pass?</p></li><li><p>Can your Product Owner read and understand your code?</p></li><li><p>In particular, if your Product Owner can&#8217;t read and understand your tests, you&#8217;re not done refactoring.</p></li></ol><p>Please leave a comment if you just tried this approach for the first time: How did it feel? Did it make a difference to your code? What happened when a non-developer read your test code?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/diving-into-the-4-rules-of-simple/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/diving-into-the-4-rules-of-simple/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Estimating user stories]]></title><description><![CDATA[The 5-day challenge]]></description><link>https://habitablecode.substack.com/p/estimating-user-stories</link><guid isPermaLink="false">https://habitablecode.substack.com/p/estimating-user-stories</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 22 Jul 2022 07:15:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!CYxT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is an article I wrote in 2014, rewritten slightly to account for the ravages of time and to incorporate the comments I&#8217;ve received since then. It&#8217;s about an idea I've introduced to every software team I&#8217;ve coached during the last eight years. If you try it, please publish your experiences and link to them via the comments here.</p><blockquote><p><strong>TL;DR:<br>Don't guess the size of a user story;<br>slice the story until it&#8217;s the size you want.</strong></p></blockquote><p>So there's this big discussion going on about #NoEstimates &#8212; and how estimating is wasteful, misleading etc &#8212; for what seems like forever. But there are very few published practical alternatives. So what to do if you want to do less estimating? Honestly, I think that's the wrong question to be asking. A more important question, at least for every team I've encountered, is "how can we become more predictable in what we will promise and deliver?" Estimates only go so far in answering this question because, well, they're just guesses. It doesn't matter whether they are expressed as hours, pair-hours, story points, complexity points, <a href="http://wiki.c2.com/?GummiBearsConsideredHarmful">Gummi bears</a> or whatever; someone somewhere will attempt to do arithmetic with your estimates and thus turn them into "facts". So estimating is hard, and it's guesswork; it is not my intention here to grumble on about all the side-effects of that &#8212; you can read all of that stuff elsewhere. Instead, let's cut to the chase and do something about it.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Estimates are risky and difficult. So let's try the opposite. Instead of estimating the next story, let's play to our strengths as developers and give ourselves a technical and analytical puzzle: Let's fit the story to the estimate. Here's how it works&#8230;</p><p>When the team picks up the next story, apply&nbsp;the "five-day challenge". First ask, "can we deliver this in 5 days?" If the answer is "yes", just do it and then pick up the next story. But if the answer is "no", have the whole team identify some core nugget of useful value within the story such that everyone agrees:</p><ol><li><p>it could be delivered in five days or less, and </p></li><li><p> it will be a useful and valuable product increment.</p></li></ol><p>Deliver that core nugget to your users, then go and pick the next story.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CYxT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CYxT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg 424w, https://substackcdn.com/image/fetch/$s_!CYxT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg 848w, https://substackcdn.com/image/fetch/$s_!CYxT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!CYxT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CYxT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg" width="430" height="322.5" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:1456,&quot;resizeWidth&quot;:430,&quot;bytes&quot;:129081,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CYxT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg 424w, https://substackcdn.com/image/fetch/$s_!CYxT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg 848w, https://substackcdn.com/image/fetch/$s_!CYxT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!CYxT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F63aa99a1-5924-4d29-a85b-52c2c936d3a5_1600x1200.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>(Historical note: This challenge is very similar to the approach used by <a href="https://www.linkedin.com/in/tomgilb/">Tom Gilb</a> in his EVO method, in which the team is asked to look for the one thing that can be delivered next week that can make a difference.)</p><p>This challenge&nbsp;process is fun, and it is exactly the kind of problem many developers and product owners are good at solving. That's a win. Furthermore, there is plenty of good literature out there to help you do it and get good at doing it. Here are three great articles that can help with that:</p><ol><li><p><a href="https://blog.jbrains.ca/permalink/three-steps-to-a-useful-minimal-feature">Three Steps to a Useful Minimal Feature</a> by Joe Rainsberger</p></li><li><p><a href="https://blog.jbrains.ca/permalink/how-youll-probably-learn-to-split-features">How You&#8217;ll Probably Learn to Split Features</a>, also by Joe Rainsberger</p></li><li><p><a href="https://www.humanizingwork.com/the-humanizing-work-guide-to-splitting-user-stories/">Guide to Splitting User Stories</a> by Humanizing Work</p></li></ol><p>Shortly&nbsp;after you have split the story to fit into five days, the Product Owner should take each of the edge cases you peeled off, turn them into stories and push them back down the queue. One or two of them may be the next stories to be scheduled, while others may wind up never being picked. All that matters right now is that they aren't essential to delivering the current story, and thus need occupy no more developer&nbsp;time this week.</p><p>Of course, if your stories are already small, instead of 5 days pick 3, or 2, or 1. I like 5 days as a starting point because for many teams it's an improvement over their current practice, and it almost always gives time to deliver an interesting chunk of value. The important thing is to pick a number of days and stick to it until you are confident that you have that size of story nailed. Then try reducing it by one day and learn how to slice your stories even more thinly.</p><p>When you have delivered the story, record the actual number of days it took. If that differs&nbsp;from five days, take 5 minutes as a team and list the reasons for that variance. Use this to help you do a better job of&nbsp;fitting the next story to 5 days (or less). You&#8217;re aiming for stable and predictable first, then for gradually smaller timeboxes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PDeA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PDeA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg 424w, https://substackcdn.com/image/fetch/$s_!PDeA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg 848w, https://substackcdn.com/image/fetch/$s_!PDeA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!PDeA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PDeA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg" width="514" height="310.406429391504" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:526,&quot;width&quot;:871,&quot;resizeWidth&quot;:514,&quot;bytes&quot;:16671,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PDeA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg 424w, https://substackcdn.com/image/fetch/$s_!PDeA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg 848w, https://substackcdn.com/image/fetch/$s_!PDeA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!PDeA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8ca5b74c-f1b7-48d4-9cdb-13db5d477a07_871x526.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Note that the 5-day challenge is NOT a challenge to the team, it's a challenge to the story. You all sat down together and dug out a core nugget of useful value, so now go ahead and deliver that without taking any short cuts. If you find yourselves running later than 5 days, don't try to squeeze the story into your estimate. It doesn't matter if the story ends up taking 11 days or just 2. The important thing is to do the story well, and then learn from the actual time it took.</p><p>Why have I posted this article in a series about <em>Habitable Code</em>? Because the habitability or otherwise of our code represents the biggest hurdle to slicing our stories thinner and thinner. Back in 2014 <a href="https://www.linkedin.com/in/matteovaccari/">Matteo Vaccari</a> wrote this comment on my original blog post:</p><blockquote><p>This is not just a challenge to the user story; it's a challenge to our codebase.  Why does it take 5 days to implement this request? Shouldn't we be able to implement this by a reconfiguration of our existing objects? Why is our codebase not closed with respect to this kind of variation? This is a challenge to our process and to the way we program.</p></blockquote><p>I made a similar point in <a href="https://www.linkedin.com/pulse/dont-forget-developers-xpsurgery/">Don&#8217;t Forget the Developers</a>: ultimately the habitability of our code is what will determine whether our &#8220;agile adoption&#8221; has any chance of succeeding.</p><p>In practice, this technique dovetails very well with the whole ecosystem&nbsp;of the eXtreme Programming (XP) practices. And it fits&nbsp;best of all with&nbsp;the&nbsp;other team micro-habits that I have evolved through my coaching practice over the last ten years or so.&nbsp;I may write about some of those here too. Or you could <a href="https://www.kevinrutherford.info/contact-me/">hire me</a> to help your team implement XP, and find the best fit for the XP principles and practices in your organisation &#128578;.</p><p>Here's a video of me explaining the 5-day challenge in a lightning talk at the Scottish Ruby Conference in 2014 (you need to skip forward to 07:54 because Substack doesn&#8217;t allow me to set the start time): </p><div id="vimeo-96825209" class="vimeo-wrap" data-attrs="{&quot;videoId&quot;:&quot;96825209&quot;,&quot;videoKey&quot;:&quot;&quot;,&quot;belowTheFold&quot;:true}" data-component-name="VimeoToDOM"><div class="vimeo-inner"><iframe src="https://player.vimeo.com/video/96825209?autoplay=0" frameborder="0" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" loading="lazy"></iframe></div></div><h3>Things to try:</h3><p>Next time you have to estimate a user story, try the 5-day challenge instead. (If your stories already typically take less than 5 days, try the challenge but with a smaller timebox.) Let us know in the comments what happened, what your team and Product Owner learned, and how you plan to take this idea forwards.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/estimating-user-stories/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/estimating-user-stories/comments"><span>Leave a comment</span></a></p><p>And when you get really good and this, and your team can reliably and predictably deliver value every day, try forgetting about user stories and slice the <em>customer&#8217;s</em> <em>problem</em> instead?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Habitable Code! Subscribe now to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Open thread: What's the most useful type of content here?]]></title><description><![CDATA[This week I need your help. I want to grow this newsletter so that it becomes more and more useful to you.]]></description><link>https://habitablecode.substack.com/p/open-thread-whats-the-most-useful</link><guid isPermaLink="false">https://habitablecode.substack.com/p/open-thread-whats-the-most-useful</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 15 Jul 2022 07:15:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6Vrt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This week I need your help.</p><p>I want to grow this newsletter so that it becomes more and more useful to you, so I&#8217;d like to get your help in shaping the content.</p><p>I know that you, like me, are passionate about the internal quality of the software you create. And like me you&#8217;re frustrated that there&#8217;s very little practical advice out there to help with refactoring, and with test-driven development in general.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Vrt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Vrt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png 424w, https://substackcdn.com/image/fetch/$s_!6Vrt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png 848w, https://substackcdn.com/image/fetch/$s_!6Vrt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!6Vrt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Vrt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png" width="386" height="386" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/a2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1200,&quot;width&quot;:1200,&quot;resizeWidth&quot;:386,&quot;bytes&quot;:71145,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6Vrt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png 424w, https://substackcdn.com/image/fetch/$s_!6Vrt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png 848w, https://substackcdn.com/image/fetch/$s_!6Vrt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!6Vrt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2fef21b-897f-4d2f-85a9-9b3c911e61cf_1200x1200.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So how can I help? What do we, as a community, need this newsletter to provide?</p><p>I&#8217;ll put my own goals in the comments, and I&#8217;m looking forward to hearing from you too &#8212; what can I write about that will help <em>you</em>?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>One final thing: Please also help to make this thread as useful as possible by sharing this post widely among people who share our need for better refactoring advice.</p><p>Thanks for your continuing support!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share Habitable Code&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share Habitable Code</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Integration tests]]></title><description><![CDATA[Do they help to make coupling explicit?]]></description><link>https://habitablecode.substack.com/p/integration-tests</link><guid isPermaLink="false">https://habitablecode.substack.com/p/integration-tests</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 08 Jul 2022 07:20:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ujlv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;m really enjoying answering your questions and comments, because it&#8217;s making me thing about things I had clearly taken for granted! This week, a question I received via email&#8230;</p><p>In response to <a href="https://habitablecode.substack.com/p/thinking-about-apis">Thinking about APIs</a> reader Richard made this comment directly to me via email:</p><blockquote><p>Have you thought about integration tests? That could solve some of the issues about the changing contracts.</p></blockquote><p>Yes, integration tests &#8212; indeed all kinds of automated checking &#8212; definitely help to establish our software&#8217;s correctness. They operate within the first of the 4 rules of Simple Design: &#8220;passes all of the tests&#8221;. But the thesis of this series of articles is that we can do more.</p><p>Shigeo Shingo, one of the founding fathers of Lean Manufacturing, said something to the effect that:</p><blockquote><p><em><strong>Inspection to prevent defects</strong></em> is absolutely required of any process,<br>but <em><strong>inspection to find defects</strong></em> is waste.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ujlv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ujlv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png 424w, https://substackcdn.com/image/fetch/$s_!ujlv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png 848w, https://substackcdn.com/image/fetch/$s_!ujlv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png 1272w, https://substackcdn.com/image/fetch/$s_!ujlv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ujlv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png" width="199" height="241.77570093457945" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:321,&quot;resizeWidth&quot;:199,&quot;bytes&quot;:88605,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ujlv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png 424w, https://substackcdn.com/image/fetch/$s_!ujlv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png 848w, https://substackcdn.com/image/fetch/$s_!ujlv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png 1272w, https://substackcdn.com/image/fetch/$s_!ujlv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F72f624e9-60cd-462f-bd7c-3ac8cbe887af_321x390.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Paraphrasing this into the domain of software development:</p><blockquote><p>It is more efficient to prevent defects from entering our code than it is to find them later &#8212; even if &#8220;later&#8221; is only the time it takes to run our tests.</p></blockquote><p>So I want to find ways to bring that feedback forward in time, so that I can &#8220;see&#8221; the coupling <em><strong>before</strong></em> I break something &#8212; and without having to execute anything. I don&#8217;t want to have to rely on test execution, or compilation, or static analysis, or any of the other tools provided within a modern IDE or CI/CD pipeline. I just want to be able to look at this one module right here, at this current level of abstraction, and &#8220;know&#8221; that it is coupled to something else &#8220;over there&#8221;.</p><p>I want to explore whether it is possible to write code that speaks clearly and immediately, regardless of what tools I have at my disposal. And even if you have different tools &#8212; less capable IDE, differently configured pipeline, etc &#8212; the code should still speak to you in exactly the same way that it speaks to me.</p><p>It may be that we will discover that there are &#8220;degrees of explicitness&#8221;, and that they are somehow related to the speed of our feedback loops. I sincerely hope that isn&#8217;t the case though. I have this naive expectation that code quality shouldn&#8217;t be related to tooling; that we can discover something &#8220;universal&#8221; &#8212; although I definitely expect those universal ideas to have widely differing expressions depending on our programming language / paradigm / ecosystem.</p><p>One final observation: The tests are also code. They are thus built using coupling, both internal &#8212; within the tests&#8217; codebase &#8212; and with the system under test. Thus, far from &#8220;solving&#8221; our implicitness problem, I view tests as just another codebase whose coupling I need to make explicit. The code of the tests should still satisfy the 4 rules of simple design, just as our production code should.</p><p>What do you think &#8212; am I on a mad Quixotic quest? Can we always write code that has no implicit coupling across encapsulation boundaries?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/integration-tests/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/integration-tests/comments"><span>Leave a comment</span></a></p><p>I think maybe it&#8217;s time we began to explore some more (a lot more) worked examples&#8230;</p>]]></content:encoded></item><item><title><![CDATA[Static and dynamic analysis]]></title><description><![CDATA[How does Implicit Coupling relate to the various kinds of Connascence?]]></description><link>https://habitablecode.substack.com/p/static-and-dynamic-analysis</link><guid isPermaLink="false">https://habitablecode.substack.com/p/static-and-dynamic-analysis</guid><dc:creator><![CDATA[Kevin Rutherford]]></dc:creator><pubDate>Fri, 01 Jul 2022 07:20:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1ZIj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://habitablecode.substack.com/p/runtime-and-compile-time">Last week</a> I answered a couple of points from a Manchester-based Slack channel. That same Slack thread continued with another comment from <a href="https://twitter.com/be4zley">Ross</a>:</p><blockquote><p>Is it safe to say the static section in your "handy cut out" is explicit coupling and the dynamic section is implicit ?</p></blockquote><p>By &#8220;handy cut out&#8221; Ross is referring to my 2016 representation of the various kinds of Connascence:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1ZIj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1ZIj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png 424w, https://substackcdn.com/image/fetch/$s_!1ZIj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png 848w, https://substackcdn.com/image/fetch/$s_!1ZIj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png 1272w, https://substackcdn.com/image/fetch/$s_!1ZIj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1ZIj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png" width="668" height="662" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:662,&quot;width&quot;:668,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!1ZIj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png 424w, https://substackcdn.com/image/fetch/$s_!1ZIj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png 848w, https://substackcdn.com/image/fetch/$s_!1ZIj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png 1272w, https://substackcdn.com/image/fetch/$s_!1ZIj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6e12cb2c-be0a-44da-ab5d-97d91d530a01_668x662.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>These nine kinds of Connascence were identified by Meilir Page-Jones in his book <em>Fundamentals of Object-oriented Design in UML</em>, and I discussed Connascence at length in the article <a href="https://explicitcoupling.substack.com/p/what-happened-to-connascence">What Happened to Connascence?</a></p><p>Page-Jones suggests that the first five kinds of Connascence can be discovered through static analysis of the code, whereas the last four can only be discovered at runtime. Ross is thus asking whether the boundary between Explicit and Implicit Coupling lies at the same point as Page-Jones&#8217;s boundary between the static and dynamic kinds of connascence.</p><p>In response, the first thing I would note is that static analysis often requires an omniscient view of the codebase, whereas in these articles I want to steer the notion of Explicit Coupling towards always being <em>local<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></em>. My working hypothesis is that the correspondence suggested by Ross doesn&#8217;t hold. But right now we&#8217;ve explored only a couple of code samples, and so I&#8217;m not prepared to make a commitment either way just yet. I believe we&#8217;ll need to explore many, many more examples of coupling before we can hypothesise that every example of Connascence of Algorithm, for example, can be viewed as Explicit Coupling.</p><p>Secondly, and as I wrote in <a href="https://habitablecode.substack.com/p/what-happened-to-connascence">What happened to Connascence?</a>, it is by no means clear to me that every specific example of coupling can be assigned to exactly one kind of connascence. I believe that connascence is a great &#8220;starter kit&#8221; for helping to find coupling that might otherwise be difficult to see; but I don&#8217;t find connascence to be useful beyond that point. We&#8217;ve found some coupling &#8212; great, now let&#8217;s stop worrying about how we found it and instead focus on improving the habitability of our code.</p><p>To sum up, to my mind connascence and implicit vs explicit coupling are addressing different problems:</p><ul><li><p>The Connascence catalogue can help us find coupling;</p></li><li><p>Implicit Coupling is how we decide whether we need to fix it; and</p></li><li><p>Explicit Coupling is about how we want the code to look after we&#8217;ve fixed it.</p></li></ul><p>Of course, that&#8217;s (probably) a gross simplification. But I&#8217;ve confused huge numbers of people in the past by talking about Connascence as if it solves all of our problems on its own, so maybe a simplification is just what we need right now&#8230;</p><div><hr></div><p>Please do keep sending me your questions, because by answering them I&#8217;m exploring <em>my</em> topic from <em>your</em> perspective. That&#8217;s really helping me to see past the things I&#8217;ve already skipped past or taken for granted, so thank you!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/p/static-and-dynamic-analysis/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/p/static-and-dynamic-analysis/comments"><span>Leave a comment</span></a></p><p>You can leave a question by commenting on any of these articles (button above &#128578;), or by replying to your subscription email (you <em>are</em> subscribed, right?), or by messaging me via any of these means:</p><ul><li><p>Email: <a href="mailto:kevin@rutherford-software.com">kevin@rutherford-software.com</a></p></li><li><p>LinkedIn: <a href="https://www.linkedin.com/in/kevinrutherford/">https://www.linkedin.com/in/kevinrutherford/</a></p></li><li><p>Twitter: <a href="https://twitter.com/kevinrutherford">@kevinrutherford</a></p></li></ul><p>Next up, I plan to answer to Richard&#8217;s question about API coupling&#8230;</p><blockquote><p>Have you thought about integration tests? That could solve some of the issues about the changing contracts</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://habitablecode.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://habitablecode.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I wrote a few paragraphs about the omniscient view in <a href="https://habitablecode.substack.com/p/discount-rules-reflection">Discount rules, some reflection</a>, and I can see now that it probably deserves a few more pages devoted to it. In particular, what does &#8220;local&#8221; mean when encapsulation units are nested within other encapsulation units?</p></div></div>]]></content:encoded></item></channel></rss>