<?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[Pragdave]]></title><description><![CDATA[Opinions on software development, and how we can do it better, from the author of The Pragmatic Programmer and a creator of the Manifesto for Agile Software Development.]]></description><link>https://articles.pragdave.me</link><image><url>https://substackcdn.com/image/fetch/$s_!cZ4d!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F507bc551-27cd-45f0-aeb9-ee3adcff092d_588x588.png</url><title>Pragdave</title><link>https://articles.pragdave.me</link></image><generator>Substack</generator><lastBuildDate>Sat, 18 Apr 2026 04:21:07 GMT</lastBuildDate><atom:link href="https://articles.pragdave.me/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[David Thomas]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[pragdave@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[pragdave@substack.com]]></itunes:email><itunes:name><![CDATA[Pragdave]]></itunes:name></itunes:owner><itunes:author><![CDATA[Pragdave]]></itunes:author><googleplay:owner><![CDATA[pragdave@substack.com]]></googleplay:owner><googleplay:email><![CDATA[pragdave@substack.com]]></googleplay:email><googleplay:author><![CDATA[Pragdave]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Premature Optimization]]></title><description><![CDATA[&#8230;or why I should practice what I preach]]></description><link>https://articles.pragdave.me/p/premature-optimization</link><guid isPermaLink="false">https://articles.pragdave.me/p/premature-optimization</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 14 Oct 2025 14:57:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!thW4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p>I ignored my own advice, burned a day, and proved&#8212;once again&#8212;that <br>I am my own worst client.</p></div><p>Our new book distributor has a talent for inventing things to charge us money for. Dozens of them. We have to account for each of these, assigning costs to individual titles so we can correctly calculate royalties. Easy, right?</p><p>Except the &#8220;per-book&#8221; expenses show up on one statement, and the lump-sum deductions that we end up paying come on another. And each of these lumps can hide a grab-bag of individual expenses, none labeled. All we get is a couple of dates and one random-looking total. We then have to match that total to some combination of expenses.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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 Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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 coding-interview lore, that&#8217;s the <strong>Subset Sum</strong> problem: take a pile of numbers and figure out which combinations add up to a given total.</p><p>It&#8217;s an NP problem; big, scary running time.</p><p>I knew that. And that was the trap.</p><p>Armed with my one dangerous fact, I set out to <em>optimize. </em>Pruning strategies. Grouping likely pairs. A truly deranged idea involving only the last digit of each number, because apparently I hate myself.</p><p>Hours vanished. Lunch went cold. I kept convincing myself the next trick would crack it.</p><p>At last I had something that looked promising, but I needed to be sure it caught <em>all</em> the subsets. So I wrote a brute-force version to test against.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!thW4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!thW4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png 424w, https://substackcdn.com/image/fetch/$s_!thW4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png 848w, https://substackcdn.com/image/fetch/$s_!thW4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png 1272w, https://substackcdn.com/image/fetch/$s_!thW4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!thW4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png" width="1456" height="685" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:685,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!thW4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png 424w, https://substackcdn.com/image/fetch/$s_!thW4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png 848w, https://substackcdn.com/image/fetch/$s_!thW4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.png 1272w, https://substackcdn.com/image/fetch/$s_!thW4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff720a8bd-fb4a-426f-8a02-1ba8f71616f9_1730x814.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 set it running and shoved my chair back, ready to walk the dog while it ground away for hours. Before I&#8217;d even stood up, the prompt blinked back.</p><p>That couldn&#8217;t be right&#8212;must be a bug. But the output looked fine.</p><p>I hammered it with property-based tests. All green. It finished in milliseconds.</p><p>I&#8217;ve stood on countless stages quoting Knuth&#8217;s immortal line: <em>&#8220;Premature optimization is the root of all evil.&#8221; </em>And then I went and sacrificed a day on the altar of exactly that.</p><p><strong>Physician, heal thyself.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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 Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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[The Kindness of Strangers]]></title><description><![CDATA[Open source may not be open forever&#8230;]]></description><link>https://articles.pragdave.me/p/the-kindness-of-strangers</link><guid isPermaLink="false">https://articles.pragdave.me/p/the-kindness-of-strangers</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 23 Sep 2025 00:37:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!svUI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!svUI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!svUI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg 424w, https://substackcdn.com/image/fetch/$s_!svUI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg 848w, https://substackcdn.com/image/fetch/$s_!svUI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!svUI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!svUI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg" width="1456" height="842" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:842,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1794006,&quot;alt&quot;:&quot;&quot;,&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;:&quot;https://pragprog.substack.com/i/174269120?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc007455f-1bd7-4b16-8571-b381a24648fa_3456x5184.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!svUI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg 424w, https://substackcdn.com/image/fetch/$s_!svUI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg 848w, https://substackcdn.com/image/fetch/$s_!svUI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!svUI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b15876-09b9-4c6d-b9e5-bed1a9cf1cff_3456x1999.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://unsplash.com/@barsuklis?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Dana Sarsenbekova</a> on <a href="https://unsplash.com/photos/a-hand-holding-a-small-red-flower-GJt1N8FnImI?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure></div><p>This last week, the Ruby world was jittery. What happened, though, has far wider ramifications.</p><p>The whole situation is still unclear, but here&#8217;s my current understanding.</p><p>The Ruby Central organization is partly funded by corporate sponsors. Some of these companies apparently became concerned about so-called supply-chain vulnerabilities, where malicious parties were injecting bad code into libraries.</p><p>It seems that maintainer access to the RubyGems archive was fairly informal. Over the years, access had been given to folks who needed it. Sometimes this access was still open even though the individuals no longer worked on gems. The financial sponsors of Ruby Central (quite rightly) viewed this as a threat, and demanded that Ruby Central take action.</p><p>Ruby Central had apparently been given a deadline. The day that deadline expired, they seem to have panicked. They moved the ownership of the RubyGems repository to their own organization, and they seem to have removed the access of maintainers who did not work for (or have a formal contract with) Ruby Central.</p><p>Some of those maintainers posted their displeasure, and the socialverse did what is supposed to do, overreacting and inflaming the situation.</p><p>I have to stress, this is all supposition, based on culling through other people&#8217;s posts.</p><p>It is clear that Ruby Central botched their handling of this. It shouldn&#8217;t have come down to the wire without having some public consultation, and the takeover of the repository should likewise have been explained as it happened.</p><p>But that doesn&#8217;t matter. A month from now, this will all be history. But that doesn&#8217;t mean we write this off as &#8220;geeks don&#8217;t communicate well *shrug*.&#8221; There&#8217;s an important warning buried in all the agita.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">Speaking about the kindness of strangers&#8230; please consider subscribing. It&#8217;s free!</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="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7g86!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7g86!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!7g86!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!7g86!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!7g86!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7g86!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6675452,&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;:&quot;https://pragprog.substack.com/i/174269120?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!7g86!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!7g86!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!7g86!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!7g86!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F381333ec-a715-4127-b984-c2d73adc1f9f_6000x4000.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://unsplash.com/@jasonpofahlphotography?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Jason Pofahl</a> on <a href="https://unsplash.com/photos/a-bunch-of-metal-boxes-stacked-on-top-of-each-other-6AQY7pO1lS0?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure></div><blockquote></blockquote><div class="pullquote"><p><em><strong>The World Literally Relies on Open-Source Governance</strong></em></p></div><p>Linux powers 96% of the worlds one-million largest servers.</p><p>The modern web relies on JavaScript, and JavaScript relies on the NPM repository.</p><p>Shopify, Netflix, AirBnB, and many other household names have systems build on Rails. Laravel probably powers more sites than Rails.</p><p>This is all open source software, maintained by and large by unpaid volunteers.</p><p>These people are dedicated and largely unthanked. They put in hour after hour, adding features and fixing bugs. In a very real sense, these people keep the modern world running.</p><p>These people would never dream of adding malicious code to their projects.</p><p>But what happens if they decide it just isn&#8217;t worth it? Or what if the various foundations who are the stewards of larger open source projects accidentally mess things up?</p><p>What happens if the open source framework on which we build our palaces of code starts to rot? Do you have insurance? Because the open source model will change.</p><h1><strong>Open Source Insurance</strong></h1><p>Here are some things you can do to mitigate your exposure to these types of issue:</p><h3><strong>Do You Really Need It?</strong></h3><p>Before adding a dependency to your project, ask if you really need it.</p><p>Sometimes the thing your are adding is so trivial, you might as well just implement it yourself. The <code>left_pad</code> fiasco of 2016 is a great example. It was literally a dozen or so lines of code that left-padded a string, and yet thousands of projects decided to add it as a dependency rather than write it themselves. Then the developer deleted his code, and projects the world over stopped building.</p><p>Sometimes you add a dependency because it lets you do something cool: fancy UI affordances are a great example. Does the customer really need the functionality?</p><h3><strong>Do You Really Need All of It?</strong></h3><p>Ruby on Rails is a proud, large, monolith. A brand new Rails app installs over 700 dependencies, which means your project is depending on 700 separate projects over which you have no control or insight.</p><p>Sometimes you need the whole thing. But quite often, you can get by with smaller and more targeted libraries.</p><p>This isn&#8217;t just a Rails issue. If anything, front end JavaScript frameworks are even worse, often starting out with literally thousands of installed libraries.</p><h3><strong>Do You Have It in Version Control?</strong></h3><p>NPM suddenly goes dark. Ruby Central runs out of money and shuts down Gems. What happens the next time you check out your project to make a change and <code>npm</code> or <code>bundle install</code> 404s?</p><p>Maybe it&#8217;s time to run a local mirror of the stuff you use, or add your installed libraries to your project&#8217;s repo.</p><h1><strong>Is This Really Necessary?</strong></h1><p>Do I think that any major library repository will just vanish? No, I don&#8217;t.</p><p>But, it is still a possibility. And if that happens, will your project survive? Insurance is always a hard sell, but it&#8217;s often a prudent purchase.</p><h4><em><strong>And&#8230;</strong></em></h4><p>It is well past the time where we should have come up with a fair and transparent way of dealing with the burden of developing and maintaining the software that underlies our whole world.</p><p>Seems to me that open source contributions are a <em>proof of work</em>, and are a more worthy basis of value than some cryptographic bit juggling. Maybe there&#8217;s a new cryptocurrency lurking in there. Just sayin&#8217;.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/the-kindness-of-strangers?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/the-kindness-of-strangers?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/the-kindness-of-strangers/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://articles.pragdave.me/p/the-kindness-of-strangers/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[On Being a Developer]]></title><description><![CDATA[A small rant]]></description><link>https://articles.pragdave.me/p/on-being-a-developer</link><guid isPermaLink="false">https://articles.pragdave.me/p/on-being-a-developer</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 16 Sep 2025 22:34:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!WmhG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WmhG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WmhG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!WmhG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!WmhG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!WmhG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WmhG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1681912,&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;:&quot;https://articles.pragdave.me/i/173799917?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WmhG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!WmhG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!WmhG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!WmhG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F240f8791-980c-43db-888c-38251ba3006f_6000x4000.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://unsplash.com/@_staticvoid?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Lucas Santos</a> on <a href="https://unsplash.com/photos/blue-and-purple-lights-on-black-background-VaTJhvMBGNA?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure></div><p>Some of the chatter over on <a href="https://www.linkedin.com/in/dave-thomas-53aa1057/">LinkedIn</a> rubbed me up the wrong way, so I posted the following:</p><blockquote><p><em>The true measure of a software developer is being able to deliver value in the simplest possible way.<br><br>It isn't knowing the latest languages, frameworks, or techniques; it's knowing when not to use them.<br><br>It isn't delivering lots of sparkly new features; it's delivering the one feature that gives its users the leverage they need.<br><br>It isn't sitting behind a screen 16 hours a day; it's knowing who to talk to and building relationships.<br><br>It isn't being right; it's being an inspiration.</em></p></blockquote><p>I thought it might be fun to dig into this a little.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">To receive new posts and support my work, please consider becoming a free or paid subscriber.</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><h4>&#8230; deliver value in the simplest possible way.</h4><p>In the daily grind of producing code, it&#8217;s easy to forget that we&#8217;re not paid to program, or write tests, or stand in daily scrums; we&#8217;re paid to create something that helps someone else to something better. We&#8217;re paid to deliver value.</p><p>End users don&#8217;t care how many design patterns we used, or our test coverage ratio, or our velocity. They care that it works, that it was delivered in a reasonable time, and that, if necessary, it can be changed.</p><p>Which means it&#8217;s our job to discover where the value is, and to produce that value using simple code. That&#8217;s a skill founded in experience and confidence, and it&#8217;s not something AIs can currently do.</p><h4>&#8230; knowing when not to use (languages, frameworks, and techniques)</h4><p>If we are going to create simple solutions, we need to think hard about every technology we use: is it carrying it&#8217;s load? Sure, it&#8217;s fun and educational to try a new language, but is it necessary to do it on production code? We all love a good framework or library, but are they strictly necessary? Every external piece of code in a project adds dependencies and complexities, and each adds to the vulnerabilities of the app. Typical JavaScript projects now have thousands of dependencies, and each of those acts as a little anchor, holding you back when you want to change stuff.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MvQ6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MvQ6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!MvQ6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!MvQ6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!MvQ6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MvQ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg" width="1456" height="972" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:972,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:645056,&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;:&quot;https://articles.pragdave.me/i/173799917?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MvQ6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!MvQ6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!MvQ6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!MvQ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd41a1a4a-b711-4f3e-8127-172b146db56f_4496x3000.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://unsplash.com/@blurrystock?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">blurrystock</a> on <a href="https://unsplash.com/photos/closeup-photography-of-mechanical-computer-keyboard-HIbAmybJHVs?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure></div><p></p><h4>&#8230;deliver the one feature that gives its users the leverage they need</h4><p>Let&#8217;s face it: features are fun. All those little bells and whistles we add to our code are our way of showing off a little, of showing our mastery. But that&#8217;s not what our customers notice (or want). These people likely use your applications a lot: they know how to drive them and what to expect. They don&#8217;t need flair and features: these just get in their way. Look at some of the most popular systems on the Web. Wordpress admin screens look like they were designed by the same people who did Craigslist and Hacker News; in your face 1990s HTML. Doesn&#8217;t stop them being popular, does it?</p><h4>&#8230;building relationships</h4><p>Programming has never been about coding. That&#8217;s a good thing, because code is becoming a commodity. No, a good developer is an intermediary between the messy, poorly specified real world and the tightly constrained and unforgiving world of machines. The defining characteristic of a good developer is that they are comfortable in both of these worlds, and they know how concepts translate between them.</p><p>More and more, that role depends on interacting with people: customers, managers, other developers. Building relationships not only helps you do your job better; it most likely will help you find your next job.</p><h4><br>It isn't being right; it's being an inspiration</h4><p>In the end, no one cares if you&#8217;re right or wrong. They care about how you make them feel. They don&#8217;t need to be told what to do; thy need to see you doing it, and to be inspired to try it, too. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://pragprog.com/titles/dtcode/simplicity/" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bnmI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg 424w, https://substackcdn.com/image/fetch/$s_!bnmI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg 848w, https://substackcdn.com/image/fetch/$s_!bnmI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!bnmI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bnmI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg" width="500" height="617" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:617,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:22339,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:&quot;https://pragprog.com/titles/dtcode/simplicity/&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://articles.pragdave.me/i/173799917?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bnmI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg 424w, https://substackcdn.com/image/fetch/$s_!bnmI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg 848w, https://substackcdn.com/image/fetch/$s_!bnmI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!bnmI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd3d7050-2edb-4b22-8beb-2f90baa2c6bf_500x617.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></p><p></p><p>Am I wrong? Please comment,</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/on-being-a-developer/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://articles.pragdave.me/p/on-being-a-developer/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/on-being-a-developer?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/on-being-a-developer?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[The Sorcerer's Apprentice]]></title><description><![CDATA[or "Don't Invoke a Spell You Can't Control"]]></description><link>https://articles.pragdave.me/p/the-sorcerers-apprentice</link><guid isPermaLink="false">https://articles.pragdave.me/p/the-sorcerers-apprentice</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 12 Aug 2025 17:00:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!glv6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!glv6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!glv6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic 424w, https://substackcdn.com/image/fetch/$s_!glv6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic 848w, https://substackcdn.com/image/fetch/$s_!glv6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic 1272w, https://substackcdn.com/image/fetch/$s_!glv6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!glv6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic" width="1016" height="682" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:682,&quot;width&quot;:1016,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:193227,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://articles.pragdave.me/i/170800956?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!glv6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic 424w, https://substackcdn.com/image/fetch/$s_!glv6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic 848w, https://substackcdn.com/image/fetch/$s_!glv6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic 1272w, https://substackcdn.com/image/fetch/$s_!glv6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F196ebcf0-ed8e-4642-b2f8-b7cf5f651a88_1016x682.heic 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 magician leaves the apprentice with a chore: &#8220;sweep up the workshop.&#8221; The apprentice, now alone, starts the task, but soon gets bored. They use a spell they&#8217;d heard the magician cast that causes the broom to start cleaning on its own. But the broom soon gets out of control, spilling water everywhere, and the apprentice doesn&#8217;t know that incantation to stop it. Everything else the apprentice does makes things worse. Eventually, the magician returns and order is restored.</p><p>Goethe&#8217;s poem was written in 1797. The story is acting out today, 230 years later.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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 Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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>Be Careful What You Wish For</h2><p>In the modern world, the coding LLM is the magic, the prompt is the spell, and the unfortunate developer is the apprentice.</p><p>All too often, we hear stories where developers invoke a prompt: &#8220;write a program that &#8230;&#8221; and the AI obliges. But the developer doesn&#8217;t understand what they&#8217;ve asked for, or what the AI produces. It&#8217;s all just magic.</p><p>And because they don&#8217;t understand, they have no way of knowing if it is correct. They don&#8217;t know if it is a reasonable implementation, whether it will fit in with the rest of the company&#8217;s infrastructure, whether it will be maintainable. They are just passengers, along for the ride. And they better hope that there&#8217;s a sorcerer somewhere in the background who can dig them out of whatever mess their magic creates.</p><p>I normally hate rules, but here&#8217;s one I can get behind:</p><h2>The AI Rule</h2><div class="pullquote"><h2><strong>Never get an AI to write code <br>that you couldn&#8217;t have written yourself.</strong></h2></div><p>AI is a tool that amplifies your ability to code. It does not replace your understanding of what needs to be done, and it won&#8217;t take the blame if what it produces is wrong.</p><p>You have to know the basics. You have to know design, and techniques, and performance, and the thousand other things, both large and subtle, that make you a developer.</p><p>And all that comes from doing the work up front&#8212;from experience and judgement.</p><p>AI is not deskilling development: if anything it requires more skill of us.</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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 Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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[An Employer's Guide To Hiring Developers]]></title><description><![CDATA[hint: programming challenges are a dumb idea]]></description><link>https://articles.pragdave.me/p/an-employers-guide-to-hiring-developers</link><guid isPermaLink="false">https://articles.pragdave.me/p/an-employers-guide-to-hiring-developers</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Sun, 03 Aug 2025 03:43:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!fCl1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>(A shorter version of this article appeared in the <a href="https://pragprog.com/newsletter">Pragmatic Bookshelf newsletter</a>.)</em></p><p>Jan turns up at her 12th interview. The interviewer hands her a marker and points to the whiteboard. "Go ahead and write out the code to calculate the weight of minimum spanning tree of a connected, weighted, and undirected graph." Jan sighs: third time this month. She sets to work.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fCl1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fCl1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg 424w, https://substackcdn.com/image/fetch/$s_!fCl1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg 848w, https://substackcdn.com/image/fetch/$s_!fCl1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!fCl1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fCl1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg" width="680" height="599" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:599,&quot;width&quot;:680,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35651,&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;:&quot;https://articles.pragdave.me/i/169271222?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fCl1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg 424w, https://substackcdn.com/image/fetch/$s_!fCl1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg 848w, https://substackcdn.com/image/fetch/$s_!fCl1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!fCl1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7a0fa7a-f89c-441f-b022-8f545a904ef8_680x599.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://unsplash.com/@charlesdeluvio">charles deluvio</a> on <a href="https://unsplash.com/s/photos/interview?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure></div><p>In my opinion, she shouldn't get the job based in this performance, however practiced the answer.</p><p>For me, a good candidate would put the pen down and ask, "Could you give me the context for this, because I'd hope you'd want programmers to use an AI (or a library) to handle this kind of problem. I was looking for a job that lets me do things your AIs can't do."</p><p>Challenge-based coding interviews were always a bad idea: they put the focus on the least important skill of a potential hire, memory. Let's list some of the more important skills that the challenge interview doesn't test:</p><ul><li><p>communication skills, including the ability to question authority in a polite, productive way;</p></li><li><p>context building skills: framing a problem in its larger setting before blindly coding;</p></li><li><p>knowledge of a spectrum of available approaches to solving a problem, and the tradeoffs between them;</p></li><li><p>the ability to work in a team;</p></li><li><p>and so on.</p></li></ul><p>I&#8217;ve never understood why anyone would consider the ability to write down some random algorithm would be a predictor of success in a job. I have a little more sympathy for questions which ask about selecting a good algorithm or data structure, but, even then, why wouldn&#8217;t you let the candidate use resources that would be available to them in their when they were working for you? </p><p>Ask yourself: who would be a better fit on your team: someone who&#8217;d memorized all four volumes of The Art of Computer Programming but who refused to work with other people, or someone who&#8217;d cheerily admit they didn&#8217;t know something, but who did know how to look it up, and then would happily share what they&#8217;d learned with others?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">Go on. Stroke my ego.</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><h3>Flip The Interview</h3><p>Some secondary schools run a flipped curriculum. Rather than learning in the classroom and practicing at home with homework, they ask the student to study the material at home and then come in with questions, prepared to try some examples in class, where help is at hand</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fe0c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fe0c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg 424w, https://substackcdn.com/image/fetch/$s_!fe0c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg 848w, https://substackcdn.com/image/fetch/$s_!fe0c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!fe0c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fe0c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg" width="1030" height="688" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:688,&quot;width&quot;:1030,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:275522,&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;:&quot;https://articles.pragdave.me/i/169271222?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fe0c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg 424w, https://substackcdn.com/image/fetch/$s_!fe0c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg 848w, https://substackcdn.com/image/fetch/$s_!fe0c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!fe0c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0584a650-7a89-4739-b0ee-baa51ffde0af_1030x688.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>That sounds like a great model for job interviews. Send the candidate a real problem that they are likely to encounter in the first six months of their job. Express it in the way that a team member would normally be given a task. Tell them you don't want a solution. Instead, when they come in, they'll be sitting in a room with you and a couple of team members. </p><p>Their task is to ask questions that will lead them to enough of an understanding to be able to start attacking the problem. When they are satisfied, ask what their plan would be to implement it. Make sure they're incorporating small steps and feedback. You don&#8217;t want them actually to do the implementation, if for no other reason than the problem is likely to be big enough that this wouldn&#8217;t be practical. Instead, you&#8217;re look for a realistic approach, with <em>small steps</em> and <em>lots of feedback</em>.  The first few steps will be fairly specific, but should then quickly become fuzzier and conditional on the results of prior steps.</p><p>Finally, tell them that, two weeks into coding, the requirement X has changed to Y. What impact will that have? For more senior candidates, make the requirements change something that is clearly a bad idea and see if they push back.</p><h3>Hire The Person, Not The Skills</h3><blockquote><p>Today, basic coding skills can be recruited by buying more AI tokens. You shouldn't be hiring based on that.</p></blockquote><p>But AI does not (currently) have the higher level, more global skills that people have. An AI is less likely to remember that Joe in fulfillment once mentioned that you should never schedule deliveries to Topeka on a Wednesday, or remember that someone at the local user group mentioned issues they&#8217;d had with a library.</p><p>Recruiting based on performance executing a challenge is an incredibly Taylorist<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> approach to hiring: it reeks of stopwatches and clipboards. We&#8217;ve moved on from that over the last hundred years. </p><p>You're hiring a person. Make sure the process you use evaluates the candidates as people, and not as algorithm-writing automata.</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><em><a href="https://en.wikipedia.org/wiki/Scientific_management">Scientific Management</a></em> is an approach to process management in manufacturing pioneered by Frederick Taylor between 1880 and 1915. Each job role was meticulously analyzed, and workers were told the exact steps they should follow to perform optimally. When they did, they were rewarded with higher pay.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Should People Learning to Code Use AI?]]></title><description><![CDATA[tldr; yes and no]]></description><link>https://articles.pragdave.me/p/should-people-learning-to-code-use</link><guid isPermaLink="false">https://articles.pragdave.me/p/should-people-learning-to-code-use</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Thu, 17 Jul 2025 18:50:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Mi-3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was contacted by someone just starting to learn programming. They asked whether they should use AI from the start, or learn the basics first.</p><p>I think that&#8217;s a very deep question. Maybe stop for a minute and think how you&#8217;d answer.</p><h2>Motivation</h2><p>I found it most useful to recast the question.</p><p>In an age where children have constant access to their phones, do they need to learn arithmetic?</p><p>I&#8217;ve heard folks online say &#8220;no&#8221; to this. &#8220;They&#8217;ll never have to manually add up numbers or calculate a percentage. Let them explore more interesting things.&#8221;</p><p>I disagree with this, but not because I believe everyone should know what seven times nine equals.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Mi-3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Mi-3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Mi-3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Mi-3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Mi-3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Mi-3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg" width="432" height="434.448" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3017,&quot;width&quot;:3000,&quot;resizeWidth&quot;:432,&quot;bytes&quot;:2486930,&quot;alt&quot;:&quot;gray concrete stairs inside building&quot;,&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="gray concrete stairs inside building" title="gray concrete stairs inside building" srcset="https://substackcdn.com/image/fetch/$s_!Mi-3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Mi-3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Mi-3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Mi-3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91c9ac22-cd21-4a2f-a130-57a7745a14be_3000x3017.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://unsplash.com/@gmalhotra?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Gayatri Malhotra</a> on <a href="https://unsplash.com/photos/gray-concrete-stairs-inside-building-4wF66_KWJxA?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure></div><p>My thinking is that numbers are the first step towards building an intuition about more useful things: ratios and percentages, speed vs. acceleration, compound growth&#8212;these are all intensely practical things. Until you have some kind of feel for them, you will be unable to make meaningful decisions when faced with a bunch of important life choices. We learn arithmetic not because we need to know what twelve divided by three is, but because we need the intuition that twelve divided by three is larger than twelve divided by six. We live in a world ruled by numbers; if you don&#8217;t know how those numbers behave, you&#8217;re at a disadvantage.</p><p>I could go on, or I could draw other parallels (do kids need to learn to history? geography? languages? &#8230;?). But every point would come to the same conclusion. Some skills are important because they are foundational to building an intuition about the world in which we operate.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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 Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><h2>Intuition</h2><p>The aim of learning is not to remember what you&#8217;re taught, but instead to make that experience accessible when it is needed. </p><p>If I say &#8220;two plus two equals,&#8221; the word &#8220;four&#8221; will pop into your head without you thinking about it. There&#8217;s no recall; it&#8217;s just intuitive. If you&#8217;re driving past a street sign your mind will likely read what it says, even if you don&#8217;t ask it to. It&#8217;s just an inate ability, learned through repetition and practice when we were young.</p><p>It is this ability to handle things below the level of conscious thought that allows us to function. </p><p>Look out the window. Maybe you see trees with leaves rustling in the wind. Maybe you hear cars driving by. Maybe you smell that bakery down the street. </p><p>How much information is arriving via your senses? What is the bandwidth we handle when we simply exist? As raw data, it must be many, many megabits each second. If we had to process all that consciously, we&#8217;d melt.</p><p>That&#8217;s why the level of thought below consciousness is so important. It&#8217;s the LLM we have been training all our lives to recognize patterns and make suggestions based on what it finds.</p><p>Back to coding.</p><h2>Do You Use AI When Learning to Code?</h2><p>My answer is that &#8220;it depends.&#8221; Why are you learning to code? Do you have some cool idea for a killer app that you need to get to MVP? Vibe away. Do you want to build a career in software development? The basics will help.</p><p>If learning to code simply means getting better at prompting Claude to write something for you, then you are choosing to limit your experience; you are choosing not to build an intuitive understanding of what the code does and why it does it. And that&#8217;s absolutely fine, but you have to know going in that you&#8217;re building on an unknown foundation. If cracks appear later, you won&#8217;t really be in a position to know why.</p><p>If, instead, you decide to forego the AI, then you&#8217;re going to go slowly. You&#8217;re going to make mistakes and experience frustration, both made worse by the knowledge that an LLM could tell you what&#8217;s wrong in seconds.</p><p>But those mistakes and frustrations are necessary if you are trying to understand how things work; these are the feedback paths that build and cement intuition.</p><p>The vast majority of experienced developers use AI every day. But they all tell me the same story: you have to keep an eye on what it&#8217;s doing, and you have to guide it towards solutions you want it to use. To do that, you have to have an idea when you start of how things will play out; you must have the experience to be able to see the overall structure of what you&#8217;re building, and to be able to predict likely issues and choices that will mitigate them. To use AI effectively, you pretty much have to know what it is doing for you.</p><h2>The AI Paradox</h2><p>If want a career when you get computers to create value for people, then you need to build the intuition; you need to do things manually and make mistakes.</p><p>But there&#8217;s the paradox. AI is an incredible tool in the hands of an experienced developer, but how do you get to be an experienced developer without using AI? Companies are unlikely to hire someone who does something as old-fashioned as writing all their own code.</p><p>So here&#8217;s what I&#8217;d suggest. If you really want to get good at doing what we used to call &#8220;programming,&#8221;  adopt a hybrid approach.</p><p>You must build intuition, and that means learning. It means trying stuff, making mistakes, rereading the same paragraph in an article a dozen times until it clicks. There&#8217;s no fast-path to experience.</p><p>But&#8230; as you start to cement that understanding into your intuition, you can start to use AI tools to facilitate using what you&#8217;ve learned. Once you know the multiple ways of summing a list of numbers, you could probably get an LLM to write that code for you,  letting you focus on the higher level things you are learning.</p><h2>Discipline</h2><p>Once you allow an AI into your editor, then you are living with constant temptation. &#8220;I could write that for you, you know&#8221; is a dangerous thing to hear when you&#8217;re struggling to master something. It might be possible to tell your ASI assistant that you only want help up to a certain level: &#8220;please help me write basic control structures, but leave the higher level function organization to me.&#8221; I&#8217;ve played a little with this, but without much success.</p><p>So, as with most things, becoming good requires motivation and discipline.</p><p>Personally, I find the rewards are worth it. What do you think?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/should-people-learning-to-code-use/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://articles.pragdave.me/p/should-people-learning-to-code-use/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/should-people-learning-to-code-use?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/should-people-learning-to-code-use?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Job Titles Are Lazy Labels]]></title><description><![CDATA[It's time to stop using simplistic labels for complex individuals]]></description><link>https://articles.pragdave.me/p/job-titles-are-lazy-labels</link><guid isPermaLink="false">https://articles.pragdave.me/p/job-titles-are-lazy-labels</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Sun, 06 Jul 2025 21:18:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!RLL1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RLL1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RLL1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png 424w, https://substackcdn.com/image/fetch/$s_!RLL1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png 848w, https://substackcdn.com/image/fetch/$s_!RLL1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png 1272w, https://substackcdn.com/image/fetch/$s_!RLL1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RLL1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png" width="496" height="365" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:365,&quot;width&quot;:496,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:269248,&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;:&quot;https://articles.pragdave.me/i/167667582?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RLL1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png 424w, https://substackcdn.com/image/fetch/$s_!RLL1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png 848w, https://substackcdn.com/image/fetch/$s_!RLL1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.png 1272w, https://substackcdn.com/image/fetch/$s_!RLL1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67e535e9-e3ef-4cad-abc4-894b492baea6_496x365.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;ve been working with a company in Belgium, helping them refine their team structures and development processes. This week, the topic turned to job titles. They asked what I thought about assigning titles like <em>Junior Developer</em>, <em>Developer</em>, and <em>Senior Developer</em>.</p><p>I recoiled. I wasn&#8217;t sure why&#8212;so I did what any self-respecting consultant does and deflected with a question:</p><p>&#8220;What&#8217;s your intent here?&#8221;</p><blockquote><p>We want to give people a set of objective requirements for each role, in order to give them something to aim for.</p></blockquote><p>&#8220;Could you give me some examples?&#8221;</p><blockquote><p>Well, a junior developer on the modelling team has to be able to create and manipulate simple 3d objects in Blender, and they have to be able to perform basic image manipulation tasks in Photoshop.&#8221;</p></blockquote><p>That clarified things. There wouldn&#8217;t be one set of requirements per role. Instead, each specialty&#8212;modeling, coding, and so on&#8212;would have its own separate expectations at each level.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5uwJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5uwJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png 424w, https://substackcdn.com/image/fetch/$s_!5uwJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png 848w, https://substackcdn.com/image/fetch/$s_!5uwJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png 1272w, https://substackcdn.com/image/fetch/$s_!5uwJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5uwJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png" width="857" height="526" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:526,&quot;width&quot;:857,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:347658,&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;:&quot;https://articles.pragdave.me/i/167667582?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5uwJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png 424w, https://substackcdn.com/image/fetch/$s_!5uwJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png 848w, https://substackcdn.com/image/fetch/$s_!5uwJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.png 1272w, https://substackcdn.com/image/fetch/$s_!5uwJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c0761af-10f3-47f1-859e-aff73de0541c_857x526.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>So I got to thinking. Suppose there are half a dozen high-level requirements in each area: <em>Junior/Modeling</em>, <em>Senior/Coding</em>, and so on. What do you do with a modeler who&#8217;s world-class in Blender but hopeless in Photoshop? Are they a <em>Junior</em> because of the Photoshop gap? A <em>Senior</em> because of their Blender mastery? Or maybe a <em>Middling</em> Modeler because you couldn&#8217;t decide?</p><h3>We Label People When We&#8217;re Too Lazy To Know Them</h3><p>We live in a world where people are dropped into buckets based on labels: <em>Republican/Democrat</em>, <em>Liverpool/Everton</em>, <em>Junior/Senior Developer</em>. And that labeling encourages the insularity of opinion we see everywhere.</p><p>Reality is messier and more nuanced. Someone might align mostly with Republican values but support parts of the Democrat platform. A Liverpool fan might secretly admire a Toffee&#8217;s striker. And a so-called junior developer might already have senior-level skills in a niche area.</p><p>These high-level labels are a management convenience. But they shortchange both the individual and the organization.</p><h3>What If We Gamified It?</h3><p>On the call, I suggested an alternative to these blanket titles. I asked if they could go back to their original requirements and break them down into individual skill challenges: <em>Basic Blender</em>, <em>Photoshop Novice</em>, <em>Blender Wizard</em>, and so on.</p><p>Each challenge would have specific, objective criteria. And when someone completed one, they&#8217;d earn a badge, trophy, or silly award. Over time, folks would collect trophies across specialties and levels&#8212;physical tokens they could display on their desk or laptop.</p><p>You could even lean into the game aspect. Every quarter, host a light-hearted showdown: two <em>Photoshop Wizards</em> go head-to-head on a tricky challenge, with their screens projected for all to see. A bit of fun&#8212;and a great way to pick up new tricks.</p><p>To my surprise, they jumped at this idea. They&#8217;re now rethinking the <em>Junior/Mid/Senior</em> hierarchy, replacing it with individual skill tracks. Their new system has three goals:</p><ul><li><p><strong>Identify people&#8217;s actual skills</strong>, so projects can tap into the right talent.</p></li><li><p><strong>Create personalized career paths</strong>, instead of promoting people based on checklists.</p></li><li><p><strong>Encourage learning through playful competition</strong>, sparking curiosity and motivation.</p></li></ul><p>It will be interesting to see how that works out over the coming year. </p><p><strong>What do you think?</strong></p><div><hr></div><p>Facing an interesting challenge? I&#8217;m at <a href="mailto:dave@pragdave.me">dave@pragdave.me</a></p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/job-titles-are-lazy-labels/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://articles.pragdave.me/p/job-titles-are-lazy-labels/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/job-titles-are-lazy-labels?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/job-titles-are-lazy-labels?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Simplicity, Agility, and Agency]]></title><description><![CDATA[Development doesn't have to be this complicated]]></description><link>https://articles.pragdave.me/p/simplicity-agility-and-agency</link><guid isPermaLink="false">https://articles.pragdave.me/p/simplicity-agility-and-agency</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Wed, 25 Jun 2025 17:20:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!YNA6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YNA6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YNA6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png 424w, https://substackcdn.com/image/fetch/$s_!YNA6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png 848w, https://substackcdn.com/image/fetch/$s_!YNA6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png 1272w, https://substackcdn.com/image/fetch/$s_!YNA6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YNA6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png" width="346" height="345" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:345,&quot;width&quot;:346,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:66104,&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;:&quot;https://articles.pragdave.me/i/166366112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YNA6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png 424w, https://substackcdn.com/image/fetch/$s_!YNA6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png 848w, https://substackcdn.com/image/fetch/$s_!YNA6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.png 1272w, https://substackcdn.com/image/fetch/$s_!YNA6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b7b5e81-02d3-4f92-b8c6-1ef04d51ef63_346x345.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 was one of the people who helped create the Manifesto for Agile Software Development. I&#8217;m proud of what we did, and I still believe that the four values are as important today as they were 25 years ago. I had hoped that it might improve the lives of developers, and for a while it did. No longer. What people now call Agile has become the kind of overbearing set of practices that we were rebelling against when we drafted those values.</p><p>For the values of the manifesto to work, we have to change the world. And the world has other things on its mind at the moment.</p><p>But I&#8217;d still like to find ways to improve the developer&#8217;s lot.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">I&#8217;m a programmer who likes to write about the things that interest (or annoy) me. Subscribe for free to get a handful of these articles a month.</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><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!87zk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!87zk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png 424w, https://substackcdn.com/image/fetch/$s_!87zk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png 848w, https://substackcdn.com/image/fetch/$s_!87zk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png 1272w, https://substackcdn.com/image/fetch/$s_!87zk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!87zk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png" width="238" height="231.9042316258352" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:875,&quot;width&quot;:898,&quot;resizeWidth&quot;:238,&quot;bytes&quot;:467530,&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;:&quot;https://articles.pragdave.me/i/166366112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!87zk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png 424w, https://substackcdn.com/image/fetch/$s_!87zk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png 848w, https://substackcdn.com/image/fetch/$s_!87zk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png 1272w, https://substackcdn.com/image/fetch/$s_!87zk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc02f669d-0bb8-4702-8072-0899f7a2c8e3_898x875.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><h2>Take Two</h2><p>We can&#8217;t control our world, or how our company runs. But I&#8217;m startinging to think we don&#8217;t have to. We still control and incredibly potent assets: ourselves.</p><p>We developers tend to forget just how much control we have over our daily lives. Sure, we have structure imposed on us, but that&#8217;s typically at the per-day, per-week, and per-sprint/release level. </p><blockquote><h4>So let&#8217;s stop trying to change <em>the</em> world, and instead focus on changing <em>our</em> world. </h4></blockquote><p>Acknowledging that we can do that is step one. Step two is setting some goals.</p><p>To my mind, there is no bigger goal right now than reducing the insane levels of complexity we work with. </p><p>Some folks may be thinking that the incursion of AI into our working lives is the number one threat. I disagree. AI is a powerful tool, but a lot of its power comes from the fact that it relishes complexity; when you see programs of a whole, as a mesh of parts that interact, you have no need to be limited by human design principles. Who needs DRY when you can immediately see and change every use of a function or some data?</p><p>But that&#8217;s a tactical view. There comes a point where you cannot afford to ignore the structure of what is being built. If interactions in your system grow exponentially with the number of parts, there&#8217;s a point at which no technology can manage it. And by that point, it is too late.</p><p>One of the reasons AI often produces bloated code is that it merely extrapolates from the code it has consumed during training; it is the ultimate <em>but we&#8217;ve always done it that way</em> engine. This is just cargo-culting.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lmpM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lmpM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png 424w, https://substackcdn.com/image/fetch/$s_!lmpM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png 848w, https://substackcdn.com/image/fetch/$s_!lmpM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png 1272w, https://substackcdn.com/image/fetch/$s_!lmpM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lmpM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png" width="227" height="230.13463751438434" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:881,&quot;width&quot;:869,&quot;resizeWidth&quot;:227,&quot;bytes&quot;:410703,&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;:&quot;https://articles.pragdave.me/i/166366112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lmpM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png 424w, https://substackcdn.com/image/fetch/$s_!lmpM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png 848w, https://substackcdn.com/image/fetch/$s_!lmpM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png 1272w, https://substackcdn.com/image/fetch/$s_!lmpM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a9d8fc5-3e20-4681-a150-60a3ad3f1769_869x881.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The sad thing is that human developers do that, too. We look for answers from people who seem to know what they are doing, adopting their designs, tool choices, and often their code to create complex patchworks of code, code that is hard to change, and code that is vulnerable to the inevitable changes in the tools and libraries on which it is built.</p><p>So I come back to the idea of reducing complexity being the most important thing we, as individuals, can do if we want to reclaim control over our daily lives.</p><p>I believe this so strongly that I spent four years writing three books about it. The first two I threw away; I discovered you cannot tell people how to simplify what they do&#8212;simplicity is always contextual. The third book took a different (and, for me, uncomfortable) tack. Rather than tell folks what to do, I give 29 examples of ways I have found, in my particular world, to make what I do simpler. The idea is not to copy me: that wouldn&#8217;t work. Instead, I hope the examples illustrate the thinking behind these simplifications, the feedback loops I used to notice that something was getting complicated and then to monitor my progress as I experimented with simplifying it.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F32C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F32C!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png 424w, https://substackcdn.com/image/fetch/$s_!F32C!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png 848w, https://substackcdn.com/image/fetch/$s_!F32C!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png 1272w, https://substackcdn.com/image/fetch/$s_!F32C!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F32C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png" width="234" height="221.24582869855394" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:850,&quot;width&quot;:899,&quot;resizeWidth&quot;:234,&quot;bytes&quot;:594712,&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;:&quot;https://articles.pragdave.me/i/166366112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F32C!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png 424w, https://substackcdn.com/image/fetch/$s_!F32C!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png 848w, https://substackcdn.com/image/fetch/$s_!F32C!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png 1272w, https://substackcdn.com/image/fetch/$s_!F32C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F889a04cf-2e0f-4934-971d-de3d57e4fe1d_899x850.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Is this article just a lame-ass attempt to <a href="https://pragprog.com/titles/dtcode/simplicity">market my new book</a>?</p><p>Sure.</p><p>But it&#8217;s an article I would have written anyway, book or no book. In many ways, we developers are our own worst enemies. We follow fads, join cults, and adopt practices. We sometimes do this because it looks interesting. More commonly we do it because we hope that one day we&#8217;ll find the silver bullet that puts to rest our fear of failing.</p><p>Ironically, every time we do that, we add complexity and stress to what we do, which in turn just accelerates the cycle.</p><p>So, buy the book if you want. But, regardless, think about how you, personally, can reduce the complexity in your (professional) life. Think about the things you take as a given (exhaustive testing, stand-up meetings, the framework <em>du jour</em>) and ask how you could test to see if they aere actually making things better. How you do things can be refactored in the same way as the things you produce, and the same rules apply: you need an objective, a timebox, and feedback.</p><p>It is difficult to make things simple. It takes a conscious process, applied over time. </p><p>It&#8217;s worth it.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\huge {simplicity: now\\ available\\ in\\ epub,\\ PDF,\\ and\\ print}&quot;,&quot;id&quot;:&quot;RSIAETNNNG&quot;}" data-component-name="LatexBlockToDOM"></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://pragprog.com/titles/dtcode/simplicity&quot;,&quot;text&quot;:&quot;Get the ebook&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://pragprog.com/titles/dtcode/simplicity"><span>Get the ebook</span></a></p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lx89!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lx89!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg 424w, https://substackcdn.com/image/fetch/$s_!lx89!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg 848w, https://substackcdn.com/image/fetch/$s_!lx89!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!lx89!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lx89!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg" width="376" height="463.8021978021978" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1796,&quot;width&quot;:1456,&quot;resizeWidth&quot;:376,&quot;bytes&quot;:196767,&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;:&quot;https://articles.pragdave.me/i/166366112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lx89!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg 424w, https://substackcdn.com/image/fetch/$s_!lx89!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg 848w, https://substackcdn.com/image/fetch/$s_!lx89!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!lx89!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad783e5b-7337-4d56-a8fd-6e96a2a43b18_2250x2775.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><div><hr></div><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/simplicity-agility-and-agency?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/simplicity-agility-and-agency?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nVxw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nVxw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png 424w, https://substackcdn.com/image/fetch/$s_!nVxw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png 848w, https://substackcdn.com/image/fetch/$s_!nVxw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png 1272w, https://substackcdn.com/image/fetch/$s_!nVxw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nVxw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png" width="1456" height="288" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a5d0b596-f897-4785-b915-c6aab440e071_5056x999.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:288,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2351208,&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;:&quot;https://articles.pragdave.me/i/166366112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nVxw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png 424w, https://substackcdn.com/image/fetch/$s_!nVxw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png 848w, https://substackcdn.com/image/fetch/$s_!nVxw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png 1272w, https://substackcdn.com/image/fetch/$s_!nVxw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5d0b596-f897-4785-b915-c6aab440e071_5056x999.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div>]]></content:encoded></item><item><title><![CDATA[Error Monads The Hard Way]]></title><description><![CDATA[I can't decide how to best express the equivalent of Haskell's Error monad and DO block in Ruby...]]></description><link>https://articles.pragdave.me/p/error-monads-the-hard-way</link><guid isPermaLink="false">https://articles.pragdave.me/p/error-monads-the-hard-way</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 03 Jun 2025 18:27:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!nyQb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nyQb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nyQb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png 424w, https://substackcdn.com/image/fetch/$s_!nyQb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png 848w, https://substackcdn.com/image/fetch/$s_!nyQb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png 1272w, https://substackcdn.com/image/fetch/$s_!nyQb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nyQb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png" width="394" height="341.1622516556291" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:523,&quot;width&quot;:604,&quot;resizeWidth&quot;:394,&quot;bytes&quot;:211723,&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;:&quot;https://articles.pragdave.me/i/165034785?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nyQb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png 424w, https://substackcdn.com/image/fetch/$s_!nyQb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png 848w, https://substackcdn.com/image/fetch/$s_!nyQb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.png 1272w, https://substackcdn.com/image/fetch/$s_!nyQb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb113f14-3fc1-4498-9a37-2f19207b0445_604x523.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 currently writing code to import royalty data from our distributor. In comes in the form of 28 or so spreadsheets (because, of course it does). For each, the first step is to upload and ingest it. And, because I&#8217;m paranoid about getting royalties correct, I try to do a bunch of validation and reconciliation as I read each sheet in.</p><p>The typical flow is:</p><ol><li><p>Extract the spreadsheet file from the incoming HTTP request.</p></li><li><p>Extract metadata from the file and use it to start populating an <code>Upload</code> record, where I keep track of each upload, regardless of its content.</p></li><li><p>Parse the spreadsheet, extracting the data I need. Sometimes this is easy; it&#8217;s just a table. Other times the data is more like a statement or invoice, with a variable format, so I have an actual parser to understand it.</p></li><li><p>I then associate the data to do with an actual title with the title in our database.</p></li><li><p>Finally, I save all the data, typically across three or four tables, in a single transaction. </p></li></ol><p>These steps are basically a pipeline, where each step feeds data to the next. However, errors can happen at each step, and I need to record them in the Upload record. When an error occurs, I stop processing that spreadsheet. This means I can&#8217;t use regular Ruby pipelines.</p><p>Each step returns a hash, either </p><p><code>    { status: :ok, data: </code><em>data_to_pass_to_next_step</em><code> }</code></p><p> or </p><p><code>    { status: :error, message: </code><em>error_reason</em><code> }</code>. </p><p>Here are the three alternative designs I played with.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">Subscribe for free to get an article each week. Thanks for reading.  Dave</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><h2>Design 1: Linear Brute Force</h2><p>Why overthink it? Just write the code:</p><pre><code>result = excel_file_attached?(file)
if result[:status] == :error
    record_error(upload, result[:message])
else
    result = add_details_to_upload(result[:data], upload)
    if result[:status] == :error
        record_error(upload, result[:message])
    else
        result = parse_statement(result[:data])
        if result[:status] == :error
            record_error(upload, result[:message])
        else
            result = map_isbns_to_skus(result[:data])
            if result[:status] == :error
                record_error(result[:message], upload)
            else
                result = save_rows(upload, result[:data])
            end
        end
    end
end</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dsf9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dsf9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png 424w, https://substackcdn.com/image/fetch/$s_!dsf9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png 848w, https://substackcdn.com/image/fetch/$s_!dsf9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png 1272w, https://substackcdn.com/image/fetch/$s_!dsf9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dsf9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png" width="398" height="398" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:800,&quot;resizeWidth&quot;:398,&quot;bytes&quot;:1099533,&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;:&quot;https://articles.pragdave.me/i/165034785?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dsf9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png 424w, https://substackcdn.com/image/fetch/$s_!dsf9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png 848w, https://substackcdn.com/image/fetch/$s_!dsf9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.png 1272w, https://substackcdn.com/image/fetch/$s_!dsf9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c39dfa-432b-4b9e-a875-5c51105b77b4_800x800.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>Code like this hurts my soul, so at the very least I&#8217;d want to flatten the nesting.</p><pre><code><code>result = excel_file_attached?(file)
unless result[:status] == :error
    result = add_details_to_upload(result[:data], upload)
end
    
unless result[:status] == :error
    result = parse_statement(result[:data])
end

unless result[:status] == :error
    result = map_isbns_to_skus(result[:data])
end

unless result[:status] == :error
    result = save_rows(result[:data], upload)
end

if result[:status] == :error
    record_error(upload, result[:message])
end</code></code></pre><p>Better, but the code that does the actual work is buried inside all those <code>unless</code> statements.</p><h2>Design 2: The Mini State Machine</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-Iil!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-Iil!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png 424w, https://substackcdn.com/image/fetch/$s_!-Iil!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png 848w, https://substackcdn.com/image/fetch/$s_!-Iil!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png 1272w, https://substackcdn.com/image/fetch/$s_!-Iil!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-Iil!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png" width="311" height="311" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/696f0604-529b-48de-914e-6a4447849d91_800x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:800,&quot;resizeWidth&quot;:311,&quot;bytes&quot;:1030267,&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;:&quot;https://articles.pragdave.me/i/165034785?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-Iil!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png 424w, https://substackcdn.com/image/fetch/$s_!-Iil!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png 848w, https://substackcdn.com/image/fetch/$s_!-Iil!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.png 1272w, https://substackcdn.com/image/fetch/$s_!-Iil!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696f0604-529b-48de-914e-6a4447849d91_800x800.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>When I have a sequence of steps like this, I often use a trivial state machine:</p><pre><code>    step = 0
    result = nil     # for scoping

    loop do
      result = case step
               when 0 then  excel_file_attached?(file)
               when 1 then  add_details_to_upload(result[:data], upload)
               when 2 then  parse_statement(result[:data])
               when 3 then  map_isbns_to_skus(result[:data])
               when 4 then  save_rows(result[:data], upload)
               when 5 then  break

               when :error
                 record_error(upload, result[:message])
                 break
               end

      if result[:status] == :ok
        step += 1
      else
        step = :error
      end
    end</code></pre><p>In general I like this code, but it seems a little over-the-top.</p><h2>Design 3: Exceptions</h2><p>The third thing I considered was having each of the processing functions raise an exception rather than return an error status. That cleans things up considerably:</p><pre><code>begin
  file
  |&gt; excel_file_attached?
  |&gt; add_details_to_upload(upload)
  |&gt; parse_statement
  |&gt; map_isbns_to_skus
  |&gt; save_rows(upload)
rescue UploadError =&gt; e
  record_error(upload, e.message)
end</code></pre><p>Clearly, this is the most direct of the three.</p><h2>Design x: Metaprogram</h2><p>I briefly considered reimplementing the pipeline operator <code>|&gt;</code> to exit early on seeing an error, but my days of that kind of tomfoolery are long past.</p><h2>Design y: A Monad Library</h2><p>I&#8217;m aware of the dry-monads library and the <a href="https://dry-rb.org/">Railroad article</a>. I considered using it, but adding an extra dependency for just a couple of lines of code was a nonstarter. Perhaps if I&#8217;d written the whole codebase from scratch using dry-monads, it would be an improvement, but this particular chunk of upload code is the first time I&#8217;ve felt the need for monadic behavior in this app.</p><h2>What I Ended Up Doing</h2><p>In the end it came down to design 2 or design 3. Of the two, I much prefer the exception-based approach: it seems on the surface to be a lot more direct and easy to comprehend.</p><p>You might be surprised, therefore, when I oped to use design 2, the state machine.</p><p>I admit it was a difficult decision, and as I write this I still have doubts. But I had two nagging thoughts about the exception/pipeline approach that swung it for me.</p><p>First, and weakest, is that I have a instinctive aversion to using exceptions as a flow-control mechanism. My rule of thumb is to use exceptions only for exceptional things&#8212;things that should never happen. A validation failure when reading external data doesn&#8217;t seem to count.</p><p>The second reason is what swung it for me. The pipeline is a great construct, but it ends up coupling functions together. When you write <code>a() |&gt; b()</code>, the return value of <code>a</code> must be acceptable as the first parameter of <code>b</code>. </p><p>For established code, which is unlikely to change, this seems like an acceptable tradeoff: the types are unlikely to change, and the pipeline is just plain more readable.</p><p>However, when I&#8217;m writing new code for a new application, I just know that I&#8217;ll be changing things around as I learn about the domain. </p><p>In the state machine approach, I&#8217;m currently emulating a pipeline by passing the result from one function to the next. But that isn&#8217;t set in stone. I can add new code before a particular call, or massage a return value. The design is more open.</p><p>The pipeline approach would make that trickier, because the fact that I&#8217;m using a language feature to chain functions together constrains my choices down the road. And as I just know I&#8217;ll end up having to change stuff, I chose to forgo the pipeline&#8217;s elegance. </p><h2>But That&#8217;s Just Me</h2><p>My reason for posting this is that I&#8217;m still not sure. I would really like to start some discussions in the comments. What would you do, and why? Are there other, better choices? Am I overthinking this?</p><p>Chat with you there.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/error-monads-the-hard-way/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://articles.pragdave.me/p/error-monads-the-hard-way/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/error-monads-the-hard-way?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/error-monads-the-hard-way?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><p></p><div><hr></div><div><hr></div>]]></content:encoded></item><item><title><![CDATA[Testing]]></title><description><![CDATA[Might not mean what you think it means]]></description><link>https://articles.pragdave.me/p/testing</link><guid isPermaLink="false">https://articles.pragdave.me/p/testing</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Mon, 26 May 2025 19:42:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!684_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!684_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!684_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png 424w, https://substackcdn.com/image/fetch/$s_!684_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png 848w, https://substackcdn.com/image/fetch/$s_!684_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png 1272w, https://substackcdn.com/image/fetch/$s_!684_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!684_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png" width="1200" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:1200,&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_!684_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png 424w, https://substackcdn.com/image/fetch/$s_!684_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png 848w, https://substackcdn.com/image/fetch/$s_!684_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.png 1272w, https://substackcdn.com/image/fetch/$s_!684_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42ee5b3d-b3b0-472d-954c-35d9bab26f12_1200x800.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;d like you do stop and thing about the following question. </p><blockquote><p><em>Why do you write tests?</em></p></blockquote><p>Seriously. Stop reading, sit back, and think about it for a couple of minutes. Maybe jot down an item or two on a bullet list. Do it now, and I&#8217;ll go make a cup of tea.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zk8t!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zk8t!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zk8t!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zk8t!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zk8t!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zk8t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg" width="3129" height="1768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1768,&quot;width&quot;:3129,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:509340,&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;:&quot;https://articles.pragdave.me/i/164495339?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14b1ff4c-e2be-48ad-884f-e870372a7147_4007x2671.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zk8t!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zk8t!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zk8t!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zk8t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff917ada4-c40c-428b-8c6c-32ce67cfc96a_3129x1768.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">Andrej Li&#353;akov</figcaption></figure></div><p>What did you come up with? Here are some of the reasons I&#8217;ve heard over the years. First, come two sad ones:</p><ul><li><p>I have to write tests: they are part of our project standards.</p></li><li><p>I feel I should write tests because everyone says I should.</p></li></ul><p>And then some perfectly good reasons:</p><ul><li><p>I write tests to verify that my code works.</p></li><li><p>Tests mean that I can more safely change my code in the future.</p></li><li><p>Tests help me explore my APIs before I use them elsewhere in my system.</p></li><li><p>Tests drive me to write code that is more decoupled.</p></li></ul><p>Each one of these is a credible assertion. Each seems like common sense. Who wouldn&#8217;t want to know if their code works? Who doesn&#8217;t want to write code in more isolated, decoupled chunks?</p><p>The problem is that assertions, particularly ones that seem to be virtuous, have a nasty habit of becoming accepted facts.</p><p>Personally, I don&#8217;t think something deserves to be a fact unless it can be tested.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">Subscribe, and I&#8217;ll send you this content for free, two to four times a month. Thank you!</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><h2>Testing Testing</h2><p>Let&#8217;s think up some experiments to try to validate whether the four testing assertions above are actually true. But, before we do, a warning. Truth is almost always contextual. Most people would assert that stabbing someone in the throat is always bad; but it&#8217;s good if you&#8217;re performing a tracheotomy. In all the discussions that follow, I&#8217;m going to have to generalize, because I don&#8217;t know your specific context. That&#8217;s why I&#8217;ll be suggesting ways you could experiment with the testing assertions personally, in your own context. Anyone who tries to sell you on a universal do-this-rule is either stupid or fraudulent.</p><h4>Assertion: I write tests to verify that my code works</h4><p>This is an obvious assertion: verifying functionality is pretty much the definition of testing. But, as with all assertions, we really should test to see if it is true, but how?</p><p>Here&#8217;s what I did a while back. I first made sure that I had a handle on the number of faults that surfaced in the code that I delivered. This code had gone through my normal testing process: it wasn&#8217;t 100% coverage (because that&#8217;s kinda dumb) but it was decent.</p><p>Once I had the baseline, I stopped writing unit tests.</p><p>Some of the impacts that I measured I&#8217;ll be talking about when we come to the other assertions. Looking just at bugs, however, I discovered two main things:</p><ol><li><p>Many of the bugs that would have been found by testing were actually found instead as I was using the buggy code in other code. In every case I encountered, the source of the bug was pretty obvious: I can&#8217;t remember triggering a bug that was more that 2 levels of call away from the place where it impacted me.</p></li><li><p>To my surprise, the failure rate of the system once delivered was slightly higher in the first few days, but then fell back to about the same levels I&#8217;d seen previously in tested code.</p></li></ol><p>I looked into the failures in the delivered code, both before the experiment and during, trying to work out why there was so little variance.</p><p>It turned out that most of these bugs had the same root cause: I had misunderstood something about the application while I was writing it. I hadn&#8217;t realized that a value might be missing, or that a key could be duplicated between two data rows. And, because I didn&#8217;t know about these things, I wouldn&#8217;t have written tests for them in the first place.</p><p>Conclusion: for me, on the kinds of projects I&#8217;m writing, religiously writing tests seemed to have little impact on my delivered error rate.</p><h4>Assertion: Tests mean that I can more safely change my code in the future</h4><p>This assertion seems very plausible: having a good suite of tests reduces the chance of introducing regressions while making future changes.</p><p>To test this out, I had a look at what happened when I came to update the code I&#8217;d written without tests.</p><p>This is anecdotal, but I found the lack of tests made changes considerably more stressful. For every change I made, I&#8217;d need to manually explore the future trajectory of any affected data, making sure that my modifications didn&#8217;t break any assumptions elsewhere in the code.</p><p>In the end, I found myself writing canary tests: functional-level tests that verified the behavior not of the changes I made, but of the code that relied on that changed 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_!8diR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8diR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png 424w, https://substackcdn.com/image/fetch/$s_!8diR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png 848w, https://substackcdn.com/image/fetch/$s_!8diR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png 1272w, https://substackcdn.com/image/fetch/$s_!8diR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8diR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png" width="1200" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1777021,&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;:&quot;https://articles.pragdave.me/i/164495339?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8diR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png 424w, https://substackcdn.com/image/fetch/$s_!8diR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png 848w, https://substackcdn.com/image/fetch/$s_!8diR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.png 1272w, https://substackcdn.com/image/fetch/$s_!8diR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5498966b-e3d0-47a5-bccf-4da5f77652b7_1200x800.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><figcaption class="image-caption">A Canary in a Code Mine</figcaption></figure></div><p>On the face of it, the assumption that tests are a benefit during code updates would seem to be valid. However, there&#8217;s another side to consider. This is not something I&#8217;ve explicitly tested, but instead comes from my experience.</p><p>Over the years, I&#8217;ve learned the hard way that it&#8217;s a mistake to simply add new chunks of code at some convenient point in an existing codebase. </p><p>When the app was first written, I was constantly refactoring the code; any friction adding new code was a hint of some kind of problem with the existing codebase. One of the joys of decoupled code is that it is easier to restructure, as changes are more likely to be localized.</p><p>However, what happens when I come to modify that code later on? Again, adding the new code could prompt a refactoring of the existing code. But if that code has a lot of unit tests (and I&#8217;m not proud of this) I just couldn&#8217;t bring myself to update both the existing tests and existing code, and so I just carbuncled the change in where it could fit. My laziness meant that the tests would tend to lower the quality of the app over time.</p><p>Conclusion: Overall, and for me, on the kinds of projects I do, the idea that having tests makes future changes less fraught seems to be true. As a result, although I may not have a full test suite when entering in to a change, I&#8217;m likely to add some high level tests before I actually make that change.</p><h4>Assertion: Tests help me explore my APIs before I use them elsewhere in my system</h4><p>The idea behind this assertion is that your test will be the first time you call the code you just wrote (or are about to write for you Test-First folks). This gives you a fresh perspective on that code, and often that perspective gives you hints that things aren&#8217;t quite right.</p><p>A key indicator (for me) is when the tests are tricky to write because they require setting up a bunch of context: your <code>format_name</code> function takes a <code>User</code> object as a parameter, so each test must go through the pain of constructing a valid <code>User</code> before it can call <code>format_name</code>.</p><p>When that kind of thing happens to me, I stop and wonder why my formatting function needs the entire user object: could I just pass in the first and last names, and perhaps a title? Or maybe this friction caused by writing the test is saying that the various name fields shouldn&#8217;t just be separate attributes of a user; instead I might need to have <code>Name</code> objects which <code>User</code> could reference.</p><p>This assertion and the next were my personal go-to reasons for writing tests. It turns out that what I learned about this API assertion mirrors my discoveries about the decoupling assertion, so I&#8217;m going to defer my conclusion until the next section.</p><h4>Assertion: Tests drive me to write code that is more decoupled</h4><p>Code that has a lot of coupling is very difficult to work with, because you can never fully know the scope of a change you make.</p><p>It turns out that unit tests are a great way of discovering some types of coupling. If you want to test function A, but to do so you need to construct half a dozen new objects, involving calls to twenty other functions, they you&#8217;re being forced to live through the pain imposed by A&#8217;s degree of coupling.</p><p>So, just as with APIs, a test that is difficult to write because the thing under test requires a lot of context is a red flag: you might get the test to run, but underneath that success you know that the code it is testing smells.</p><p>The thing I feared most when I started my experiment of not writing unit tests was the damage it might do the the design of the code I was writing. I worried that coupling would sneak in if I had no tests to keep the code simple.</p><p>In practice, I discovered something surprising. And, before I go on, I have to confess that, of all my observations in this experiment, this is likely to be the most personal and least applicable generally.</p><p>Anyway, to my surprise, I discovered that, although I was not writing unit tests, I was constantly thinking about writing them. &#8220;How would I test this&#8221; was running in a kind of loop all the time I was coding. It turns out that just considering that question was enough to trigger the doubt that would end up driving the refactoring I needed. In effect I was getting the design benefits of testing without actually writing the tests.</p><p>I think part of the reason for this is that I had spent decades before the experiment doing various kinds of testing, and the various facets of creating tests and become part of my tacit brain. (This is also what happens when you learn to drive. Initially, you have to think about everything you do, but after a while it becomes almost automatic: the tacit side of your brain has developed the reflexes and intuitions to handle most of the act of driving for you.)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ns81!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ns81!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png 424w, https://substackcdn.com/image/fetch/$s_!ns81!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png 848w, https://substackcdn.com/image/fetch/$s_!ns81!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png 1272w, https://substackcdn.com/image/fetch/$s_!ns81!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ns81!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png" width="800" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1229572,&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;:&quot;https://articles.pragdave.me/i/164495339?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ns81!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png 424w, https://substackcdn.com/image/fetch/$s_!ns81!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png 848w, https://substackcdn.com/image/fetch/$s_!ns81!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.png 1272w, https://substackcdn.com/image/fetch/$s_!ns81!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d43adb-b4c0-472d-9136-2d25785f65ce_800x800.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>My experience was that I was refactoring code just as often when I developed with tests as when I developed without. Looking back at code written without tests, I really don&#8217;t see too much I&#8217;d want to change in terms of structure.</p><p>Conclusion: I thing that thinking about testability is a key tool when it comes to improving your APIs and your code structure. In my personal experience, though, I find that I get that benefit even if I never write the tests; just thinking about them is enough.</p><h2>So&#8230;</h2><p>I am not saying that tests are good or tests are bad. I&#8217;m not saying that testing makes your code better or makes worse, easier to maintain or harder.</p><p>All I&#8217;m saying is that I performed the experiment, and came up with some personal conclusions that inform what I do now.</p><p>I still write tests, but I focus in on areas where the cost of the code being wrong are greater than the costs of creating and maintaining the tests. When I&#8217;m writing code that deals with money, or with information that has personal value, I write unit tests. I will write higher level functional tests that exercise a whole chunk of the app (does importing this spreadsheet cause the correct royalty adjustments to appear in that table?). And if one of those high level tests fails, I might explore with some lower level tests until I&#8217;ve isolated the issue. </p><p>I make a point of maintaining the &#8220;how would I test this&#8221; inner dialog when I&#8217;m coding, and I make time to react and refactor when the question has no easy answer.</p><p>But that&#8217;s me. I have no idea what you should do. Except&#8230;</p><ul><li><p>If you&#8217;re just starting out, write tests. Keep doing it until in becomes reflexive. This probably takes two to five years.</p></li><li><p>If you&#8217;re working in a domain where the cost of failure is high, write tests. It is always going to be more expensive to write this kind of code, and the tests won&#8217;t be as costly in relative terms.</p></li><li><p>If you&#8217;re exploring, write tests. I do this a lot, and I find that the series of tests becomes a great reference; I look back on them to remember what I&#8217;ve learned.</p></li></ul><p>More suggestions:</p><ul><li><p>If you write exploratory tests, delete them before delivering the project.</p></li><li><p>If you&#8217;re a TDD person, and the strictly follow the no-code-without-a-failing-test mantra, do back and delete all the silly tests which have nothing to do with the application functionality.</p></li></ul><p>Tests are code, and the more code you&#8217;re carrying around in a project, the more dependencies you have, and the more that can go wrong.</p><p>At the end of the day, I&#8217;m simply suggesting that you don&#8217;t have to do something because people tell you it&#8217;s a good idea, or because you yourself assume that it&#8217;s the right thing to do.</p><p>Test you assumptions, and refactor what you believe accordingly.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/testing?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/testing?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Module-based Polymorphism]]></title><description><![CDATA[A quickie]]></description><link>https://articles.pragdave.me/p/module-based-polymorphism</link><guid isPermaLink="false">https://articles.pragdave.me/p/module-based-polymorphism</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Thu, 15 May 2025 18:40:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!USCy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!USCy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!USCy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!USCy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!USCy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!USCy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!USCy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!USCy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!USCy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!USCy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!USCy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa215a6e4-7987-414c-900c-3a10ec68a7c9_1024x1024.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 writing code to import sales information from a variety of sources. The data from each source is first uploaded and normalized, then imported into our main database for reporting and royalty calculations.</p><p>Uploading the data involves ingesting a binary file (typically a spreadsheet) and normalizing it depending on the data source. The import into the main system is also source-dependent, as different business rules apply to each.</p><p>In the past, my go-to approach was to have a base class, with a subclass for each source.</p><p>These days, though, I favor functions over object instance methods, and modules over classes. As I&#8217;m integrating this into an existing system, I&#8217;m sticking with Ruby.</p><p>I experimented with a couple of approaches before settling on one I liked.</p><p>I use the following directory and module structure:</p><pre><code>lib/
    royalties/
        dispatcher.rb              Royalties::Dispatcher
        source_one/
            import_handler.rb      Royalties::SourceOne::ImportHandler
            upload_handler.rb      Royalties::SourceOne::UploadHandler
        source_two/
            import_handler.rb      Royalties::SourceTwo::ImportHandler
            upload_handler.rb      Royalties::SourceTwo::UploadHandler
        source_three/
            import_handler.rb      Royalties::SourceThree::ImportHandler
            upload_handler.rb      Royalties::SourceThree::UploadHandler</code></pre><p>I also have a model object representing an upload (regardless of source). (And, yes, it&#8217;s an object, because I&#8217;m using <code>ActiveRecord</code>.) Each upload object has an attribute that identifies its source.</p><p>Elsewhere in the code, I want to be able to work with these upload objects regardless of their source, so I write something like:</p><pre><code>Royalties::Dispatcher::handle_upload(upload)</code></pre><p>The dispatcher handles the polymorphic aspects of this by using the upload type to select the module to invoke:</p><pre><code>module Royalties::Dispatcher
  extend self

  def handle_import(upload)
    find_handler(upload.source)::ImportHandler.handle(upload)
  end

  def handle_upload(upload)
    find_handler(upload.source)::UploadHandler.handle(upload)
  end

  private

  SOURCE_TO_HANDLER = {
    Upload::SOURCE_ONE   =&gt; Royalties::SourceOne,
    Upload::SOURCE_TWO   =&gt; Royalties::SourceTwo,
    Upload::SOURCE_THREE =&gt; Royalties::SourceThree,
  }

  def find_handler(source)
    SOURCE_TO_HANDLER[source] || 
        fail("No handler found for upload source #{source}")
  end
end</code></pre><p>Because the source-specific implementations are just functions, testing them in isolation is easy.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/module-based-polymorphism?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/module-based-polymorphism?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Method Chaining vs Function Composition]]></title><description><![CDATA[Part of an occasional series on my move away from OO programming]]></description><link>https://articles.pragdave.me/p/method-chaining-vs-function-composition</link><guid isPermaLink="false">https://articles.pragdave.me/p/method-chaining-vs-function-composition</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Wed, 14 May 2025 21:13:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!vHV-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vHV-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vHV-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif 424w, https://substackcdn.com/image/fetch/$s_!vHV-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif 848w, https://substackcdn.com/image/fetch/$s_!vHV-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif 1272w, https://substackcdn.com/image/fetch/$s_!vHV-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vHV-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif" width="1200" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/caf764b4-0535-4943-9e42-4874d4f9a516.tif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!vHV-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif 424w, https://substackcdn.com/image/fetch/$s_!vHV-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif 848w, https://substackcdn.com/image/fetch/$s_!vHV-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif 1272w, https://substackcdn.com/image/fetch/$s_!vHV-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf764b4-0535-4943-9e42-4874d4f9a516.tif 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>Summary<em>: using method chaining might look fluent and elegant, but it adds coupling while reducing design flexibility. For the last ten years I have been moving away from chaining, instead using various kinds of function composition. Let me tell you why I find it better.</em></p><h1>The Appeal of Method Chains</h1><p>Here&#8217;s a turtle graphics program that draws a square. It&#8217;s written in some arbitrary OO language.</p><p><code>turtle<br>  .pen_down()<br>  .move(1)<br>  .turn(90)<br>  .move(1)<br>  .turn(90)<br>  .move(1)<br>  .turn(90)<br>  .move(1)<br>  .pen_up()</code></p><p>It&#8217;s a kind of <a href="https://martinfowler.com/bliki/FluentInterface.html">Fluent Interface</a>, a mini-Domain Specific Language. It&#8217;s made possible because each of the actions is a method defined in the Turtle class, and each does its business and then <em>returns that same object</em>.</p><p><code>def pen_down<br>  # move the pen&#8230;<br>  return self  # (or this, or &#8230;)<br>end</code></p><p>There&#8217;s no law that says it has to be the same object that is returned by each method:</p><p><code>File               # &#8594; File class<br>.open(&#8220;data.dat&#8221;)  # &#8594; File object<br>.read_line()       # &#8594; string1<br>.trim()            # &#8594; string2<br>.split(/\s+/)      # &#8594; array of string</code></p><p>This is the <em>method chain</em>, and it has been a staple of OO development pretty much from the start.</p><p>I love them, and use them every day.</p><p>But the lure of the fluent-style method chain can lead developers down some pretty dangerous paths. Let&#8217;s look at a couple of these before considering an alternative.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">If you subscribe, you&#8217;ll get all my free content sent to you, no messy clicking required.</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><h2>&#8220;I Can Make It Like English&#8221;</h2><p>(or French, German, Spanish&#8230;)</p><p>Testing is a big deal in the Ruby world. There are two schools: traditional and behavior-driven. Both use assertions to check expected values against the values produced by code. In the traditional camp, we have tools such as minitest:</p><p><code>assert(update_complete)<br>assert_equal(7, add(2, 5))<br>refute(count &gt; 5)</code></p><p>In the BDD classrooms, they teach tools such as RSpec:</p><p><code>expect(update_complete).to be(true)  # </code>or<code> be_truthy<br>expect(add(5, 2)).to eql(7)<br>expect(count).to_not be &gt; 5</code></p><p>Both styles achieve the same thing, but RSpec attempts to look more like a specification, more like natural language. And it is pretty clever. </p><p>But, for the same reason there&#8217;s an (increasingly shallow) <a href="https://en.wikipedia.org/wiki/Uncanny_valley">uncanny valley</a> between artificial and real images, RSpec&#8217;s attempts at fluency leave me feeling uncomfortable. </p><p>Every test starts <code>expect(</code><em>expression</em><code>).to</code> (or <code>.to_not</code>). The .to method is there largely as window dressing; it gives us a semblance of English-like syntax. It&#8217;s followed by the actual assertion: a verb and possibly the expected value. RSpec calls these parts <em><a href="https://www.rubypigeon.com/posts/rspec-expectations-cheat-sheet/">matchers</a></em>. </p><p>They&#8217;re trying to be fluent, but failing. Like AppleScript, it&#8217;s fairly intuitive to read, but it is anything but to write. Why the space after <code>to</code>? (Because the matcher is actually a parameter.) Why <code>be(true)</code> but <code>eql(7)</code>? (Because these are two of the three different kinds of Ruby equality). And why the split infinitive in the last case? Who knows?</p><p>I believe that part of the reasoning for this was to allow less technical people to read and agree on the tests. It may actually have happened that a manager peeked at this code, at some point, somewhere. But my guess is that this worked about as well as assuming managers could read COBOL because of its English-like syntax. The barrier that needs to be crossed is not one of syntax; it&#8217;s one of abstraction, of thinking like a developer.</p><p>Programming is all about layering abstractions, and method chaining is one way of doing that. But it can come with a high price.</p><h2>Homogenous Chains Good,&#8230;</h2><p>For a method chain to work, the methods that form the links must each return an object that implements the subsequent method in the chain: in</p><p><code>a().b().c()</code></p><p>The method <code>a</code> must return an object that implements a method <code>b</code>, and that method in turn must return an object that implements <code>c</code>.</p><p>There is a style of method chain that makes this easy. It&#8217;s when you start with some initial object that has a bunch of methods that can be used to update its state. Each of these methods returns the initial object, allowing these calls to be chained. Sometimes this is called a <em>builder</em> or a <em>constructor</em>. The turtle graphics example at the top of this article is an example of this:</p><p><code>turtle<br>  .pen_down()<br>  .move(1)<br>  .turn(90)</code></p><p>The turtle object has an initial state, and methods such as <code>pen_down</code> and <code>move</code> update that state. The chain is homogenous; it&#8217;s turtles all the way down.</p><p>Another example of this is the ActiveRecord query builder:</p><p><code>Book.where("id &gt; 100").limit(20).order("id desc")</code></p><p>Each of these methods adds to the query structure without actually executing any SQL; that SQL is only generated when you try to access data from the query.</p><p>But there&#8217;s another style of chain, where we&#8217;re striving for some kind of fluent API, but we have to bend the code to make it work.</p><h2>Heterogeneous Chains Bad</h2><p>Another common use of chains is to traverse a bunch of objects, either to extract some particular piece of data or to execute some particular functionality. </p><p>Here we have a line of code in the fulfillment module trying to work our the charge for shipping based on a client&#8217;s address:</p><pre><code><code>client.address(&#8220;home&#8221;).postcode().delivery_zone().shipping_cost(package)</code></code></pre><p>We can get all academic and call this a violation of the supposed Law of Demeter, or we can just be pragmatic and say that this code has just increased the coupling in your application in manifold ways. Let&#8217;s see how.</p><h2>Chains That Bind</h2><p>Let&#8217;s look at dependencies. </p><p>We can infer that our client object depends on an Address class, with in turn depends on a PostCode, and so on.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!slu5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!slu5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png 424w, https://substackcdn.com/image/fetch/$s_!slu5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png 848w, https://substackcdn.com/image/fetch/$s_!slu5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png 1272w, https://substackcdn.com/image/fetch/$s_!slu5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!slu5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png" width="599" height="34" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:34,&quot;width&quot;:599,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6578,&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;:&quot;https://articles.pragdave.me/i/163496036?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!slu5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png 424w, https://substackcdn.com/image/fetch/$s_!slu5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png 848w, https://substackcdn.com/image/fetch/$s_!slu5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png 1272w, https://substackcdn.com/image/fetch/$s_!slu5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a5f224a-5cbb-4ce6-ad5f-a25edb30aa8a_599x34.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This is a perfectly fine set of dependencies: if the <code>PostCode</code> class implementation changes, then that might affect the <code>Address</code> class, but that&#8217;s all (at least in this picture).</p><p>But add in our Fulfillment class, and the picture changes:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hXcX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hXcX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png 424w, https://substackcdn.com/image/fetch/$s_!hXcX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png 848w, https://substackcdn.com/image/fetch/$s_!hXcX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png 1272w, https://substackcdn.com/image/fetch/$s_!hXcX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hXcX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png" width="624" height="153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:153,&quot;width&quot;:624,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18274,&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;:&quot;https://articles.pragdave.me/i/163496036?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hXcX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png 424w, https://substackcdn.com/image/fetch/$s_!hXcX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png 848w, https://substackcdn.com/image/fetch/$s_!hXcX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png 1272w, https://substackcdn.com/image/fetch/$s_!hXcX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94be50-24b3-4f07-831d-310dbbbf3483_624x153.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Our Fulfillment class now depends on all five of the other classes: a change in any of them could potentially cause the need to change <code>Fulfillment</code>. Maybe we decide that the <code>PostCode</code> class has no business knowing about its delivery zone, and we move that functionality somewhere else. <code>Fulfillment</code> breaks</p><p>One way to fix this is to say that <code>Fulfillment</code> only depends on <code>Client</code>, and that <code>Client</code> must implement a <code>shipping_cost()</code> method. If we apply that same logic throughout, we&#8217;d also have to add a <code>shipping_cost() </code>method to <code>Address</code>, <code>PostCode</code>, and <code>DeliveryZone</code> as well. That&#8217;s clearly untenable. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7mDg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7mDg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png 424w, https://substackcdn.com/image/fetch/$s_!7mDg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png 848w, https://substackcdn.com/image/fetch/$s_!7mDg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png 1272w, https://substackcdn.com/image/fetch/$s_!7mDg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7mDg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png" width="1200" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1630322,&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;:&quot;https://articles.pragdave.me/i/163496036?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7mDg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png 424w, https://substackcdn.com/image/fetch/$s_!7mDg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png 848w, https://substackcdn.com/image/fetch/$s_!7mDg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.png 1272w, https://substackcdn.com/image/fetch/$s_!7mDg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98d5239a-be03-4f18-ba8a-051a9119153f_1200x800.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></p><h1>Functions and Composition</h1><p>One way out of this mess is to stop insisting that we pass state and functions together; that we no longer have to invoke methods only on objects. We&#8217;ll call these liberated methods <em>functions</em>, as they transform one or more parameters into a new value. This lets us write something like this:</p><pre><code>shipping_cost(delivery_zone(postcode(address("home&#8221;, client))), package)    </code></pre><p>Of course, this particular cure is worse than the disease; these kinds of nested calls are a nightmare to read and maintain.</p><p>This is where method composition and pipelines come into play. </p><p>In a functional language such as OCaml, function composition creates a new function that is the result of  running the first, then passing the result to the second. We can create a function that does composition; we&#8217;ll call it <code>&gt;&gt;</code>.</p><pre><code>let ( &gt;&gt; ) f g x = g (f x)</code></pre><p>This says that <code>&gt;&gt;</code> is a function that takes three parameters: two functions, <code>f</code> and <code>g</code>, and a value <code>x</code>. It passes <code>x</code> to <code>f</code>, and then passes the result of that to <code>g</code>. We can use this function to build a new function:</p><pre><code>let plus1 n = n + 1 
let square n = n*n 
let plus1_and_square = plus1 &gt;&gt; square 
plus1_and_square 10    &#8594; 121   </code></pre><p>In this example, <code>plus1_and_square</code> is a new function that is the composition of <code>plus1</code> and <code>square</code>.</p><p>We can parameterize these composite functions:</p><pre><code>let plusn n = (+) n
let plusn_and_square n = plusn n &gt;&gt; square  
plusn_and_square 3 2     -&gt; 25</code></pre><p>Now we can create a new function that creates a function that calculates the shipping for our customer and package:</p><pre><code>let shipping client package =
  address "home" client &gt;&gt;
  postcode              &gt;&gt;
  delivery_zone         &gt;&gt;
  shipping_cost package</code></pre><p>Using that, I can create a function that calculates the shipping cost of delivering any package to me:</p><pre><code>let shipping_to_dave package = shipping_client &#8220;pragdave&#8221; package</code></pre><p>or, more concisely</p><pre><code><code>let shipping_to_dave = shipping_client &#8220;pragdave&#8221; </code></code></pre><p> See what we&#8217;ve done? We created a chain of functions which can be parameterized, and each is independent of the other.</p><h2>And There Are Pipelines</h2><p>Your language <em>du jour</em> may not support function composition, but an increasing number of languages support something similar, the <em>function pipeline</em>. Using the OCaml and Elixir notation, we can say</p><pre><code>value |&gt; f |&gt; g</code></pre><p>takes <code>value</code>, pipes it into the function <code>f</code> as a parameter, then pipes the value returned by <code>f</code> into <code>g</code>. It is similar to function composition, but it executes immediately. Using pipelines, we could write our shipping code as</p><pre><code><code>client
  |&gt; address "home"
  |&gt; postcode
  |&gt; delivery_zone
  |&gt; shipping_cost package  </code></code></pre><h1>Try This&#8230;</h1><p>I&#8217;ve found that this kind of decoupling of functions from state pays enormous dividends, to the point where I now write my code in this style even if I&#8217;m writing in an OO language. Typically I&#8217;ll use objects or read-only structs to hold state, and then I&#8217;ll write independent functions to transform that state. If the language doesn&#8217;t have a pipeline equivalent, I&#8217;ll either use temporary variables or a loop and a trivial counter-based state machine to chain together the function calls. </p><p>It takes getting used to, but if your experience is anything like mine, you&#8217;ll find yourself writing code that easier to test (because each function is independent), maintain (because state is easy to examine at every step), and update.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/method-chaining-vs-function-composition?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/method-chaining-vs-function-composition?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Design Patterns Are Not Design]]></title><description><![CDATA[Enough already with the factories and the decorators.]]></description><link>https://articles.pragdave.me/p/design-patterns-are-not-design</link><guid isPermaLink="false">https://articles.pragdave.me/p/design-patterns-are-not-design</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Wed, 30 Apr 2025 01:06:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Y0Rn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>As always, history plays a role. In the case of Design Patterns, history shows us a kind of slingshot acceleration of adoption by developers, starting in the late 1980s, with an exponential growth in the 1990s, followed by the freefall of mass adoption in the 2000s. Here&#8217;s a potted version:</em></p><p>In 1977, the architect Christopher Alexander published the book <em>A Pattern Language</em>,  containing over 250 suggestions for folks designing spaces. Each pattern was a context followed by a suggested solution and a discussion. For example, pattern 159 starts</p><blockquote><p>When they have a choice, people will always gravitate to those rooms which have light on two sides, and leave the rooms which are lit only from one side unused and empty.</p><p>Therefore:</p><p>Locate each room so that it has outdoor space outside it on at least two sides, and then place windows in these outdoor walls so that natural light falls into every room from more than one direction.</p><p>This pattern, perhaps more than any other single pattern, determines the success or failure of a room. The arrangement of daylight in a room, and the presence of windows on two sides, is fundamental. If you build a room with light on one side only, &#8230;</p></blockquote><p>Ten years later, Ward Cunningham and Kent Beck cowrote the paper <a href="https://c2.com/doc/oopsla87.html">Using Pattern Languages for Object-Oriented Program</a>s, which suggested Alexander&#8217;s approach might also work for code. They continued to work on this, and in 1994 Ward invented the wiki in order to create a <a href="https://c2.com/ppr/titles.html">place</a> where people could discuss patterns. </p><p>That same year, Gang of Four<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> published <em>Design Patterns; Elements of Reusable Object Oriented Software</em>. Their intent was to isolate and name various structures that people used in particular situations; if two or more people had address a particular issue in the same way, they&#8217;d name it and describe it. In their case, they were looking at code written in C++, and many of the patterns exist to overcome constraints imposed by that language.</p><p>The crowd went wild. For the next 8 or 9 years, Ward&#8217;s wiki was the place the cool kids hung out. If a thing moved, someone would write a pattern language describing how. There are thousands of published patterns for software development.</p><p>And every single one of them is used incorrectly.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">If you like the occasional rant about software development, then go ahead and subscribe. It&#8217;s free, and it feeds my ego&#8230; :)</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><h2>The Title is to Blame</h2><p>I don&#8217;t know why the GoF gave Design Patterns the subtitle they did, but <em>Elements of Reusable Object Oriented Software s</em>ent a subtle but damaging message. The word <em>reusable</em> implies that they are presenting you with some kind of plug-and-play component library. Do you need to create instances of different classes depending on some value? Then you need a Factory! And, for a limited time, we&#8217;re throwing in the code and a UML diagram at no extra cost!!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y0Rn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png" width="404" height="404" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:404,&quot;bytes&quot;:1576025,&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;:&quot;https://articles.pragdave.me/i/162490515?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Y0Rn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff50b5960-0c35-457c-80e2-37a34395415f_1024x1024.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>And that&#8217;s what happened. People jumped on the idea of patterns being building blocks of design. Suddenly you couldn&#8217;t write a class unless it&#8217;s name ended with the name of a pattern: <code>UserFactory</code>, <code>ConfigSingleton</code>, <code>PrintDecorator</code>. What&#8217;s worse, people then implemented these classes by transcribing the C++ code from Design Patterns into their language <em>du jour</em>, line for line.</p><p>And this is really, really dumb. </p><p>Patterns are not reusable chunks of code. They are not components.</p><p>Patterns are descriptions of techniques that might be useful in a particular context. They are not recipes; Alexander called them hypotheses. </p><p>Time for a bad analogy.</p><h2>How To Paint, A Pattern Language</h2><p>Through a miracle of engineering, scientists bring the painter Rembrandt van R&#307;n back to life. Before he dies for a second time, they want to capture his knowledge and expertise as a artist. He decides to document what he knows as a pattern language.</p><p>He sets to work, writing patterns such as &#8220;Capturing soft light on the forehead&#8221;, &#8220;The nose of a drunk,&#8221; and &#8220;The disdainful eyebrow.&#8221; When finished, the book is a global phenomenon. Artists everywhere hail it as the new way to construct a painting: apply each of the patterns as needed as you traverse the canvas, and you&#8217;re guaranteed a masterpiece.</p><p>We end up with pictures 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_!hgto!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hgto!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png 424w, https://substackcdn.com/image/fetch/$s_!hgto!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png 848w, https://substackcdn.com/image/fetch/$s_!hgto!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png 1272w, https://substackcdn.com/image/fetch/$s_!hgto!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hgto!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png" width="371" height="383" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:383,&quot;width&quot;:371,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:245799,&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;:&quot;https://articles.pragdave.me/i/162490515?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hgto!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png 424w, https://substackcdn.com/image/fetch/$s_!hgto!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png 848w, https://substackcdn.com/image/fetch/$s_!hgto!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.png 1272w, https://substackcdn.com/image/fetch/$s_!hgto!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b3a4050-6153-4880-a394-166ba80c18a2_371x383.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>This is what happens when you say &#8220;I need a nose here and a forehead there&#8221;, go to Rembrandt&#8217;s patterns book, and copy his implementations onto your canvas.</p><p>Clearly, that&#8217;s not how Rembrandt&#8217;s patterns should be used. They should be studied for technique and for insight, and then reinterpreted by the hand holding the brush.</p><h2>For Example</h2><p>Search for &#8220;factory pattern ruby&#8221; and you&#8217;ll find examples such as 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_!NjZ6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NjZ6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png 424w, https://substackcdn.com/image/fetch/$s_!NjZ6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png 848w, https://substackcdn.com/image/fetch/$s_!NjZ6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png 1272w, https://substackcdn.com/image/fetch/$s_!NjZ6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NjZ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png" width="911" height="1374" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1374,&quot;width&quot;:911,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:134452,&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;:&quot;https://articles.pragdave.me/i/162490515?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NjZ6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png 424w, https://substackcdn.com/image/fetch/$s_!NjZ6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png 848w, https://substackcdn.com/image/fetch/$s_!NjZ6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.png 1272w, https://substackcdn.com/image/fetch/$s_!NjZ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F566db301-a0a7-4c14-b653-49d1081cd3b5_911x1374.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>This is the programming language equivalent of the Monty Python <a href="https://www.youtube.com/watch?v=1lXyup0De7Q">fish license</a>, but rather than being a dog license with the word &#8220;dog&#8221; replaced with the word &#8220;cat&#8221;, it&#8217;s C++ (or Java, or &#8230;) code with the syntax replaced with Ruby. </p><p>On top of that, it doesn&#8217;t actually show a factory method: it&#8217;s just two unnecessary levels of delegation.</p><p>Why pick on this code? I&#8217;d rather not, but it&#8217;s all like that, and this was the least obnoxious. Rather than ask themselves &#8220;what do I need to achieve?&#8221;, the implementors of these online exemplars made the decision &#8220;I need a factory",&#8221; looked it up, and transcribed what they found into Ruby.</p><p>Let&#8217;s convert this example to use an actual factory method, and write it based on need, and not some pattern.</p><p>We need to simulate one of <em>n</em> machines. Which one we chose depends on the value of an external parameter. Every machine is a class, and each implements an <code>operate</code> method.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QRCI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QRCI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png 424w, https://substackcdn.com/image/fetch/$s_!QRCI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png 848w, https://substackcdn.com/image/fetch/$s_!QRCI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png 1272w, https://substackcdn.com/image/fetch/$s_!QRCI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QRCI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png" width="724" height="949.1001494768311" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:877,&quot;width&quot;:669,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:82167,&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;:&quot;https://articles.pragdave.me/i/162490515?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QRCI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png 424w, https://substackcdn.com/image/fetch/$s_!QRCI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png 848w, https://substackcdn.com/image/fetch/$s_!QRCI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.png 1272w, https://substackcdn.com/image/fetch/$s_!QRCI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a0d8432-9eb7-4d0e-9227-9de729c0234c_669x877.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>Still pretty ugly. We can tidy it a little by replacing code with data (my current 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_!1YVz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1YVz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png 424w, https://substackcdn.com/image/fetch/$s_!1YVz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png 848w, https://substackcdn.com/image/fetch/$s_!1YVz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png 1272w, https://substackcdn.com/image/fetch/$s_!1YVz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1YVz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png" width="759" height="302" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:302,&quot;width&quot;:759,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37084,&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;:&quot;https://articles.pragdave.me/i/162490515?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1YVz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png 424w, https://substackcdn.com/image/fetch/$s_!1YVz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png 848w, https://substackcdn.com/image/fetch/$s_!1YVz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.png 1272w, https://substackcdn.com/image/fetch/$s_!1YVz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cda4a4b-b577-4d9f-8a24-08c69fe56858_759x302.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>It still has those strange <code>Machine1</code> and <code>Machine2</code> classes though. This is where sample code breaks down, because we don&#8217;t know what they do in real life. If they are simply stateless wrappers for the functions they contain, then they should be modules, and not classes.</p><p>If instead they have behavior in common, and the <code>operate</code> method is the difference between being a <code>machine1</code> and a <code>machine2</code>, then we have some options.</p><p>The option that you probably <em>shouldn&#8217;t take</em> is the one that everyone uses: create an abstract base class containing the shared behavior and make <code>Machine1</code> and <code>Machine2</code> subclasses. In a strongly typed OO language you are forced to do this to get polymorphic behavior. But in languages such as Ruby and JavaScript, there&#8217;s no need, and adding class hierarchies increases coupling.</p><p>So if we assume that the external interface to all machines is a <code>do_something</code> method, which in turn calls the machine-specific <code>operate</code> method, we could use mixins:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cSE3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cSE3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png 424w, https://substackcdn.com/image/fetch/$s_!cSE3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png 848w, https://substackcdn.com/image/fetch/$s_!cSE3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png 1272w, https://substackcdn.com/image/fetch/$s_!cSE3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cSE3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png" width="759" height="623" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:623,&quot;width&quot;:759,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49264,&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;:&quot;https://articles.pragdave.me/i/162490515?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cSE3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png 424w, https://substackcdn.com/image/fetch/$s_!cSE3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png 848w, https://substackcdn.com/image/fetch/$s_!cSE3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.png 1272w, https://substackcdn.com/image/fetch/$s_!cSE3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45f7b5b1-5ff3-4672-bf6d-c05679dc30ce_759x623.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>An alternative is to remove the polymorphism altogether, and instead inject the appropriate method at runtime:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bugw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bugw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png 424w, https://substackcdn.com/image/fetch/$s_!bugw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png 848w, https://substackcdn.com/image/fetch/$s_!bugw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png 1272w, https://substackcdn.com/image/fetch/$s_!bugw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bugw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png" width="805" height="825" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:825,&quot;width&quot;:805,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:100809,&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;:&quot;https://articles.pragdave.me/i/162490515?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bugw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png 424w, https://substackcdn.com/image/fetch/$s_!bugw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png 848w, https://substackcdn.com/image/fetch/$s_!bugw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.png 1272w, https://substackcdn.com/image/fetch/$s_!bugw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd80a19f9-524b-44b4-bf0a-6936d78490a9_805x825.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>This code assumes that the machine object <code>do_something</code> functions can be called multiple times. If that wasn&#8217;t the case, there&#8217;s no need for a separate StandardMachine class: we can just pass the <code>operation</code> to the <code>do_something</code> method.</p><h1>Don&#8217;t Design Before You Need To</h1><p>In last week&#8217;s article I talked about the evils of premature design. This article is really just a continuation of that. The only difference is that when you use a design pattern, that design predates your need by at least 30 years.</p><p>My personal take: design patterns are a convenient way of describing code that you already wrote. Don&#8217;t use them as recipes.</p><blockquote><h3>Postscript</h3><p>Whenever I meet an architect, I make a point of asking what they think of Christopher Alexander and his idea of patterns. I&#8217;m well past my tenth, and none of them has heard of him. </p></blockquote><p></p><div><hr></div><p>There&#8217;s more of this kind of old-man-fist-waving-at-clouds in my new book, <em><a href="https://pragprog.com/titles/dtcode">simplicity</a></em>&#8230;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/design-patterns-are-not-design?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/design-patterns-are-not-design?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><p></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>Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides</p><p></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>Slight exaggeration.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Premature Design Is Not Design]]></title><description><![CDATA[Resist the temptation to guess, and let the code tell you what it needs.]]></description><link>https://articles.pragdave.me/p/premature-design-is-not-design</link><guid isPermaLink="false">https://articles.pragdave.me/p/premature-design-is-not-design</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 22 Apr 2025 17:39:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Jzi4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jzi4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jzi4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Jzi4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Jzi4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Jzi4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jzi4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!Jzi4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!Jzi4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!Jzi4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!Jzi4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b1cdf1c-97b3-4c1e-aefe-40006907f434_1024x1024.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>In the 1974 paper with the somewhat click-baity title <em><a href="https://web.archive.org/web/20130731202547/http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf">Structured Programming With go to Statements</a></em><strong>, </strong>Donald Knuth wrote:</p><blockquote><h3><strong>premature optimization is the root of all evil (or at least most of it) in programming</strong></h3></blockquote><p>Knuth&#8217;s point was that optimizing code normally makes that code trickier to work with; when you&#8217;re still in the exploring phase, trying to work out what your code should do, that&#8217;s the last thing you need. So, when you optimize (and you probably should at least think about optimization), you should do it only when (a) you find out what actually needs optimizing, and (b) when you&#8217;re unlikely to make major structural changes to the code base.</p><p>I&#8217;m coming to believe that what&#8217;s true for optimization is true pretty much universally: premature anything is likely to be a bad thing.</p><p>And you won&#8217;t find a better example of this than the way folks design code.</p><h1>Premature Design is the Devil&#8217;s Work</h1><p>I know this because I&#8217;m guilty of doing just that: bringing my vast arsenal of design principles to bear simply because I believed the Devil when they said &#8220;if you don&#8217;t make it perfect now, you&#8217;ll never come back and fix it later.&#8221;</p><p>That was old, sinful, Dave. Today&#8217;s Dave views the world differently. Today&#8217;s Dave believes that design is something that is iterated with the code, and is only introduced when needed.</p><p>Let&#8217;s look at a somewhat simplified example.</p><h1>RBAC Rabbit Hole</h1><p>A while back I needed a way to share information among all the people who work on writing and producing books at the Bookshelf. Everyone was already using our giant Rails app in other ways, so I decided to bolt on a kind of wiki-like thing.</p><p>Then a little red figure with a pitchfork, horns, and a tail popped into existence on my right shoulder. &#8220;How are you going to protect key information from being altered by novices,&#8221; asked the miniature Prince of Darkness. &#8220;You&#8217;re going to need hierarchies of user access rights.&#8221;</p><p>Old, sinful Dave listened. Old Scratch was right. We had different levels of user: systems admins, managers, editors, book authors, and third parties such as copy editors and layout folks. Managers should be allowed to alter pages they created, as well as pages created by any of the editors who reported to them, and the authors who worked under those editors. Editors could update their pages, along with those of their authors. Poor old authors could only edit their own work, while third parties had no ability to edit anything.</p><p>That was my high-level design for the authorization, but before I opened up an editor, I&#8217;d need to do some more work on the lower levels.</p><p>Clearly I&#8217;d need a database table mapping users to roles. But, thinking ahead, I&#8217;d likely need to have different kinds of authorization for different resources, so I shouldn&#8217;t hard wire in my Wiki. That called for another database table containing the resource types (it would start off with just one row).  I&#8217;d need to create the code to manage the entries in those tables. </p><p>Then I&#8217;d need to be able to determine if user A could edit page X. There was clearly a recursive step in there: a manager could change pages owned by their editors, and the pages owned by that editor&#8217;s authors. So I&#8217;d need to design a recursive SQL query, which sent me off on a day&#8217;s worth of exploring CTEs and how I could express them in ActiveRecord.</p><p>I started off needing a place to store notes, but with the Devil&#8217;s help I was going to do it properly, and implement a fully-fledged Role-Based Access Control system.</p><p>That felt righteous, so off I went down the rabbit hole.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Svpb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Svpb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png 424w, https://substackcdn.com/image/fetch/$s_!Svpb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png 848w, https://substackcdn.com/image/fetch/$s_!Svpb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png 1272w, https://substackcdn.com/image/fetch/$s_!Svpb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Svpb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png" width="1019" height="761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:761,&quot;width&quot;:1019,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1623819,&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;:&quot;https://articles.pragdave.me/i/161850130?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Svpb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png 424w, https://substackcdn.com/image/fetch/$s_!Svpb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png 848w, https://substackcdn.com/image/fetch/$s_!Svpb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.png 1272w, https://substackcdn.com/image/fetch/$s_!Svpb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbfa301-573e-4333-9d80-c554a6b3cdd1_1019x761.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></p><h1>Today&#8217;s Dave Would Do It Differently</h1><p>Today, when that little red fellow makes an appearance, I try to ignore what he says. </p><p>Instead, I wait until I need something before designing it.</p><p>I&#8217;d start my wiki with an in-memory hash that mapped page names to page content, accessed via a trivial <code>Page</code> model.  I&#8217;d get the wiki stuff working using this.</p><p>At that point, I&#8217;d make a decision. Clearly I need to store the data somewhere more permanent than RAM. And I clearly need to implement some kind of access control. Which should I do first?</p><p>On the basis of not doing things until I need to, I&#8217;d most likely choose the access control next, simply because it is likely to impact the data I need to store, and that data is easier to mess with while I&#8217;m just storing it in an in-memory hash. </p><p>I&#8217;d write the access control code as a placeholder method in my User model:</p><pre><code><strong>class</strong> User
  <strong>def</strong> can_edit_wiki_page?(page)
    true
  <strong>end
end</strong>                                                                                                                                                                                                                                     </code></pre><p>Then I could update the editing code to call this method.</p><p>At this point, I wouldn&#8217;t be able to write any meaningful access-control tests, so I&#8217;d need a little more logic.</p><pre><code><strong>class</strong> User
  <strong>def</strong> can_edit_wiki_page?(page)
    page.owner == self
  <strong>end
end</strong> </code></pre><p>You&#8217;re right! This isn&#8217;t the recursive SQL query. It doesn&#8217;t use a role table or a resource table. But it&#8217;s enough design to see me through to the next phase, when I add some persistence.</p><p>And, you know what? I deployed it with just one minor change:</p><pre><code><strong>class</strong> User
  <strong>def</strong> can_edit_wiki_page?(page)
    self.admin? || page.owner == self
  <strong>end</strong>
<strong>end</strong></code></pre><p>Turns out I didn&#8217;t need any of that fancy design. Everyone was happy with it being simple.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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 this. If you&#8217;re not already subscribed, please consider joining us. It&#8217;s free, you get notifications of new content, and I get a warm fuzzy feeling that someone cares.</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><h1>The Devil Likes DRY</h1><p>Recently I&#8217;ve come across folks who don&#8217;t like the Don&#8217;t Repeat Yourself principle, which first appeared 25 years ago in <em>The Pragmatic Programmer</em>. These folks say that slavishly removing duplicated code from your apps can make the designs more complex, and can lead to architectures where unrelated things are somehow conflated.</p><p>As a response, I updated the DRY section of the 20th anniversary edition extensively. I tried to explain that DRY is not about code duplication; it&#8217;s about the representation of <em>knowledge</em>. If two pieces of code that represent different pieces of knowledge happen to be identical, they are not a DRY violation, and it would be a mistake to factor them into a single place. (Assuming, of course, that the two pieces of knowledge are not just two statements of a single fact).</p><h1>Viva Las Vegas!</h1><p>It can&#8217;t be a coincidence that I most recently saw the Devil at work when I when to the Sin City Ruby conference. Fito von Zastrow and Alan Ridlehoover gave a great talk with a fantastic example of the way the premature design, combined with an incomplete understanding of DRY, can lead to some crappy 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_!-EXt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-EXt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!-EXt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!-EXt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!-EXt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-EXt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2145234,&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;:&quot;https://articles.pragdave.me/i/161850130?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-EXt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!-EXt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!-EXt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!-EXt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3929a1bf-b964-44e4-b855-869bc3ead391_1024x1024.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>Their example was a machine that dispenses cups of hot beverages. Initially, it just knew how to make a cup of coffee. (The code that follows is just a sketch of theirs.)</p><pre><code><strong>def</strong> dispense
  heat_water
  drop_cup
  grind_coffee
  force_water_through_filter
  present_cup_to_customer
<strong>end</strong></code></pre><p>So far, so good. But then the requirement changes: the machine also has to dispense tea.</p><pre><code><strong>def</strong> dispense(options)
  <strong>case</strong> options.drink
  <strong>when</strong> :coffee
    heat_water
    drop_cup
    grind_coffee
    force_water_through_filter
    present_cup_to_customer

  <strong>when</strong> :tea
    heat_water
    drop_cup
    measure_tea_on_to_filter
    force_water_through_filter
    present_cup_to_customer

  <strong>else</strong>
    ...
  <strong>end</strong>
<strong>end</strong></code></pre><p>Here&#8217;s where premature DRYing kicks in. We look at that code, and think &#8220;the two parts of the case statement are identical apart from the one line in the middle of each that adds either coffee or tea to the filter. So the DRY principle says we should refactor.</p><pre><code><strong>def</strong> dispense(options)
  heat_water
  drop_cup

  <strong>case</strong> options.drink
  <strong>when</strong> :coffee
    grind_coffee

  <strong>when</strong> :tea
    measure_tea_on_to_filter

  <strong>else</strong>
    ...
  <strong>end</strong>

  force_water_through_filter
  present_cup_to_customer
<strong>end</strong></code></pre><p>The a new requirement comes in: we need to be able to add creamer to the coffee and milk to the tea. Obviously, the milk has to go in before the hot water, and the cream goes in only after the coffee has poured. We also need to add sweetener on request. Oh, and there the option for decaf coffee.</p><pre><code><strong>def</strong> dispense(options)
  heat_water
  drop_cup

  <strong>case</strong> options.drink
  <strong>when</strong> :coffee
    <strong>if</strong> options.decaf?
      grind_decaf_coffee
    <strong>else</strong>
      grind_coffee
    <strong>end</strong>

  <strong>when</strong> :tea
    dispense_milk if options.white?
    measure_tea_on_to_filter

  <strong>else</strong>
    ...
  <strong>end</strong>

  force_water_through_filter
  dispense_cream if options.drink == :coffee &amp;&amp; options.white?
  present_cup_to_customer
<strong>end</strong></code></pre><p>Then along comes the request to add hot chocolate to the machine,  with the option for whipped cream. Then we get a request for low-fat milk&#8230;</p><p>We started out with the best of intentions, but our initial refactoring, done to satisfy DRY, is leading us down a decidedly ugly path. We&#8217;re left trying to salvage the mess by adding more and more code as we try to split up the <code>dispense</code> method.</p><h1>DRY is About Knowledge, Not Code</h1><p>Our process broke down when we looked at this code:</p><pre><code><strong>def</strong> dispense(options)
  <strong>case</strong> options.drink
  <strong>when</strong> :coffee
    heat_water
    drop_cup
    grind_coffee
    force_water_through_filter
    present_cup_to_customer

  <strong>when</strong> :tea
    heat_water
    drop_cup
    measure_tea_on_to_filter
    force_water_through_filter
    present_cup_to_customer

  <strong>else</strong>
    ...
  <strong>end</strong>
<strong>end</strong></code></pre><p>Our DRY instinct kicked in, and we immediately made the design decision to fix it. But we were rushing things, updating the design prematurely. I&#8217;ve come to realize that being hasty like this almost always leads to worse code in the long run. Today Dave would probably look at the code I&#8217;d written and add a single line:</p><pre><code><em># <strong>TODO</strong>: dry?</em></code></pre><p>Sure, there might be a DRY violation here, but it is currently doing no harm. Remember, all design comes down to &#8220;how easy it it to change?&#8221; Even though our first thought might be that the duplication in this code might lead to problems, we have no current evidence that this is the case. In fact, if we stop to think about it, there isn&#8217;t actually a duplication here at all, because DRY is about knowledge, not code.</p><blockquote><h4><strong>all design comes down to &#8220;how easy it it to change?&#8221;</strong></h4></blockquote><p>The body of the first <code>when</code> clause is the recipe for making a cup of coffee; the body of the second is the recipe for tea. Those are separate items of knowledge that just happen to share some steps. Thinking that there&#8217;s duplication here is like thinking that making an omelette and baking a cake are the same thing because they both involve cracking some eggs.</p><h1>The Lazy Path</h1><p>We  feel justified to leave the code untouched, but then along comes the dairy requirement. Again, we  don&#8217;t try to &#8220;do design&#8221; until we have a problem to solve, so we make the obvious changes:</p><pre><code><strong>def</strong> dispense(options)
  <strong>case</strong> options.drink
  <strong>when</strong> :coffee
    heat_water
    drop_cup
    grind_coffee
    force_water_through_filter
    dispense_cream <strong>if</strong> options.white?
    present_cup_to_customer

  <strong>when</strong> :tea
    heat_water
    drop_cup
    measure_tea_on_to_filter
    dispense_milk <strong>if</strong> options.white?
    force_water_through_filter
    present_cup_to_customer

  <strong>else</strong>
    ...
  <strong>end</strong>
<strong>end</strong></code></pre><p>At this point, I&#8217;m starting to feel that we <em>do</em> have a design problem: this method now has four different paths through it. in it&#8217;s initial form it was possible to take it all in at a glance, but it now requires active reading. So let&#8217;s split it up.</p><pre><code><strong>def</strong> dispense_coffee(options)
    heat_water
    drop_cup
    grind_coffee
    force_water_through_filter
    dispense_cream <strong>if</strong> options.white?
    present_cup_to_customer
end

<strong>def</strong> dispense_tea(options)  
    heat_water
    drop_cup
    measure_tea_on_to_filter
    dispense_milk <strong>if</strong> options.white?
    force_water_through_filter
    present_cup_to_customer
<strong>end</strong>

<strong>def</strong> dispense(options)
  <strong>case</strong> options.drink
  <strong>when</strong> :coffee <strong>then</strong> dispense_coffee(options)
  <strong>when</strong> :tea    <strong>then</strong> dispense_tea(options)
  <strong>else</strong>
    ...
  <strong>end</strong>
<strong>end</strong></code></pre><p>I&#8217;m liking this: each method is now a representation of a recipe. It&#8217;s easy to see what is going on, and how we&#8217;d add new recipes in the future. To me, this is DRY; each piece of knowledge is represented just once.</p><p>Could we do more? Of course. Right now each recipe starts with the same two actions and ends with the cup presentation. We could definitely extract that out:</p><pre><code><strong>def</strong> dispense_tea(options)  
  serve_hot_drink_in_cup <strong>do</strong>
    dispense_milk <strong>if</strong> options.white?
    measure_tea_on_to_filter
  <strong>end</strong>
  force_water_through_filter
<strong>end</strong></code></pre><p>But, again, I think that&#8217;s premature. We only have two recipes in our code, and two of anything is not a pattern. </p><p>Similarly, I look at the <code>dispense</code> function. Whenever I see a  <code>case</code> statement used to dispatch to different behaviors, I want to replace it with a hash/dictionary lookup. But that&#8217;s also premature. Let&#8217;s make a <code># TODO</code> note in the code, just to keep an eye on it as things change in the future, and move on.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DHx8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DHx8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!DHx8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!DHx8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!DHx8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DHx8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2359297,&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;:&quot;https://articles.pragdave.me/i/161850130?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DHx8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!DHx8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!DHx8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!DHx8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f043d59-788a-4cb4-81d1-cdad294e53d0_1024x1024.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><h1>Evidence Based Design</h1><p>One of the keys to keeping things simple is to avoid doing stuff until it actually needs to be done. There are no rules that say you must stop what you&#8217;re doing and refactor just because two lines of code are the same. </p><p>Instead, good design comes from a discovered need; from evidence that your code is not as easy to change as it could be.</p><p>Sometimes we can anticipate that need, but the world doesn&#8217;t end if instead we discover it as we go along. </p><p>Design is not rules that you follow. It isn&#8217;t in charge of what you do.</p><p>Instead, design is a tool you use to make your code easier to change.</p><div><hr></div><p>My latest book, <em>simplicity</em>, is now available at <a href="https://pragprog.com/titles/dtcode/simplicity/">The Pragmatic Bookshelf</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/premature-design-is-not-design?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/premature-design-is-not-design?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Received Wisdom]]></title><description><![CDATA[True wisdom can only come from within.]]></description><link>https://articles.pragdave.me/p/received-wisdom</link><guid isPermaLink="false">https://articles.pragdave.me/p/received-wisdom</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Wed, 16 Apr 2025 00:46:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!T7aC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!T7aC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!T7aC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!T7aC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!T7aC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!T7aC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!T7aC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!T7aC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!T7aC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!T7aC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!T7aC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f990a8-60af-4a8e-b001-6fe47c56b7de_1024x1024.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>How do we learn, really learn? </p><p>We experiment.</p><p>We create mental models, we test them, and we adjust them. We have theories that this new piece of knowledge might relate to some other piece of knowledge, and we test that assumption. Over time, we accumulate a web of things we feel that we know.</p><p>But what we really have is a self-consistent set of beliefs. New information is admitted to this web if it doesn't damage too much of the existing beliefs.</p><p>This process is what leads to bias. When sufficient numbers of people share sufficiently similar beliefs, they reinforce each other. The beliefs become rules, and believers become less critical; asking questions might damage the group.</p><p>I suspect it might be because so much of what we do is novel, but developers seem particularly prone to glorifying shared beliefs. Here are some that have graduated to dogma:</p><ul><li><p>everyone must do test-driven development</p></li><li><p>agile beats waterfall</p></li><li><p>agile doesn't work</p></li><li><p>web pages should be rendered in the client/server (choose one)</p></li><li><p>customers don&#8217;t know what they want</p></li><li><p>new is better than old</p></li><li><p>we know what we're doing </p></li></ul><p>and so on&#8230;</p><p>As individuals, we need to be cautious of this phenomenon and avoid joining these soft cults as they surge past us in our social feeds. After all, if no rules are universal, acting as if a belief is actually a rule is pretty much guaranteed to make us wrong some percentage of the time.</p><p>So my advice is that you hear about something being &#8220;the way to do it&#8221; or, even worse, a &#8220;best practice,&#8221; take note, but consider what you're hearing to be nothing more than an opinion; someone else's belief. There are things you can learn from it&#8212;things you can integrate into your own belief system&#8212;but as with everything you allow into your head it needs to be tested and refined before it becomes yours. Be a skeptic, not an ardent disciple.</p><p>This advice applies to the stuff I say; it applies to the stuff everyone tells you.</p><p>None are rules. </p><p>Instead, view them as beliefs and suggestions. They&#8217;re not actions to take or rules to follow, they're just my beliefs that you might want to consider, test, modify, and maybe merge into your beliefs. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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 Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><h2>Truth is Contextual</h2><p>No rules are universal.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> At the very least, a rule needs a context in which it applies. It's generally considered bad form to stick a knife into someone's throat, unless they're dying and you're performing a tracheotomy.</p><p>Context is a multidimensional concept. At a minimum, it includes:</p><ul><li><p>timescale<br>We will do things differently depending on how long they are likely to take.</p></li><li><p>group size<br>Are we looking at a personal practice, or something that involves the team, or the company?</p></li><li><p>impact<br>We might behave differently if the outcome has a significant up or downside.</p></li><li><p>moral and legal risk<br>Is this another social media site, or are we creating a medical device?</p></li><li><p>confidence<br>How much uncertainty affects our actions?</p></li></ul><p>And so on.</p><p>So, a plea. Stop for a minute and think about the things you feel are obvious, or that you believe because the group believes. Examine the basis for that belief. Is it universal? (I&#8217;m personally suspicious of any rule that doesn&#8217;t have exceptions.) Can it be tested to see if it is true? Can it be discussed rationally, or do things get heated?</p><p>Received wisdom is skin deep. True wisdom comes only from experience.</p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/received-wisdom?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/received-wisdom?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></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>Except this one. Sorry&#8230;</p></div></div>]]></content:encoded></item><item><title><![CDATA[Disagreements Are Not Zero-Sum Games]]></title><description><![CDATA[Once you stop trying to be right, you'll start to understand more (and you'll be nicer to know).]]></description><link>https://articles.pragdave.me/p/disagreements-are-not-zero-sum-games</link><guid isPermaLink="false">https://articles.pragdave.me/p/disagreements-are-not-zero-sum-games</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Wed, 09 Apr 2025 03:02:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!j_6p!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!j_6p!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j_6p!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png 424w, https://substackcdn.com/image/fetch/$s_!j_6p!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png 848w, https://substackcdn.com/image/fetch/$s_!j_6p!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png 1272w, https://substackcdn.com/image/fetch/$s_!j_6p!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j_6p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png" width="724" height="751.1669793621013" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/03e39543-19b8-493f-970c-a4be88343e2c_533x553.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:553,&quot;width&quot;:533,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:510382,&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;:&quot;https://articles.pragdave.me/i/160910318?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!j_6p!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png 424w, https://substackcdn.com/image/fetch/$s_!j_6p!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png 848w, https://substackcdn.com/image/fetch/$s_!j_6p!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.png 1272w, https://substackcdn.com/image/fetch/$s_!j_6p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03e39543-19b8-493f-970c-a4be88343e2c_533x553.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>One of the problems of our times is that people are convinced that the only way they can win is for someone else to lose. Couple that with the fact that many people care more about winning than about the actual longer-term outcome, and you end up with a dysfunctional and noisy world.</p><p>A simple difference of opinion can end up as a confrontation. Some people enjoy that, and others walk away. Neither side actually wins in that situation.</p><blockquote><p>No one wins a zero-sum argument</p></blockquote><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LPru!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LPru!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png 424w, https://substackcdn.com/image/fetch/$s_!LPru!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png 848w, https://substackcdn.com/image/fetch/$s_!LPru!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png 1272w, https://substackcdn.com/image/fetch/$s_!LPru!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LPru!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png" width="533" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:533,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:587290,&quot;alt&quot;:&quot;An alternative approach is to realize that things are rarely black and white. No one is likely to be 100% right about anything. The trick is to accept this, and to make what would otherwise have been an argument into something more like an exploration.&quot;,&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;:&quot;https://articles.pragdave.me/i/160910318?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="An alternative approach is to realize that things are rarely black and white. No one is likely to be 100% right about anything. The trick is to accept this, and to make what would otherwise have been an argument into something more like an exploration." title="An alternative approach is to realize that things are rarely black and white. No one is likely to be 100% right about anything. The trick is to accept this, and to make what would otherwise have been an argument into something more like an exploration." srcset="https://substackcdn.com/image/fetch/$s_!LPru!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png 424w, https://substackcdn.com/image/fetch/$s_!LPru!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png 848w, https://substackcdn.com/image/fetch/$s_!LPru!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.png 1272w, https://substackcdn.com/image/fetch/$s_!LPru!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa386b7b-d910-4b17-b4d4-04ddb1829e81_533x800.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>This approach is called <em>dialectical reasoning</em>. It assumes there are elements of truth in both sides of an opinion, and it emphasizes the benefits of trying to synthesize something new and bigger from them. Just as important, it turns something that threatened to be a confrontation into an interesting discussion.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">I try to post something every week. Subscribe for free, and it&#8217;ll drop straight into your inbox.</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><h3><strong>Try This:</strong> Practice dialectical thinking</h3><p>Here's an exercise. The next time you find yourself disagreeing with someone, try not to flip the bozo bit and assume they're an idiot. Rather than trying to show them they are wrong, instead genuinely try to work out if maybe you are. Be actively interested in what led them to their position, not because you're hoping to trip them up, but rather because it might give you insights. Your mission is not to prove you're correct, or that the other person is wrong. Instead, you are trying to find out which parts of each of your positions have merit, and from that synthesize a new understanding that's better than the two original ones.</p><p>This is tricky; it's easy to come across as condescending or maybe sly. You might start by saying "I hear what you are saying, but I need to understand more about Xyz, because it doesn't quite line up with my experience. Could you show me what led to your belief."</p><p>Never disagree; you're not trying to win. The exercise is to see things from their point of view. A nice side effect might be that you end up learning something.</p><h3><strong>Try This:</strong> Arguing with knives</h3><p>There's a fun exercise that helps you practice seeing things from both sides. Next time you're at a lunch or dinner where half the people advocate one thing, and the other half advocate the opposite, suggest the following game.</p><p>Everyone who agrees with the position should place their knives (or spoons, or pens, or...) pointing into the center of the table (the way a knife is normally set). Those who disagree should place their knives at 90&#186; to this, parallel to the edge of the table.</p><p>Let the debate run for a few minutes. Then pick a pair of people who disagree and flip their knives around; the person who previously advocated for the position must now argue against it, and the person who previously refuted it must now do their best to sell it to everyone else.</p><p>Keep swapping a pair of knives every few minutes. Try to give everyone a chance to cycle through both sides of the issue more than once.</p><p>It becomes a game: how can you marshal what you know to support something you disagree with. It's like high-school debate.</p><p>You're not trying to find winners or losers, or even to find a consensus. It's just an interesting way to spend 30 minutes with friends. But, on the way home, you might just find yourself reevaluating some of your strongly held views.</p><h2>Absolute is the enemy of simple</h2><p>Every time you hold an absolute and inflexible opinion, you&#8217;re very likely to be at least partially wrong. Even if you believe your idea is justified by science, try to remember that the fundamental tenet of science is to disprove what it believes.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> </p><p>That means that there will be times when your firmly-held opinion may be contradicted by your direct experience. Now you have a choice. The rational approach is to treat the inconsistency as an opportunity to explore and possibly revise your belief. The most popular approach, though, is to come up with some kind of justification of why your belief is still 100% true and reality is mistaken. </p><p>One of the problems with lying about things is that you need to remember your past lies and make sure that everything is consistent with them. Subsequent lies now multiply the complexity of your imaginary world; most people struggle to maintain a consistent story when it&#8217;s informed by more than one lie.</p><p>Denying reality in favor or a belief is lying to yourself. Do it often, and you are forced to build a world view that is so convoluted that it takes a lot of mental energy just to maintain. Meanwhile, the decisions you make based on this baroque version of reality become less and less effective as you struggle to reconcile their outcomes with what you thought would happen.</p><p>Everyone lives in this state to some extent; it&#8217;s a consequence of the world being unknowable. But some people  embrace opinions which are detached from reality. These are the people who are angry at the world, because the world is wrong. These are the people who make  debate difficult, because they are not interested in exploring alternatives. These are the people who feel threatened by &#8220;different.&#8221;</p><p>And it all comes down to the fact that disagreement is not a zero-sum game.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/disagreements-are-not-zero-sum-games?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/disagreements-are-not-zero-sum-games?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hO0-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hO0-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png 424w, https://substackcdn.com/image/fetch/$s_!hO0-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png 848w, https://substackcdn.com/image/fetch/$s_!hO0-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png 1272w, https://substackcdn.com/image/fetch/$s_!hO0-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hO0-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png" width="80" height="21.56996587030717" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/82d2a072-9a22-40c8-a830-33f294162368_879x237.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:237,&quot;width&quot;:879,&quot;resizeWidth&quot;:80,&quot;bytes&quot;:21018,&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;:&quot;https://articles.pragdave.me/i/160910318?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hO0-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png 424w, https://substackcdn.com/image/fetch/$s_!hO0-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png 848w, https://substackcdn.com/image/fetch/$s_!hO0-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png 1272w, https://substackcdn.com/image/fetch/$s_!hO0-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82d2a072-9a22-40c8-a830-33f294162368_879x237.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This is an adaptation of one of the practices in my new book, <em>simplicity</em>, available now in beta from the <a href="https://pragprog.com/titles/dtcode">Pragmatic Bookshelf</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://pragprog.com/titles/dtcode" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HKot!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png 424w, https://substackcdn.com/image/fetch/$s_!HKot!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png 848w, https://substackcdn.com/image/fetch/$s_!HKot!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png 1272w, https://substackcdn.com/image/fetch/$s_!HKot!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HKot!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png" width="1456" height="1796" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1796,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1238120,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://pragprog.com/titles/dtcode&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://articles.pragdave.me/i/160910318?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HKot!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png 424w, https://substackcdn.com/image/fetch/$s_!HKot!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png 848w, https://substackcdn.com/image/fetch/$s_!HKot!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.png 1272w, https://substackcdn.com/image/fetch/$s_!HKot!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa54fb4ee-ce20-4ad7-80b9-da8807d90d99_2250x2775.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></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>Although, to a first approximation, a belief backed by genuine science is likely to be more true than one formed from rhetoric, received knowledge, or people shouting on TV.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Fear, and When To Fear It]]></title><description><![CDATA[Fear is good, but letting it get in your way is just plain unnecessary. Here are some of the many tricks for pushing through.]]></description><link>https://articles.pragdave.me/p/fear-and-when-to-fear-it</link><guid isPermaLink="false">https://articles.pragdave.me/p/fear-and-when-to-fear-it</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 01 Apr 2025 23:51:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1wfK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1wfK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1wfK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png 424w, https://substackcdn.com/image/fetch/$s_!1wfK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png 848w, https://substackcdn.com/image/fetch/$s_!1wfK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png 1272w, https://substackcdn.com/image/fetch/$s_!1wfK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1wfK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png" width="1020" height="706" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:706,&quot;width&quot;:1020,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!1wfK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png 424w, https://substackcdn.com/image/fetch/$s_!1wfK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png 848w, https://substackcdn.com/image/fetch/$s_!1wfK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.png 1272w, https://substackcdn.com/image/fetch/$s_!1wfK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62fbdbd4-2daf-43bb-b398-8633c61eee9e_1020x706.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>Fear is a rational response to change. Fear is the enemy of change. </p><p>I could not find a source for this following graphic, but it quite nicely illustrates how fear is a barrier that keeps us contained within our comfort zones.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0v3A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0v3A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png 424w, https://substackcdn.com/image/fetch/$s_!0v3A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png 848w, https://substackcdn.com/image/fetch/$s_!0v3A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png 1272w, https://substackcdn.com/image/fetch/$s_!0v3A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0v3A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png" width="1133" height="923" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:923,&quot;width&quot;:1133,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:239995,&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;:&quot;https://articles.pragdave.me/i/160380347?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0v3A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png 424w, https://substackcdn.com/image/fetch/$s_!0v3A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png 848w, https://substackcdn.com/image/fetch/$s_!0v3A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.png 1272w, https://substackcdn.com/image/fetch/$s_!0v3A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb05802b-8adc-41a0-9b39-83044ed50fd6_1133x923.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></p><p>We developers share a nasty secret. We all know just how fragile the world of software is; how easy it is for a slight change to create some unintended consequence and take down an application.</p><p>So we're (quite rightly) frightened to make changes. We resist making them because we can't be sure that they will work. We put procedures in place&#8212;meetings, committees, sign-offs&#8212;so that when a change is made, the blame gets shared if something goes awry.</p><p>Don't get me wrong. Fear is a valuable feeling; it stops us from being reckless. But too much fear paralyzes us.</p><p>So here are some suggestions for exploiting the benefits of fear without having it getting in the way of change.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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">I&#8217;m trying to create one of these longer pieces each week. Please subscribe (for free) and you&#8217;ll see them when they are published. Thank you.</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><h1>Good practices mitigate fear</h1><p>This sounds obvious, but consistency is one of the most important ways to alleviate fear.</p><p>Have you ever worked on a project where the build instructions were a three-page document, and where deploying software involved copying a bunch of files into particular places on some servers? I have, I and can tell you that after installing a new release I was in a state of mild anxiety for the next day, waiting for the inevitable phone call from an irate customer or boss.</p><p>These days, all my deployments are automated: a single command will update any number of applications and services on any number of hosts. And now I deploy on pretty much every commit I make.</p><blockquote><p>Automate to Reduce Fear</p></blockquote><p>This can be taken further if you implement a Continuous Integration/Continuous Delivery pipeline. To do this, you'll</p><ul><li><p>need to be using version control,</p></li><li><p>have a release strategy (perhaps using tags or branches),</p></li><li><p>have decent tests,</p></li><li><p>use automated deployment,</p></li><li><p>and have a way of rolling a bad deployment back.</p></li></ul><p>This is something that you grow into as a team: you shouldn't just announce one day you're switching to CI/CD, But if you have that as a goal, it will inform the decisions you make while constructing the project.</p><p>Having automated testing and deployment takes a lot of the fear out of changing software. What's more, the fact that deployment no longer takes a lot of ceremony or time means that you can deploy smaller changes. You won't be as afraid of a 2-line change as you will of a 200-line change.</p><h3>Good Practices Include Good Code</h3><p>Every change you make builds on the existing codebase. And if that code is unreliable, hard to understand, or just plain wrong, then you're quite right to fear any changes you make.</p><p>So maintaining good code hygiene is an essential requisite of approaching code changes without fear.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JZ2O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JZ2O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!JZ2O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!JZ2O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!JZ2O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JZ2O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png" width="490" height="490" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:490,&quot;bytes&quot;:2267808,&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;:&quot;https://articles.pragdave.me/i/160380347?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JZ2O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!JZ2O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!JZ2O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!JZ2O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25a0c1d4-76f2-4bbc-9e64-84be7a2973ae_1024x1024.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><figcaption class="image-caption">Code hygiene&#8212;your mother would be proud.</figcaption></figure></div><h1>Take Smaller Steps</h1><p>When you're unsure of the ground ahead, taking small steps is just good sense. </p><p>You might not be unfamiliar with the domain, uncertain of the customer's needs, or uncomfortable with the design.</p><p>Whatever the reason, the fear brought on by this uncertainty can lead to the infamous <em>writer's block:</em> the fear of the blank page.</p><p>Alleviate that fear by reducing the impact of getting it wrong. If every step you take is a small one, backtracking is easy.</p><blockquote><p>Small Steps Are Safer</p></blockquote><p>Sometimes you can drive this process with tests. Pure Test-Driven Design (TDD) asserts that you never write code without a failing test. AT the extreme, that means you can't start coding a new module without first having a test fail trying to reference the (nonexistent) module.</p><p>At a more pragmatic level, you can do something similar: write a test of something trivial, and then write the very simplest piece of code to make that test pass.</p><p>My advice is to be very cautious with this approach. It is very easy to start following a drunkard's walk  (a process where each step is some random distance and/or direction from the end of the previous step) where successive tests add to the codebase but take you no closer to the goal. </p><h3>Walk With Me</h3><p>Sometimes you can involve your customer in the small-steps path.</p><p>They are asking for a bunch of functionality; do they need it all at once? Or is there some small subset that could be delivered early and that would still give them some business value?</p><blockquote><p>:Step With Your Customer</p></blockquote><p>The benefits to your customer include:</p><ul><li><p>they get to see their software as it is being developed, given them the opportunity to learn and to make adjustments;</p></li><li><p>they get a better feeling for progress and likely timescales;</p></li><li><p>they start seeing a return on their investment early; </p></li><li><p>they'll start to see other opportunities for development.</p></li></ul><p>You also get many benefits:</p><p>You can approach the project in smaller, less scary, chunks. This goes a long way to reducing the fear of starting.</p><ul><li><p>You get to shake down your build and deployment practices.</p></li><li><p>You get feedback, and any changes are easier to make because they're localized to a smaller delivery;</p></li><li><p>* You get the confidence to make future changes.</p></li></ul><p>Most importantly, though, doing this builds a relationship between you andyour customer; they'll know that, even if you deliver stuff that's not quite right, you'll make it better. You'll know that your customer will change their minds, but will work with you to find ways to make the corresponding software changes easier.</p><p>In this environment, handling change turns from being a confrontation to a more enjoyable "you bet!"</p><h1>Cheap Code Is Easier to Throw Away</h1><p>When I'm writing something in a new domain or using new tools or technologies, I worry that I'll spend a month creating something only to discover that, finally, I understand, and that what I've just done is basically junk.</p><p>I fear that because I've done it&#8212;many times.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fWBk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fWBk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!fWBk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!fWBk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!fWBk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fWBk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png" width="450" height="450" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:450,&quot;bytes&quot;:2284928,&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_!fWBk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!fWBk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!fWBk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!fWBk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff142dd21-1bf3-46ac-9427-71f590b79d84_1024x1024.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>Nowadays I overcome that fear by prototyping; writing code to try out ideas that I know I'll be throwing away. This code will be ugly. It won't have any error handling (unless I need to handle errors to explore the system).</p><p>It might not be in a repository, and will only have tests if tests are the cheapest way to learn what I want to learn.</p><blockquote><p>Prototype To Resolve Fear</p></blockquote><p>I recently used GraphQL in a project. Having never used it before, I started with a piece of code that sent a simple query off to an API. To get that working, I had to work out which GraphQL library to use, how authentication worked, how to express queries and create fragments, and what error responses looked like.</p><p>The resulting code would have made Dr Frankenstein proud: snippets of code cobbled together from a bunch of web sources, GitHub archaeology, and random experimentation. Half-way through the second day, something flipped in my brain and I felt like I got it. So I created the repo for the actual project and started coding. Maybe an hour later I had what I felt was well-structured and resilient code chatting away with the service API. I broke my own rule and kept the prototype code lying around in a temporary directory: it was a useful playground when I wanted to try out something new and didn't want to mess up the main project.</p><h2>&#8220;We Have Nothing To Fear But Fear Itself&#8221;</h2><p>Churchill&#8217;s aphorism still sounds good (until you stop to parse it). The problems we anticipate are not the enemy; they are simply the challenges. It&#8217;s the fear of those problems that we have to overcome. And hygiene, small steps, and experimenting are just a few of the many charms we can use to banish fear whence it came.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/fear-and-when-to-fear-it?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/fear-and-when-to-fear-it?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Throwing the Babies Out With the Bathwater]]></title><description><![CDATA[A defense of Junior Developers]]></description><link>https://articles.pragdave.me/p/throwing-the-babies-out-with-the</link><guid isPermaLink="false">https://articles.pragdave.me/p/throwing-the-babies-out-with-the</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 25 Mar 2025 18:15:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!VP1J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VP1J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VP1J!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!VP1J!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!VP1J!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!VP1J!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VP1J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png" width="724" height="724" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:2036899,&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;:&quot;https://articles.pragdave.me/i/159847361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VP1J!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!VP1J!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!VP1J!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!VP1J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff06a47fc-5725-4c2d-b193-20bbbb04ad0b_1024x1024.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>Apparently, a bunch of larger companies have decided that, as AI makes their more senior developers more productive, they can thin the ranks of more junior staff. </p><p>I believe this is a short-sighted move for all the usual reasons, and also for a reason I haven&#8217;t heard expressed before.</p><h1>The Usual Reasons It&#8217;s a Bad Idea</h1><ul><li><p>With no junior developers, where are tomorrow&#8217;s senior developers coming from?</p></li><li><p>If the end result of this move is that all code is AI generated, then where do those AI train on new paradigms, frameworks, languages, and so on?</p></li><li><p>I&#8217;m anticipating a massive and public failure some time soon: a large company going out of business because of code that no-one understood did something catastrophic. When that happens, the rest of the world will retrench somewhat, and all those junior devs you let go today are suddenly going to be in demand.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4lhq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4lhq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!4lhq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!4lhq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!4lhq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4lhq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png" width="724" height="724" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:2084750,&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;:&quot;https://articles.pragdave.me/i/159847361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4lhq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!4lhq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!4lhq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!4lhq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a94434-12b6-4b72-8a36-babc1a6722f6_1024x1024.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><h1>Another Reason It&#8217;s a Bad Idea</h1><p>Junior developers (really, any junior members of staff) have a real and unique benefit.</p><p>No, it&#8217;s not that they&#8217;re cheap.</p><p>It&#8217;s that they are both naive and enthusiastic. They are the toddlers of the industry, untouched by the world-weary cynicism of the rest of us. Unlike us, they don&#8217;t know that &#8220;you do it this way because we&#8217;ve always done it this way.&#8221; They don&#8217;t know that an idea is ridiculous, or that something can&#8217;t be done. Like toddlers, they&#8217;re happy to try stuff and learn, and they almost expect to fail often&#8212;it&#8217;s no big deal.</p><p>This has always been an untapped resource. We rarely listen to these tyros when it comes to making decisions; they are basically cannon fodder, thrown in to do the grunt work.</p><p>But what if, when the AIs make your senior devs 5x more productive, you pause before laying off the rest. You take 20% of that savings, and use it to keep your junior devs at work.</p><p>But change the focus. No longer view them as code generators. Instead, treat them as what they are: the next generation of senior devs. Give them space. Let them make mistakes. Try to listen to their crazy ideas. I&#8217;m betting that some of those ideas, once tamed, could fundamentally improve the way you do things. </p><p>I also bet that these junior devs, who have grown up with AI, will find new, and better, ways of exploiting these coding assistants, ways that might not even occur to people who are adapting to AI after a career spent manually coding.</p><p>It requires a little faith, and a little courage. But it might just be the factor that lets you succeed while the more short-term companies decline.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/throwing-the-babies-out-with-the?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/throwing-the-babies-out-with-the?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[The Best Features Are The Ones You Don’t Ship]]></title><description><![CDATA[This is an extract from my book "simplicity." The layout has been simplified to work with substack.]]></description><link>https://articles.pragdave.me/p/the-best-features-are-the-ones-you</link><guid isPermaLink="false">https://articles.pragdave.me/p/the-best-features-are-the-ones-you</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Tue, 18 Mar 2025 14:24:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!soAA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!soAA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!soAA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!soAA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!soAA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!soAA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!soAA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!soAA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!soAA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!soAA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!soAA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9489886d-13fc-4f5e-b981-6949fd82664a_1024x1024.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 can&#8217;t help it. Just like the lab rat pushing the button to get the next food pellet, I love delivering features; creating and delivering something new. In the past, I was known for delivering features the customer didn&#8217;t even know they wanted. That&#8217;s a superhero play.</p><p>It&#8217;s also ridiculously stupid.</p><p>Every feature we add to our software represents a future liability, because all that code will need to be supported, maintained, extended, and understood by new developers.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C9jZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C9jZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png 424w, https://substackcdn.com/image/fetch/$s_!C9jZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png 848w, https://substackcdn.com/image/fetch/$s_!C9jZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png 1272w, https://substackcdn.com/image/fetch/$s_!C9jZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C9jZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png" width="895" height="84" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:84,&quot;width&quot;:895,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14283,&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;:&quot;https://articles.pragdave.me/i/159301500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!C9jZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png 424w, https://substackcdn.com/image/fetch/$s_!C9jZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png 848w, https://substackcdn.com/image/fetch/$s_!C9jZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png 1272w, https://substackcdn.com/image/fetch/$s_!C9jZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd651be1a-d784-46ca-ac84-58b574ea7b6b_895x84.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>Does that stop everyone adding feature after feature? No.</p><p>Should it?</p><p>Yes, sometimes.</p><h3><strong>Need Driven Development</strong></h3><p>There&#8217;s a basic rule for keeping software simple: don&#8217;t write code unless someone needs the functionality it provides. And &#8220;wouldn&#8217;t it be cool if&#8230;&#8221; and &#8220;it&#8217;d be really easy to add&#8230;&#8221; don&#8217;t count as need.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gDry!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gDry!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png 424w, https://substackcdn.com/image/fetch/$s_!gDry!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png 848w, https://substackcdn.com/image/fetch/$s_!gDry!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png 1272w, https://substackcdn.com/image/fetch/$s_!gDry!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gDry!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png" width="895" height="82" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:82,&quot;width&quot;:895,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:10223,&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;:&quot;https://articles.pragdave.me/i/159301500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gDry!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png 424w, https://substackcdn.com/image/fetch/$s_!gDry!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png 848w, https://substackcdn.com/image/fetch/$s_!gDry!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png 1272w, https://substackcdn.com/image/fetch/$s_!gDry!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40074f8b-d1a6-45da-bfd4-8070840a9af3_895x82.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Obviously, need depends on your context. If your company is creating a mass-market product, then the marketing folks will likely be keeping an eye on competitors and creating feature requests to keep up and surpass them. That&#8217;s genuine need.</p><p>But if you&#8217;re creating software for a single client or internal use, then the concept of need becomes more interesting. It can also be tainted by politics.</p><p>I&#8217;ve spoken to managers who have to budget for software development. Every year, they prepare a report saying what they want to build, how much it will cost, and what value it will produce. They&#8217;ll receive back an approval to spend some amount, normally lower than their request. So what do they do? They add all the features they think they might need to the project before they submit it. This both bumps up the price and also acts as a form of insurance; they don&#8217;t want to ask for a baseline project this year only to get turned down for the extensions they need next year. This applies to both internal and external clients.</p><p>But we can be more agile than that. Back when I was delivering software to paying customers, I&#8217;d flip the equation around. Rather than talking about need, I&#8217;d ask the customer where they&#8217;d extract value from the project, and what their priorities were for doing so.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aApp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aApp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png 424w, https://substackcdn.com/image/fetch/$s_!aApp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png 848w, https://substackcdn.com/image/fetch/$s_!aApp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png 1272w, https://substackcdn.com/image/fetch/$s_!aApp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aApp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png" width="895" height="81" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:81,&quot;width&quot;:895,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8767,&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;:&quot;https://articles.pragdave.me/i/159301500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aApp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png 424w, https://substackcdn.com/image/fetch/$s_!aApp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png 848w, https://substackcdn.com/image/fetch/$s_!aApp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png 1272w, https://substackcdn.com/image/fetch/$s_!aApp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dc8dc36-d180-4937-82f1-c1ff513993ed_895x81.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Then the team and I would go away and assign a level of effort to delivering these values. This is purely internal to the team: we just needed a sense of how big the task was. The result of the guess would be as simple as &#8220;easy,&#8221; &#8220;medium,&#8221; &#8220;difficult,&#8221; and &#8220;unknown.&#8221;</p><p>We&#8217;d take these rough estimates and compare them to the value they&#8217;d deliver. Assuming the dependencies would allow it, we could then work out which features we could deliver early that would also give the customer a decent amount of business value.</p><p>Then we&#8217;d go back to the customer and say something like:</p><blockquote><p>We&#8217;ve been looking at your requirements, and we think we can give you some options. This first is a conventional project, where we deliver the software to you at the end.</p><p>With the second option, we&#8217;ll deliver the software incrementally, feature by feature. We looked through your list of values, and combined them with our project planning, and we feel that we can deliver feature X well before the final project is complete. You should be able to start using it then, getting business value early. We can talk nearer the time about subsequent deliveries, but right now we think we might look at features Y and Z next.</p></blockquote><p>This gives the customer two big wins. First, they can start earning some value from the software earlier; value now is always better than the same value later. Second, your customer gets to experience using this first deliverable. In my experience, when the customer first uses a partial delivery, they suddenly realize things about the system that weren&#8217;t apparent when it was just some words in a document. They&#8217;ll be able to come back to you with ideas and suggestions for next steps that might be radically different from their original request. In fact, a while back I had a customer who took the first two of five feature deliveries and then said the system did just what they needed; the extra three features were there for insurance, and they weren&#8217;t required.</p><p>It also gives you some massive wins. First, you get feedback a lot earlier than you would. Ideally you&#8217;ll be talking with the customer every week, but often that just doesn&#8217;t happen. But you&#8217;ll definitely get their attention when you deliver something. Second, you start to build a trusting relationship with them. When the project started they were taking a risk on you. When you deliver something, even if it&#8217;s not the complete project, they&#8217;ll start feeling a lot more comfortable, and you&#8217;ll find that you&#8217;ll get more open and useful interactions with them. Finally, this approach catches potential problems early: if you have a misunderstanding that would propagate throughout the code, finding out early stops a whole lot of rework later.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5HlO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5HlO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png 424w, https://substackcdn.com/image/fetch/$s_!5HlO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png 848w, https://substackcdn.com/image/fetch/$s_!5HlO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png 1272w, https://substackcdn.com/image/fetch/$s_!5HlO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5HlO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png" width="895" height="81" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:81,&quot;width&quot;:895,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12593,&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;:&quot;https://articles.pragdave.me/i/159301500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5HlO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png 424w, https://substackcdn.com/image/fetch/$s_!5HlO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png 848w, https://substackcdn.com/image/fetch/$s_!5HlO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png 1272w, https://substackcdn.com/image/fetch/$s_!5HlO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9c9e4aa-db4d-487b-848c-4405d8246c0a_895x81.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><h3><strong>Simplicity</strong></h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sRqh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sRqh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png 424w, https://substackcdn.com/image/fetch/$s_!sRqh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png 848w, https://substackcdn.com/image/fetch/$s_!sRqh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png 1272w, https://substackcdn.com/image/fetch/$s_!sRqh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sRqh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png" width="900" height="517" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:517,&quot;width&quot;:900,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Graph showing complexity grows faster than features&quot;,&quot;title&quot;:&quot;Graph showing complexity grows faster than features&quot;,&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="Graph showing complexity grows faster than features" title="Graph showing complexity grows faster than features" srcset="https://substackcdn.com/image/fetch/$s_!sRqh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png 424w, https://substackcdn.com/image/fetch/$s_!sRqh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png 848w, https://substackcdn.com/image/fetch/$s_!sRqh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.png 1272w, https://substackcdn.com/image/fetch/$s_!sRqh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c4f2a1c-7480-45af-ad14-cc3ae76bff7a_900x517.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>You can&#8217;t ship software that does nothing. But you can work to reduce the number of features, delivering only what&#8217;s needed, free from unnecessary embellishments or complications, and delivering it earlier. Features can always be added later.</p><blockquote><h3>Your turn</h3><p>Look back at some projects you&#8217;ve delivered. What percentage of the code in each gets used on a daily basis? What percentage would you guess never gets used?</p></blockquote><p></p><div><hr></div><p>This was an extract from my new book, simplicity, now in beta at <a href="https://pragprog.com/titles/dtcode/simplicity?utm_source=substack&amp;utm_campaign=article-2025-03-18">pragprog.com.</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://pragprog.com/titles/dtcode/simplicity?utm_source=substack&amp;utm_campaign=article-2025-03-18" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XYuw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 424w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 848w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 1272w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XYuw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic" width="398" height="490.93956043956047" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1796,&quot;width&quot;:1456,&quot;resizeWidth&quot;:398,&quot;bytes&quot;:187128,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:&quot;https://pragprog.com/titles/dtcode/simplicity?utm_source=substack&amp;utm_campaign=article-2025-03-18&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://articles.pragdave.me/i/159022241?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XYuw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 424w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 848w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 1272w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/the-best-features-are-the-ones-you?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/the-best-features-are-the-ones-you?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item><item><title><![CDATA[Agility On An Index Card]]></title><description><![CDATA[This is an extract from my book "simplicity." The layout has been simplified to work with substack.]]></description><link>https://articles.pragdave.me/p/agility-on-an-index-card</link><guid isPermaLink="false">https://articles.pragdave.me/p/agility-on-an-index-card</guid><dc:creator><![CDATA[Pragdave]]></dc:creator><pubDate>Thu, 13 Mar 2025 21:11:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QV0X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here&#8217;s how I try to develop software.</p><ul><li><p>I work in the smallest increments I can, using feedback at all levels to assess the value being produced.</p></li><li><p>I constantly adapt what I do, but only after I&#8217;ve decided how to tell if the impact of the change was good or bad.</p></li><li><p>I deliver value incrementally, as soon as I have something new to show my users. That way I can use their feedback to guide my next steps.</p></li></ul><p>I&#8217;m not always successful. In 2023/4 I wasted nine months because I went heads down on a complex project. I got caught up in the technicalities and forgot to deliver incrementally. I&#8217;m still learning. But the vast majority of the time, I stick to these principles, and it works well.</p><h3><strong>Break It Down</strong></h3><p>Here&#8217;s how I apply these principles. There are just three activities.</p><p><strong>1: Orient</strong></p><ul><li><p>I find out where I am.</p></li></ul><p><strong>2: Step</strong></p><ul><li><p>I take the smallest possible step towards where I want to be, doing the least amount of work possible to generate something that gives me some feedback.</p></li></ul><p><strong>3: Learn</strong></p><ul><li><p>I assess whether what I did produced the expected value.</p></li><li><p>I adjust my understanding based on the feedback.</p></li><li><p>And I go back to the first activity, and reorient myself.</p></li></ul><p>Honestly, there&#8217;s nothing special about this; it&#8217;s really just common sense. But it only works if you consciously follow the three steps.</p><blockquote><p><strong>All Of agility Comes Down to Orient, Step, Learn</strong></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_!QV0X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QV0X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic 424w, https://substackcdn.com/image/fetch/$s_!QV0X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic 848w, https://substackcdn.com/image/fetch/$s_!QV0X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic 1272w, https://substackcdn.com/image/fetch/$s_!QV0X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QV0X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic" width="1456" height="598" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:598,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:398690,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://articles.pragdave.me/i/159022241?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QV0X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic 424w, https://substackcdn.com/image/fetch/$s_!QV0X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic 848w, https://substackcdn.com/image/fetch/$s_!QV0X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic 1272w, https://substackcdn.com/image/fetch/$s_!QV0X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c7dda7b-f9b4-4a99-a957-37267acfe16b_3794x1558.heic 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://unsplash.com/@oriz?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Ron Fung</a> on <a href="https://unsplash.com/photos/dog-jumping-on-lawn-during-daytime-VQJXJ4IaU_o?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure></div><p>Here&#8217;s an example. This afternoon I had a call with Susannah, my wonderful editor. She mentioned that she could no longer build my book; she got a &#8220;file not found&#8221; error. Every other book built just fine for her. She sent me the console log. (I think it&#8217;s so cool that my editor uses the command line&#8230;)</p><p>I went through the three activities in a cycle. (And, yes, I&#8217;m laboring the point a little. Bear with me.)</p><p><strong>Orient #1</strong></p><p>I tried building my book on my machine and had no problems, so the issue was likely a difference between her environment and mine. One thing she mentioned was that she stored all her book projects in a directory with a space in the path.</p><p><strong>Step #1</strong></p><p>We&#8217;ve had problems with paths like this in the past, but we fixed them and haven&#8217;t seen any issues for years. But, in lieu of any better idea, the simplest thing would be to check the book out into a path that contained spaces on my machine and see if it worked. It failed just as hers had done.</p><p><strong>Learn #1</strong></p><p>Despite my strong belief going in to this, it <em>was</em> the space in the path causing the problem. Time to reorient my thinking. Back to step 1.</p><p><strong>Orient #2</strong></p><p>I knew the book built successfully on her machine last week, but not this week, so I was probably looking for something I&#8217;d messed up over the weekend. But I wasn&#8217;t aware of changing anything to do with paths.</p><p><strong>Step #2</strong></p><p>The simplest thing was to scan the change logs. I saw no modifications to any of the actual tools, but I did see that I&#8217;d bumped the version of JRuby that we use.</p><p><strong>Learn #2</strong></p><p>Given that this had to be related to code, and the only code that changed was the third party JRuby compiler, I had a suspect.</p><p><strong>Orient #3</strong></p><p>Over the years I&#8217;ve taught myself that when something breaks, 99.999% of the time it&#8217;s my fault, and not a bug in some third party code. So the orientation here was to convince myself that a quick test was needed.</p><p><strong>Step #3</strong></p><p>I tried running <code>jruby -v</code> and it also failed.</p><p>and so on&#8230;</p><p>In the end, it was a bug in the <code>jruby</code> script in the newly updated package. I rolled back to the previous version and reported it to the JRuby team on GitHub. Charles Nutter acknowledged it within a couple of hours, and a patch was available a few hours later (which is seriously agile).</p><h3><strong>But Dave&#8230;</strong></h3><p>I know what you&#8217;re thinking: <em>&#8220;That&#8217;s nothing special. That how everyone would attack an issue like this.&#8221;</em></p><p>Maybe&#8212;but not in my experience. I&#8217;ve given many classes to all levels of developer, and most people do not take a methodical approach to this kind of problem. I have sympathy, because neither did I.</p><p>Also, remember that these three steps apply to everything I do, from naming functions though picking a technology for our new website: <em>Orient, Step, Learn, repeat.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D6Wu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D6Wu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!D6Wu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!D6Wu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!D6Wu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D6Wu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2155523,&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;:&quot;https://articles.pragdave.me/i/159022241?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D6Wu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!D6Wu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!D6Wu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!D6Wu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01645552-5a58-4f31-b062-492ce799ab7e_1024x1024.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><h3><strong>A Larger Example</strong></h3><p>The publishing industry is mired in the Victorian times. All information is exchanged in spreadsheets, with people at one end manually creating them and people at the other end transcribing information into some 1990s mainframe system. We receive monthly distributor statements this way, but we process them in code.</p><p>A few years back, our international distributor started creating a different monthly spreadsheet. We adjusted our ingestion code to match. A couple of months later, it failed: they&#8217;d renamed some columns, and added a few new ones. This triggered an Orient, Step, Learn cycle.</p><p>During orientation, we determined that this was likely to be an ongoing problem, and that we&#8217;d likely have to adjust our import now and then going forward. We also knew that we had to retain the ability to reimport all historical data, so our code would have to add new CSV formats while still accepting the old. This mean that we&#8217;d need to decouple to reading of the raw data from the processing of that data. A pipeline was born.</p><p>Step one was to make that split in the code explicit and run regression tests to make sure nothing had changed. Not much to learn, so we went back to the orientation step.</p><p>We had to deal with two types of change: the order (and number) of columns could be different, and the column names would often change (sometimes with typos, so it was clearly created by hand every month). We needed to decouple the finding of the data we needed from the layout of the spreadsheet.</p><p>Step two was to replace the code that analyzed the spreadsheet with a table that mapped column names to internal variables so that the internal value <code>total_sales</code> could be extracted from a column called <code>Sales</code> one month and <code>Sale total</code> the next. Again, we ran regressions to verify the step.</p><p>Orienting again, we needed to make sure that we could read all historical imports while adding new layouts.</p><p>The next step was to use the tables we&#8217;d defined in the previous cycle to pattern match against the incoming spreadsheet. If the column names and locations matched a table, we&#8217;d use that for the extraction. If no table matched, we&#8217;d abandon the import and someone would have to create a new mapping table.</p><p>Again, we ran regression tests, this time against the accumulated months of data. At this point we&#8217;d learned all we could until new data arrived.</p><p>Over the following months, the distributor managed to throw a few more surprises at us: columns with the same names as before but with different values, different formats for currency values, and so on. We used each of these to trigger a new Orient, Step, Learn cycle. Often we&#8217;d find that we&#8217;d spend more time on the Orient and Learn steps with these changes, as we tried to find patterns in the changes, and tried to build in more safeguards to ensure we weren&#8217;t misinterpreting the data.</p><p>Over the last 36 months, there have been 15 different formats sent to us. Sometimes we&#8217;ll get the same format for three months in a row, and sometimes a format from the past will suddenly reappear.</p><p>I draw two lessons from this. First, the initial orientation was critical; working out that we needed backwards compatibility informed all the decisions we subsequently made. In particular, splitting the code into separate parsing and processing steps turned out to be the right step.</p><p>The second lesson was the benefits of the small steps. I am absolutely paranoid about royalty calculations: getting authors and editors paid accurately for their hard work is critical to me. When dealing with something as uncertain as this feed, taking lots of small steps, and running full regression tests at each, gave me the confidence to deploy these changes.</p><h3><strong>The Benefits</strong></h3><p>It&#8217;s a simple plan, but <em>Orient-Step-Learn</em> is the fundamental essence of agility. It makes me conscious of the changes I make and the feedback I need when making them.</p><p>I find there are so many benefits to following this ritual:</p><ul><li><p><em>Pausing to orient myself</em> before attacking my keyboard saves my butt many times a day. I realize I was about to solve the wrong problem, or that I&#8217;d already solved the same problem elsewhere, or that I didn&#8217;t actually understand what I was about to do.</p></li><li><p><em>Being deliberate about feedback</em> focusses what I do in each step; I only do work that&#8217;s contributing to generating a successful result.</p></li><li><p>I give myself <em>permission to experiment and fail,</em> knowing that the cost is minimal because I&#8217;ve taken just a small step.</p></li></ul><blockquote><h3><strong>Pause, Then Act</strong></h3></blockquote><p>It can also be a difficult and sometimes painful plan to implement. It means slowing down and giving up the illusion of control. (Hint: we never really had control in the first place.)</p><p>It means constantly experimenting, and constantly using those experiments to improve what you do and how you do it. It means getting used to the idea that failing is an integral part of succeeding.</p><h3><strong>Your Turn</strong></h3><p>Please try organizing your work into these three practices. It&#8217;s a purely personal thing: you don&#8217;t need permission to do it. It&#8217;s simply a way of organizing how you think about what you do</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bAt6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bAt6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic 424w, https://substackcdn.com/image/fetch/$s_!bAt6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic 848w, https://substackcdn.com/image/fetch/$s_!bAt6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic 1272w, https://substackcdn.com/image/fetch/$s_!bAt6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bAt6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic" width="1456" height="877" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:877,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18043,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://articles.pragdave.me/i/159022241?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bAt6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic 424w, https://substackcdn.com/image/fetch/$s_!bAt6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic 848w, https://substackcdn.com/image/fetch/$s_!bAt6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic 1272w, https://substackcdn.com/image/fetch/$s_!bAt6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48e3ac24-733a-4b36-bce5-8eccd14e4f24_1508x908.heic 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 practice, it&#8217;s probably less work that you&#8217;re doing now, and it&#8217;s more productive. But it also requires that you build a set of habits, so that you naturally think about feedback when you both start and finish anything. And, as with any habit, this means that initially you&#8217;ll need to do it consciously and deliberately. Maybe write on an index card and tape it to your screen.</p><p>And, obviously, use your daybook to record all of this. (And if you aren&#8217;t using a daybook, perhaps have a look at <a href="https://pragdave.substack.com/p/why-you-need-a-daybook">this article</a> before continuing.) At first, record every decision you make, and go back when you finished that particular step and record the feedback; a tick if it worked and an angry X if not.</p><p>And, just to keep you on the straight and narrow, never start something until you&#8217;ve established what feedback you&#8217;ll use to decide whether it was successful.</p><p>The rest of this chapter is a deeper dive into Orient, Step, and Learn.</p><blockquote><h3><strong>Try this</strong></h3><p>Write &#8220;Orient, Step, Learn&#8221; on something and stick it in your line of sight while working. Or, stick it in a file and make that the default buffer your editor shows. Or decorate your desktop. Maybe tattoo it on the inside of your eyelids.</p><p>Do whatever it takes to remind yourself to be deliberate as you work, consciously taking the three steps as you move forward.</p><p>(This is going to sound silly, but you might try saying &#8220;Orient&#8221; aloud as you start an activity, then &#8220;Step&#8221; when you&#8217;ve decided what to to, and then &#8220;Learn&#8221; when it&#8217;s done. I do this all the time when I&#8217;m trying to adjust my habits; I find that vocalizing seems to engage a different part of my brain, and doing that speeds my adoption.)</p></blockquote><h3></h3><blockquote><h3>Think about</h3><p>Do you suppose this idea might apply to things other than software development?  </p></blockquote><div><hr></div><p>This was an extract from my new book, simplicity, now in beta at <a href="https://pragprog.com/titles/dtcode/simplicity">pragprog.com.</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XYuw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XYuw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 424w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 848w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 1272w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XYuw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic" width="398" height="490.93956043956047" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1796,&quot;width&quot;:1456,&quot;resizeWidth&quot;:398,&quot;bytes&quot;:187128,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://articles.pragdave.me/i/159022241?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XYuw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 424w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 848w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 1272w, https://substackcdn.com/image/fetch/$s_!XYuw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa216a1-f3cd-4a22-9c5e-e3023098b4a9_2250x2775.heic 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/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://articles.pragdave.me/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://articles.pragdave.me/p/agility-on-an-index-card?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://articles.pragdave.me/p/agility-on-an-index-card?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item></channel></rss>