<?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[Deeply Nested]]></title><description><![CDATA[On the craft and industry of Software Engineering]]></description><link>https://nested.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!fF2b!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7e5fcb0-569a-420e-8812-92bb08ec735e_512x512.png</url><title>Deeply Nested</title><link>https://nested.substack.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 19 May 2026 08:33:50 GMT</lastBuildDate><atom:link href="https://nested.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Jeff Schwab]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[nested@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[nested@substack.com]]></itunes:email><itunes:name><![CDATA[Jeff Schwab]]></itunes:name></itunes:owner><itunes:author><![CDATA[Jeff Schwab]]></itunes:author><googleplay:owner><![CDATA[nested@substack.com]]></googleplay:owner><googleplay:email><![CDATA[nested@substack.com]]></googleplay:email><googleplay:author><![CDATA[Jeff Schwab]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Acceleration over Position]]></title><description><![CDATA[Focus on surviving and thriving, even at the expense of short term goals.]]></description><link>https://nested.substack.com/p/acceleration-over-position</link><guid isPermaLink="false">https://nested.substack.com/p/acceleration-over-position</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Thu, 17 Oct 2024 19:49:37 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/32637338-1567-4a70-bf91-5f70ab1bab8f_1252x838.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The single biggest mistake I see at early stage startups is focus on <em>position</em> rather than <em>acceleration</em>.  If you&#8217;re engaged in an iterative process&#8212;such as integrating new data sources, or on-boarding new customers&#8212;and your team isn&#8217;t moving fast enough, then one of the worst mistakes you can make is to achieve short term goals in a way that doesn&#8217;t improve your ability to execute on long term goals.  In other words:  <strong>Whatever it is that you need to get better at, prioritize getting better at that thing,</strong> not on achieving &#8220;victories&#8221; that won&#8217;t increase your rate of delivery on future iterations.</p><blockquote><p>Just when we shelter under paper, the rockets come at us sideways.</p><p>&#8212;Meat Puppets, <em><a href="https://www.youtube.com/watch?v=oFD88EyZ80E">Backwater</a></em></p></blockquote><p>As a software engineer, the chief manifestation of this mistake I see up close is the accumulation of technical debt.  Some amount of debt is natural; and, in fact, the amount of debt may reasonably <em>increase</em> over time (implying a <em>tech</em> <em>deficit</em>), so long as the team&#8217;s ability to deliver increases at an even greater rate.  But if each new integration, customer, etc. is no faster or easier than the last, then you cannot scale any faster than linearly (O(N)), which is typically not good enough for a startup with limited runway; nor, indeed, for any initiative in a competitive market, since somebody else will soon be better at this (whatever &#8220;this&#8221; is) than you are.  If you&#8217;re not actively tracking your debt vs. delivery rate, it's likely that your acceleration is <em>negative</em>, meaning your ability to scale isn&#8217;t even linear.</p><p>When institutional debt&#8212;technical or otherwise&#8212;interferes with acceleration, a common response is to hire more people.  Surprisingly, this makes the problem worse, not better.  This principle is sometimes called Brooks&#8217;s Law:</p><blockquote><p>Adding manpower to a late software project makes it later.</p><p>&#8212;Fred Brooks, <em>The Mythical Man-Month</em></p></blockquote><p>The inclination to expand the team, even when management is intellectually aware of this principle, stems from a misunderstanding of the root cause of the problem.  The issue is neither position, nor velocity, but <em>rate of change</em> in that velocity.  If you&#8217;re going in the wrong direction, then doing that faster makes things worse, not better.  A more intuitive phrasing of Brooks&#8217;s Law may be the old joke (whose origin eludes me, but please do enlighten me in the comments):</p><blockquote><p>We're losing money on every unit, but we'll make it up in volume.</p></blockquote><p>If the reason you&#8217;re not moving fast enough is that you&#8217;re accumulating tech debt faster than you&#8217;re acquiring reliable automation, then hiring more people is like trying to &#8220;make it up in volume.&#8221;  You&#8217;re only making the problem worse.</p><p>A lot of Deeply Nested readers will be familiar with the tribulations of trying to deliver market value in the face of accumulated tech debt, bureaucracy, or other institutional inertia.  Aside from tech debt, the most common form I&#8217;ve seen in person has been badly structured deals, the architects of which are often long gone by the time I arrive.  Deal structuring is an underrated art form.  If you&#8217;re in the process of signing a new customer to a long-term support contract, take care what concessions you make: They will have a real impact on your life (or at least, the lives of your teammates) for years to come.</p><p>If it feels like you&#8217;re spinning your wheels faster and faster, but not getting anywhere, then it&#8217;s likely you&#8217;re not understanding the actual impediments to progress.  These are often several degrees removed from easily observable metrics like delivery or integration time, instead amounting to things like code complexity or customer support burden.  The only way to defeat these impediments once you&#8217;ve identified them, as far as I know, is head on.  <strong>The direction of your velocity is more important than its magnitude, and its derivative </strong><em><strong>acceleration</strong></em><strong> is more important than either.  </strong>If your weapons are pointed in the wrong direction, you&#8217;re liable to suffer more damage from friendly fire than you inflict on your opponents.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n9bC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n9bC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg 424w, https://substackcdn.com/image/fetch/$s_!n9bC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg 848w, https://substackcdn.com/image/fetch/$s_!n9bC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!n9bC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n9bC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg" width="225" height="225" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:225,&quot;width&quot;:225,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSLHV0_8VVWd8pdzwG-fIiGPWZtUmr485g3-A&amp;s&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSLHV0_8VVWd8pdzwG-fIiGPWZtUmr485g3-A&amp;s" title="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSLHV0_8VVWd8pdzwG-fIiGPWZtUmr485g3-A&amp;s" srcset="https://substackcdn.com/image/fetch/$s_!n9bC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg 424w, https://substackcdn.com/image/fetch/$s_!n9bC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg 848w, https://substackcdn.com/image/fetch/$s_!n9bC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!n9bC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcdc69ab-2f36-4060-aed1-5e70d12fe9d8_225x225.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>If you agree with this sentiment in principle, but simply can&#8217;t afford the time to make fundamental changes, then it&#8217;s time to move on.  You&#8217;re like a passenger on a sinking ship who can&#8217;t stop bailing water long enough to plug the holes in the hull.  So, at some point, you have to ask yourself:  Is this boat sufficiently maneuverable to reach a safe harbor before it sinks?  You might as well take drastic measures, when the only alternative is going down with the ship.</p>]]></content:encoded></item><item><title><![CDATA[One Silly Integer Trick]]></title><description><![CDATA[Just a bit (or two) of fun.]]></description><link>https://nested.substack.com/p/one-silly-integer-trick</link><guid isPermaLink="false">https://nested.substack.com/p/one-silly-integer-trick</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 12 Apr 2024 16:44:58 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f28246c4-bd0e-4d3b-aa02-0afe316cb91a_1254x836.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>2 in 1 shampoo is not real, because 1 is not big enough to hold 2.  That's why 2 was created.  If it was 2 in 1, it would be overflowing.</p><p>&#8212;<a href="https://www.youtube.com/watch?v=cF8MpK-yK5o&amp;t=272s">Mitch Hedberg</a></p></blockquote><blockquote><p>What you must learn is that these rules are no different than the rules of a computer system.  Some of them can be bent.  Others can be broken.</p><p>&#8212;Morpheus, in <a href="https://www.youtube.com/watch?v=ozGuPbeFFIY">The Matrix</a></p></blockquote><div><hr></div><p>Pairs of countable things are themselves countable.  In other words:  Any pair of integers can be associated with a single scalar integer, distinct from the integer representing any other pair.</p><p>One way is to raise mutual primes, such as 2 and 3, to the original values, then multiply the results to get a single number, as in the following &#8216;encode&#8217; function:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g1hl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g1hl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png 424w, https://substackcdn.com/image/fetch/$s_!g1hl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png 848w, https://substackcdn.com/image/fetch/$s_!g1hl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png 1272w, https://substackcdn.com/image/fetch/$s_!g1hl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g1hl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png" width="1456" height="441" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:441,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:291050,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!g1hl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png 424w, https://substackcdn.com/image/fetch/$s_!g1hl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png 848w, https://substackcdn.com/image/fetch/$s_!g1hl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.png 1272w, https://substackcdn.com/image/fetch/$s_!g1hl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc74cc004-1eb1-4ebc-9039-0f588bcec993_2484x752.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><figcaption class="image-caption"><a href="https://github.com/jeffs/nested/blob/main/silly-integer-trick/src/encode/encode.rs">encode/encode.rs</a></figcaption></figure></div><p>This is more powerful than simple addition, multiplication, or exponentiation, because it&#8217;s guaranteed to be reversible.  We can recover the inputs by factoring, as in this &#8216;decode&#8217; function:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A902!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A902!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png 424w, https://substackcdn.com/image/fetch/$s_!A902!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png 848w, https://substackcdn.com/image/fetch/$s_!A902!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png 1272w, https://substackcdn.com/image/fetch/$s_!A902!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A902!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png" width="1456" height="828" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:828,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:533561,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!A902!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png 424w, https://substackcdn.com/image/fetch/$s_!A902!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png 848w, https://substackcdn.com/image/fetch/$s_!A902!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.png 1272w, https://substackcdn.com/image/fetch/$s_!A902!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6e21224c-bcb5-44c7-8657-4b3871d76917_2484x1412.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><figcaption class="image-caption"><a href="https://github.com/jeffs/nested/blob/main/silly-integer-trick/src/encode/decode.rs">encode/decode.rs</a></figcaption></figure></div><p>For example, we can encode the pair (3, 5) as the single value 1944, because 2**3 = 8, 3**5 = 243, and 8 * 243 = 1944:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GO20!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GO20!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png 424w, https://substackcdn.com/image/fetch/$s_!GO20!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png 848w, https://substackcdn.com/image/fetch/$s_!GO20!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png 1272w, https://substackcdn.com/image/fetch/$s_!GO20!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GO20!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png" width="1456" height="634" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:634,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:379499,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!GO20!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png 424w, https://substackcdn.com/image/fetch/$s_!GO20!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png 848w, https://substackcdn.com/image/fetch/$s_!GO20!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.png 1272w, https://substackcdn.com/image/fetch/$s_!GO20!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64ace455-608b-42b7-884b-e2797522f4cc_2484x1082.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 href="https://github.com/jeffs/nested/blob/main/silly-integer-trick/src/encode/tests.rs">encode/tests.rs</a></figcaption></figure></div><p>Let&#8217;s take this trick for a spin on everyone&#8217;s favorite hobbyhorse, the Fibonaccis.</p><p>The Fibonacci sequence (<a href="https://oeis.org/A000045">OEIS A000045</a>) is a well known plaything of mathematicians and programmers alike.  It begins [0, 1], and each subsequent number is the sum of the previous two.  The first ten Fibonacci numbers are therefore [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jweo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jweo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png 424w, https://substackcdn.com/image/fetch/$s_!Jweo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png 848w, https://substackcdn.com/image/fetch/$s_!Jweo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!Jweo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jweo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png" width="1456" height="712" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:712,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:420039,&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_!Jweo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png 424w, https://substackcdn.com/image/fetch/$s_!Jweo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png 848w, https://substackcdn.com/image/fetch/$s_!Jweo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!Jweo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19281813-3ef1-4bab-8d15-6767b515bbf0_2484x1214.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 href="https://github.com/jeffs/nested/blob/main/silly-integer-trick/fibs.txt">fibs.txt</a></figcaption></figure></div><p>A loop for generating Fibonacci numbers obviously must maintain two integer values as state, because, by definition, it needs them to compute the next value:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QDw0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QDw0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png 424w, https://substackcdn.com/image/fetch/$s_!QDw0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png 848w, https://substackcdn.com/image/fetch/$s_!QDw0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png 1272w, https://substackcdn.com/image/fetch/$s_!QDw0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QDw0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png" width="1456" height="1060" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c2330f08-79e5-490d-906a-a26450179bad_2484x1808.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1060,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:673210,&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_!QDw0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png 424w, https://substackcdn.com/image/fetch/$s_!QDw0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png 848w, https://substackcdn.com/image/fetch/$s_!QDw0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.png 1272w, https://substackcdn.com/image/fetch/$s_!QDw0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2330f08-79e5-490d-906a-a26450179bad_2484x1808.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 href="https://github.com/jeffs/nested/blob/main/silly-integer-trick/src/nth_fib.rs">nth_fib.rs</a></figcaption></figure></div><p>But using our handy integer compression trick, we can amaze friends and family by implementing a Fibonacci loop that maintains only a single integer between iterations!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7A5Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7A5Y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png 424w, https://substackcdn.com/image/fetch/$s_!7A5Y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png 848w, https://substackcdn.com/image/fetch/$s_!7A5Y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png 1272w, https://substackcdn.com/image/fetch/$s_!7A5Y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7A5Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png" width="1456" height="1098" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1098,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:734239,&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_!7A5Y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png 424w, https://substackcdn.com/image/fetch/$s_!7A5Y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png 848w, https://substackcdn.com/image/fetch/$s_!7A5Y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.png 1272w, https://substackcdn.com/image/fetch/$s_!7A5Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4a7e827-80ba-4ba3-82af-383729b4ae6d_2484x1874.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 href="https://github.com/jeffs/nested/blob/main/silly-integer-trick/src/nth_fib_scalar.rs">nth_fib_scalar.rs</a></figcaption></figure></div><p>Can we repeat the process, reducing any four values into two scalars, and thence to a single integer?  By extension, can we compress arbitrary amounts of data into a single integer?  Yes in principle, but no in practice, because the exponentiation quickly causes overflow, or turns BigInts into RAM hogs.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G4Hd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G4Hd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg 424w, https://substackcdn.com/image/fetch/$s_!G4Hd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg 848w, https://substackcdn.com/image/fetch/$s_!G4Hd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!G4Hd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G4Hd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg" width="1024" height="681" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:681,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:167554,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!G4Hd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg 424w, https://substackcdn.com/image/fetch/$s_!G4Hd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg 848w, https://substackcdn.com/image/fetch/$s_!G4Hd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!G4Hd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631281d3-6ee2-4f44-bdf7-2c2fbdb45f91_1024x681.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">Dogs rolling in the grass, proving the value of silly tricks.</figcaption></figure></div><p>Does this trick have any practical application at all?  None whatsoever, as far as I know.  It&#8217;s just cool enough that I thought you should know about it. &#128526;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts.</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[Been a Minute]]></title><description><![CDATA[How you doin'?]]></description><link>https://nested.substack.com/p/been-a-minute</link><guid isPermaLink="false">https://nested.substack.com/p/been-a-minute</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Sat, 06 Apr 2024 15:25:58 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/57d8bf39-386a-4dad-bec6-bd7a12fc2352_2660x1700.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Long time, no see!  Deeply Nested has been on hiatus for the past <em>[checks watch]</em> sixteen months.  Oof.  Before we return to our regularly scheduled musings, we have some spring cleaning to do.</p><h1>How should we present inline code?</h1><p>Substack&#8217;s Gist integration broke, and they don&#8217;t seem inclined to fix it.  I&#8217;ll be updating old posts to replace the Gists with&#8230; something.  But going forward, Gists are no longer really an option.  I see two viable alternatives:</p><ol><li><p><strong>Code blocks.</strong> Substack now has inline code blocks that are, dare I say, almost usable.  They still have some serious drawbacks:  They don&#8217;t support syntax highlighting.  They&#8217;re limited to 73 columns on desktop, and some laughable width on mobile.  If we want line numbers, those come out of our line width budget.  They don&#8217;t support captions or alt text.</p></li><li><p><strong>Screenshots.</strong> The most flexible option is to screenshot code, and hyperlink plain text versions in the image captions.  The primary limitation of screenshots is that they force readers who can&#8217;t visually see the code to click through links.</p><p>By the way, Substack&#8217;s alt text support is now completely broken.  Seriously, they lose the image entirely if I add alt text.  On the bright side, it&#8217;s <em>so</em> broken that maybe they&#8217;ll actually fix it.</p></li></ol><p>For comparison, here&#8217;s a code block, followed by the same code as a linked screenshot:</p><pre><code><code>/// Upper cases text from r, and writes it to w.
fn to_upper&lt;R: BufRead, W: Write&gt;(
    mut r: R,
    w: &amp;mut W,
) -&gt; io::Result&lt;()&gt; {
    let line = &amp;mut String::new();
    while r.read_line(line)? != 0 {
        w.write(line.to_uppercase().as_bytes())?;
    }
    Ok(())
}</code></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_!91YB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!91YB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png 424w, https://substackcdn.com/image/fetch/$s_!91YB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png 848w, https://substackcdn.com/image/fetch/$s_!91YB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png 1272w, https://substackcdn.com/image/fetch/$s_!91YB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!91YB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png" width="1244" height="690" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:690,&quot;width&quot;:1244,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:118085,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!91YB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png 424w, https://substackcdn.com/image/fetch/$s_!91YB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png 848w, https://substackcdn.com/image/fetch/$s_!91YB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.png 1272w, https://substackcdn.com/image/fetch/$s_!91YB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa28af182-19ba-4fd8-83ec-6d6703c9dfc9_1244x690.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><figcaption class="image-caption"><a href="https://github.com/jeffs/nested/blob/main/been-a-minute/to_upper.rs">to_upper.rs</a> (<a href="https://raw.githubusercontent.com/jeffs/nested/main/been-a-minute/to_upper.rs">raw</a>)  This is the same snippet shown in the code block above.  Do you find linked screenshots a reasonable way to present code?</figcaption></figure></div><h1>Should we stay on Substack?</h1><p>Other options include Notion, Squarespace, or a bespoke website.  It would be a shame to make current subscribers&#8212;there are <em>several</em> of you!&#8212;switch platforms, or else for Deeply Nested to lose those subscribers.  But Substack&#8217;s support, especially for technical blogs, is *ahem* lackluster.</p><h1>Do we want to build a community?</h1><p>Deeply Nested has always been a mix of posts about careers in software, technical details of software development itself, and short essays about random stuff I personally find interesting.</p><p>In the current job market, networking seems especially valuable, as well as building portfolios of work that can be shared online with prospective employers.  (Even if you have tons of professional experience, you can&#8217;t always publicly share the work you&#8217;ve done.)  Can Deeply Nested be a resource for helping people connect, personally and professionally?  Or is it better off remaining a periodic deep dive/diatribe/pontification?</p><p>Regardless of where we publish, we might also expand to a new medium, such as a podcast, that would be more amenable to conversation than a comments section.</p><p>Please do share your thoughts on all of the above, or whatever else comes to mind.  It&#8217;s great to see you again.</p>]]></content:encoded></item><item><title><![CDATA[All Models Are Wrong]]></title><description><![CDATA[But some are useful.]]></description><link>https://nested.substack.com/p/all-models-are-wrong</link><guid isPermaLink="false">https://nested.substack.com/p/all-models-are-wrong</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Mon, 19 Dec 2022 14:55:57 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/6eb6e0a6-dbc4-46b1-a58b-53af48f015d8_2832x2304.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Despite the virtues of Science, Technology, Engineering, and Mathematics (STEM), these fields have a dark side that we ought to shine more light on.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>STEM trains the mind to model the world precisely and mathematically.  We are tested and interviewed primarily on our understanding of  such models; sometimes, to such an extent that we lose sight of the realities they abstract.  The distinction between model and reality is nevertheless critical.  Choosing the right mental model in any situation&#8212;and understanding that all models are inherently imperfect, just as no map entirely captures the terrain it represents&#8212;is a more valuable skill than the ability to wield any particular model effectively.</p><blockquote><p>The universe is not only queerer than we suppose, but queerer than we can suppose.</p><p>&#8212;<a href="https://quoteinvestigator.com/2018/12/25/universe/">J. B. S. Haldane</a>, <em>Possible Worlds</em></p></blockquote><p>Models are tools, and like all tools, their utility is situational.  No single person has the luxury of unimpeded access to universal truth.  The best we can do is to leverage whichever models are most likely to help us achieve specific goals.</p><p>When someone else applies a different model than one we&#8217;ve accepted, and thus reaches different conclusions than our own, it&#8217;s easy to suppose that one of us must be wrong.  That disagreement can be frustrating.  <strong>It&#8217;s helpful to remember that we rarely really </strong><em><strong>know</strong></em><strong> anything, especially when deciding the best way to solve a problem.</strong>  The single most important trait distinguishing senior engineers from junior ones may well be the humility that comes from having been wrong many times before.</p><blockquote><p>All models are wrong, but some are useful.</p><p>&#8212;<a href="https://www.lacan.upc.edu/admoreWeb/2018/05/all-models-are-wrong-but-some-are-useful-george-e-p-box/">Attributed</a> to statistician George E. P. Box</p></blockquote><p>Engineers, at least, routinely deal in space-time trade-offs, margins of error, mechanical tolerances, etc., whereas many people naively believe pure mathematics to be some kind of absolute truth rather than, like all forms of study, a mere representation of our intrinsically flawed understanding of a fundamentally unknowable world.  Having &#8220;proven&#8221; something doesn&#8217;t mean it&#8217;s True with a capital T, only that we can&#8217;t see how it could <em>not</em> be true.  We are imperfect beings though, and often miss things.</p><blockquote><p>Kant, who was ten times more distant from Aristotle than we are from him, even held that nothing significant had been added to Aristotle&#8217;s views in the intervening two millennia.</p><p>In the last century, Aristotle&#8217;s reputation as a logician has undergone two remarkable reversals.  The rise of modern formal logic following the work of Frege and Russell brought with it a recognition of the many serious limitations of Aristotle&#8217;s logic; today, very few would try to maintain that it is adequate as a basis for understanding science, mathematics, or even everyday reasoning.</p><p>&#8212;Stanford Encyclopedia of Philosophy, <em><a href="https://plato.stanford.edu/entries/aristotle-logic/">Aristotle&#8217;s Logic</a></em></p></blockquote><p>None of this undercuts the usefulness or merit of scientific models.  The medical and technological advances of the last few centuries probably would have been impossible without the scientific revolution.  When you disagree with someone though&#8212;and can&#8217;t understand how they could be so boneheaded, especially in the face of so much evidence!&#8212;rather than thinking they must be stupid or evil, try to understand their mental model.  And have the humility to realize that it may be no less valid than your own.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Advent of Code]]></title><description><![CDATA[Here we go again!]]></description><link>https://nested.substack.com/p/advent-of-code</link><guid isPermaLink="false">https://nested.substack.com/p/advent-of-code</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Thu, 01 Dec 2022 22:44:04 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c44cd5d3-1632-41f7-9c91-1237187994d9_1825x1643.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://adventofcode.com/">Advent of Code 2022</a> began today.  In case you&#8217;re not familiar, Advent is an annual coding challenge comprising 25 puzzles, released one per day beginning on December 1st.  Participants don&#8217;t actually submit code, although they often <a href="https://github.com/jeffs/advent-of-code">share it online</a>.  Rather, they submit answers to simple questions that prove they&#8217;ve run code that solved the problem.  Because each participant is given their own input to process, you can&#8217;t just copy someone else&#8217;s answer.  (You could copy someone&#8217;s code and run it on your own input, but where&#8217;s the fun in that?)  Even though you&#8217;re solving a specific puzzle, you really have to tackle the more general problem in order to find your specific solution.</p><p>What I love about Advent is that it&#8217;s a good microcosm of real-world software development, which is something other coding challenges struggle (and generally fail) to model.  Aside from the lack of teammates and end users, completing Advent in real time (one challenge per day) takes you on a journey not dissimilar from most professional coding.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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>The first puzzle is logically easiest, yet in some ways also the hardest.  You have to decide what programming language you&#8217;ll use, how to lay out your repository, whether to publish your solutions online, and so on.  It really feels like you&#8217;re at the start of something.  The first day also gets you comfortable with the structure of the puzzles, each of which has two parts:  You have to complete the first part to unlock the second part, which asks you a new question about the same input.  For example, if Part 1 wants you to sum a list of numbers, Part 2 might ask for the maximum of those numbers.  So, right away, you&#8217;re almost forced to factor your code into three pieces: code that&#8217;s useful in both Part 1 and Part 2 (such as an input parser, or hard-coded input values if you&#8217;re a killjoy), code that&#8217;s useful only in Part 1, and code that&#8217;s useful only in Part 2.  What an ingenious way to create engineering tasks from simple riddles!</p><p>After the first day, the puzzles get gradually harder, often building on earlier puzzles in interesting ways.  Again, you&#8217;re forced to either refactor or copy/paste code so that you can reuse the logic from earlier solutions in new ones.  Sometimes you realize that the data model you used for one puzzle isn&#8217;t right for another, even when the two puzzles are semantically similar.  The multiple perspectives you gain on the problem space (artificial though it may be) force you to think deeply about it, and give you the incredibly satisfying feeling of <em>understanding</em> it.</p><p>Somewhere around December 20th, the difficulty skyrockets.  Puzzles go from something you can do before or after work, to something that takes all day, or even multiple days.  (Some years, I finish these on time; and some years, I don&#8217;t.)  Somehow, in three short weeks, you&#8217;ve gone from the ease and excitement of a greenfield project to the tension and stress of being up against a deadline.  Not the simple deadline of a traditional coding challenge, but a deadline for something you&#8217;re <em>invested</em> in.  Something you take pride in, and want to show off to other people.  You may not have &#8220;users,&#8221; but you do have peers, and you care what they think.  Not even hackathons inspire the sense of urgency that late-stage Advent does.  This may sound terrible, but no more so than the climax of a great story, when the hero faces the most powerful villain, and we truly doesn&#8217;t know whether the hero will win or lose.  It&#8217;s an exciting moment.</p><p>One other thing that Advent does well is to walk you through sample input for each puzzle, and give you the answer for that sample.  This gives you something to test your own code against, which is invaluable for debugging.  There&#8217;s a lesson to be learned here for actual engineering:  If you&#8217;re building something to work in the big messy nasty real world, make sure you can also run it on something small and clean and well understood.  It not only makes debugging easier, but is often critical to making debugging possible at all.</p><p>Kudos to Eric Wastl, the creator of Advent of Code.  If you&#8217;re participating this year, feel free to share observations and code links here.  And if you&#8217;ve never tried it before, but you love a good coding challenge, you&#8217;re in for a treat.  This really is one of the best.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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[Hearing Voices]]></title><description><![CDATA[New ideas are rarely great, and great ideas are rarely new.]]></description><link>https://nested.substack.com/p/hearing-voices</link><guid isPermaLink="false">https://nested.substack.com/p/hearing-voices</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Sat, 26 Nov 2022 00:10:56 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/14d59fd9-6b1a-4e9e-b4b0-e8a9bc795b86_2025x1481.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Good ideas can come from anywhere.  The best ones are usually the result of cross-pollination from seemingly disparate disciplines.   Before <a href="https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612">Design Patterns</a> were <em>de rigeur</em> knowledge for software engineers, they were an <a href="https://en.wikipedia.org/wiki/Pattern_(architecture)">architectural</a> tool.  <a href="https://biomimicry.org/about/">Biomimicry</a> lets us apply proven, evolved solutions in design and engineering.  Art imitates life, and vice versa.  <strong>New ideas are rarely great, and great ideas are rarely new.</strong></p><p>There are some obvious places to look for new-to-you ideas.  Sabbaticals, newsletters, or even chatting about work in a <a href="https://baradvisor.com/bars-and-networking-startuplife/">social context</a> can plant established ideas from one field in another where they may bloom afresh.  Both sides of this pollination can be extremely satisfying:  Finding a way to apply the wisdom of others in your own work, or seeing the gleam in someone&#8217;s eye when you explain what to you has long since become prosaic.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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>Ironically, the least obvious place that new ideas originate is from within your own organization, from folks ideating beyond their formal purview.  (Flamin&#8217; Hot Cheetos were <a href="https://www.latimes.com/business/story/2021-05-16/flamin-hot-cheetos-richard-montanez">not actually invented by a janitor</a>, but wouldn&#8217;t it be great if they had been?)  If, like most development teams, you use an issue tracking system, one of the best things you can do is to make sure <em>everyone</em> at the company can create new tickets in an incoming Triage column (assuming a <a href="https://kanbanize.com/kanban-resources">Kanban</a>-like dashboard in which columns represent stages of work).  Periodically (say, once a week), folks with the authority to accept work on behalf of the team should go through any new arrivals in Triage, and respond to them thoughtfully, either adding the issue to the team&#8217;s backlog, or explaining why that&#8217;s not being done at this time.</p><blockquote><p>If I had asked people what they wanted, they would have said faster horses.</p><p>&#8212;unknown, but <a href="https://hbr.org/2011/08/henry-ford-never-said-the-fast">attributed</a> to Henry Ford</p></blockquote><p>One of the saddest mistakes I see folks make with such &#8220;suggestion box&#8221; Triage columns is to delete or archive the tickets.  Keep them!  Keep them forever.  You can certainly create a separate column&#8212;called Triaged, perhaps&#8212;but deleting suggestions is unnecessary, and sends the message that you do not value people&#8217;s ideas.  Moreover, it implies that you are kiboshing their suggestion forever, which you&#8217;ll admit is an awfully long time.  As long as you keep the triaged tickets around:</p><ul><li><p>You can refer back to them for the rationale of why an idea was not pursued.  This is surprising valuable.  All too often, &#8220;new&#8221; product/eng ideas are greeted by a few old-timers who vaguely recall a similar idea already having been rejected, but cannot recall any compelling reason why</p></li><li><p>Suggestions that are rejected for lack of resources to implement them can be revisited later.  Some make great intern projects, or chances for new hires to get their feet wet.  Often, when an idea rattles around the back of the group&#8217;s head long enough, they realize it wouldn&#8217;t be all that difficult after all.</p></li><li><p>Team members who care deeply about a rejected idea can move tickets from Triaged back to Triage, so that they will be reconsidered.  You can cap the frequency of such reversion; say, to once or twice a year.  If somebody cares that much about it, maybe it really is worth reconsideration.</p></li><li><p>The poobahs who accept or reject work from the Triage column may choose to set aside one day each year for reconsidering rejected tickets.  As times and people change, so do priorities and opinions.  Think of it as the <a href="https://westwing.fandom.com/wiki/Big_Block_of_Cheese_Day">Big Block of Cheese Day</a> from The West Wing.  Of all the seemingly unworkable ideas, some will turn out to be like the ice-shipping scheme that earns Richard Pryor an inadvertent  fortune in Brewster&#8217;s Millions.</p><div id="youtube2-svKq044qrYU" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;svKq044qrYU&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/svKq044qrYU?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div></li></ul><p>While not every idea is worth pursuing, every idea that someone took the time to document matters to <em>somebody</em>, and should be treated accordingly.  Sincerely welcoming ideas from all directions can help you find diamonds in the rough, and humility can help you recognize those diamonds even if they aren&#8217;t obvious at first sight.  Be open, be thoughtful, and remember that sometimes, long shots pay off.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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[Made of People]]></title><description><![CDATA[In tough times, it's important to remember what&#8212;and who&#8212;matter most.]]></description><link>https://nested.substack.com/p/made-of-people</link><guid isPermaLink="false">https://nested.substack.com/p/made-of-people</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 18 Nov 2022 23:55:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/h_600,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.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_!s6Uf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s6Uf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg 424w, https://substackcdn.com/image/fetch/$s_!s6Uf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg 848w, https://substackcdn.com/image/fetch/$s_!s6Uf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!s6Uf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s6Uf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg" width="1456" height="978" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:978,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3057615,&quot;alt&quot;:&quot;Three groups of about ten men apiece, all dressed in white trousers and T-shirts, form standing human pyramids.  The man at the top of each pyramid holds a flag in the air with his right hand, with his left hand placed on his hip.&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="Three groups of about ten men apiece, all dressed in white trousers and T-shirts, form standing human pyramids.  The man at the top of each pyramid holds a flag in the air with his right hand, with his left hand placed on his hip." title="Three groups of about ten men apiece, all dressed in white trousers and T-shirts, form standing human pyramids.  The man at the top of each pyramid holds a flag in the air with his right hand, with his left hand placed on his hip." srcset="https://substackcdn.com/image/fetch/$s_!s6Uf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg 424w, https://substackcdn.com/image/fetch/$s_!s6Uf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg 848w, https://substackcdn.com/image/fetch/$s_!s6Uf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!s6Uf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F398988c8-2ec1-4e4a-a840-c79f645f785f_2112x1419.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">Vintage photograph of Victorian british army, Gymnastic team, Living pyramids display by the training staff at Aldershot gymnasium. 1890s.</figcaption></figure></div><p>The past few weeks have entailed brutal layoffs by well-known tech companies.  The treatment of Twitter&#8217;s staff has been especially bizarre, and speculation continues about whether (and how long) the company can continue operation having decimated<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> its headcount.</p><blockquote><p>Email from Elon to the engineering team: "Anyone who can actually write software, please report to the 10th floor at 2pm today. Before doing so, please email me a bullet point summary of what your code commits have achieved in the past 6 months."  Elon Musk is also asking for up 10 screenshots of the "most salient lines of code" from Twitter engineers. . . . Yesterday, Twitter told employees the offices were closed and badge access was suspended until Monday. Employees are extremely confused.<br><br>&#8212;<a href="https://twitter.com/ZoeSchiffer/status/1593652897236934656">Zo&#235; Schiffer</a>, Managing Editor at <a href="https://www.platformer.news/">Platformer</a></p></blockquote><div class="twitter-embed" data-attrs="{&quot;url&quot;:&quot;https://twitter.com/sheonhan/status/1588029253496414208?s=20&amp;t=5br3tpxk7YOJKScswQJMrQ&quot;,&quot;full_text&quot;:&quot;My employee login <span class=\&quot;tweet-fake-link\&quot;>@Twitter</span> vs. Lettuce\nLet's goooooooooo &quot;,&quot;username&quot;:&quot;sheonhan&quot;,&quot;name&quot;:&quot;Sheon Han&quot;,&quot;profile_image_url&quot;:&quot;&quot;,&quot;date&quot;:&quot;Thu Nov 03 04:44:12 +0000 2022&quot;,&quot;photos&quot;:[{&quot;img_url&quot;:&quot;https://pbs.substack.com/media/FgnQBzFVIAEox-K.jpg&quot;,&quot;link_url&quot;:&quot;https://t.co/bgkZiLmH8T&quot;,&quot;alt_text&quot;:null}],&quot;quoted_tweet&quot;:{},&quot;reply_count&quot;:0,&quot;retweet_count&quot;:3912,&quot;like_count&quot;:49613,&quot;impression_count&quot;:0,&quot;expanded_url&quot;:{},&quot;video_url&quot;:null,&quot;belowTheFold&quot;:false}" data-component-name="Twitter2ToDOM"></div><p>I once worked at a company where employees were treated more like code to be debugged, or perhaps feral dogs to be domesticated, than professionals to be inspired.  Behavior that was not &#8220;<a href="https://www.cnn.com/2022/11/17/tech/twitter-employees-ultimatum-deadline">extremely hardcore</a>&#8221; (as Twitter&#8217;s new owner puts it), or was seen as disloyal, could severely limit one&#8217;s chances of career advancement.  Employees were seen more as potential liabilities than vital assets.  A wise coworker observed to me that the company&#8217;s most valuable resources left at the end of every day, and management didn&#8217;t even realize it.</p><p>One asinine speech by a senior manager (which I did not witness first hand) implied that product quality should be deprioritized, because maintaining the high bar (and correspondingly excellent repuation) that this company had earned across the industry was costly.  Not prohibitively so; merely an expense that could be reduced, thus netting more money (in the short term).  When someone objected, asking semi-rhetorically whether we really wanted to reduce our product from a (metaphorical) luxury car to a jalopy, the manager replied: &#8220;You can make a lot of money selling jalopies.&#8221;</p><p>Another coworker once told me something I didn&#8217;t understand at the time, but that rings truer and truer to me:  <strong>Companies are made of people.</strong>  They&#8217;re also made of paperwork and legal entities and sometimes brick and mortar, and the people who start a company aren&#8217;t always the same ones who make it tick in later years, but the people are always the parts that matter most.  People run the company, and in many ways, those who control the company exercise control over the lives of other people.  That&#8217;s a responsibility that some executives don&#8217;t take seriously enough.</p><p>This is a tough time for tech workers, but if you&#8217;re a junior engineer trying to enter industry even as hiring is slowing and the market is flooded with laid-off competition, or you&#8217;re a senior who&#8217;s back on the market after decades of stability, remember that opportunities are still out there, and some company&#8212;some <em>people</em>&#8212;really need you.  You just may not know them yet.</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>Nota bene: <a href="https://www.abc.net.au/news/2019-09-03/decimate-does-not-mean-to-kill-one-in-every-10/11459980">Decimate does not mean to kill one in every 10</a></p></div></div>]]></content:encoded></item><item><title><![CDATA[Floppy Capacitors ]]></title><description><![CDATA[Let's pay homage to some weird results of Materials Science, and the awe-inspiring applications to which engineers have put them.]]></description><link>https://nested.substack.com/p/floppy-capacitors</link><guid isPermaLink="false">https://nested.substack.com/p/floppy-capacitors</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Thu, 10 Nov 2022 20:26:33 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/30981749-7d1e-4422-a471-4b9782438268_2309x1299.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The variety of borderline magical materials now commonplace in even commoditized technology is frankly stupefying. The most exotic behavior, comprehensible only through the wizardry of physics and chemistry and the outr&#233; runes of advanced mathematics, is now taken completely for granted. Let's pay a moment of homage to some weird results of Materials Science, and the awe-inspiring applications to which engineers have put them.</p><p><strong>Piezoelectric</strong> materials create electricity when you squeeze them. They're like physical functions that transform pressure into voltage. We use them in doorbells and microphones, and lots of other stuff. There&#8217;s also a reverse piezoelectric effect whereby some objects, when exposed to an electric field, change their shape or size. Reverse piezoelectrics are used in ultrasound: A rapidly oscillating sheet of reverse piezoelectric ceramic acts as a &#8220;speaker&#8221; to generate ultrasound waves. It is <em>weird</em> that we can make materials dance for us by subjecting them to fields of invisible energy.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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><strong>Thermoelectric</strong> materials turn temperature differentials into electricity (the Seebeck effect) or vice versa (the Peltier effect). If you're in a warm room in cold weather, and you stick one end of a thermoelectric pole out the window, you get free electricity (except insofar as you're paying to heat that room in the first place). In practice, we use thermoelectrics to build heat pumps for refrigeration; but research is underway toward reclaiming energy from otherwise wasted heat.</p><p><strong>Semiconductors</strong> either prevent or allow the flow of electricity, depending on their environment. Most materials are either electrical insulators (like the rubber sheath of your laptop&#8217;s power cable) or conductors (like the metal wire inside that sheath).  Semiconductors are like insulators, except that when we put them in certain electric fields, they become conductors. Computer microprocessors use semiconductors in billions of tiny switches, whereby the state of each switch (either insulating or conducting) controls other switches, and so on, almost the way billions of neurons in the human brain interact to produce higher order phenomena like thought.</p><p>Effects so simple they might be mistaken for mere novelties can be combined to create awe-inspiring technology. Consider the mind-blowing example of floppy capacitors. (Floppy isn't a technical term, but an accurate one.)  Most modern electronics are made deliberately rigid, so that their size, shape, and behavior are consistent even if you shake them. (If you're old enough to remember portable CD players, you&#8217;ll appreciate the fact that modern music players don't skip as you jog.) But it is possible to make floppy electronics that are easily deformed by acceleration. In particular, the electrical properties of simple devices called <em>capacitors</em> change as they're deformed. You know the visceral feeling you get when an elevator starts moving or comes to a stop? Floppy capacitors &#8220;feel&#8221; it too.</p><p>The change in floppy capacitors&#8217; behavior as they get jerked around has been leveraged to create <em>accelerometers</em>. When your smartwatch tells you it's time to get off your duff and stand up for a minute, your watch is using a built-in accelerometer to tell when you last stood up or sat down.</p><p>Accelerometers are key components of automobile airbags. Microcontrollers monitor the output of accelerometers, checking for sudden deceleration, and constantly sending a single bit of information (either true or false) to the airbag deployment system: Are we crashing right now? The United States Department of Transportation <a href="https://crashstats.nhtsa.dot.gov/Api/Public/ViewPublication/812967.pdf">estimates</a> that over a recent 30-year period, airbags saved the lives of over 50,000 people. All thanks to the magnificent insight that floppy electronics could be more than a novelty. (Inventor Allen Breed earned his degree in Mechanical Engineering <a href="https://lemelson.mit.edu/resources/allen-breed">after</a> patenting the modern airbag.)</p><p>There&#8217;s no telling what we'll discover next&#8212;what bizarre properties of matter and energy, or what novel uses we'll put them to. Whatever they may be, engineers will be the people who turn the possible into the practical, and the interesting into the invaluable.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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[Pasta]]></title><description><![CDATA[Abstractions should be translucent, not opaque.]]></description><link>https://nested.substack.com/p/pasta</link><guid isPermaLink="false">https://nested.substack.com/p/pasta</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 04 Nov 2022 23:01:12 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/18923509-d459-493d-8218-9508b572f6ed_851x601.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most software abstractions are deliberately opaque.  Let&#8217;s consider making them, if not transparent, at least translucent.</p><h3>Spaghetti</h3><p>The term &#8220;computer program&#8221; is misleading, because it implies order.  Computer programs are lists of instructions&#8212;things for the computer to do&#8212;that aren&#8217;t necessarily executed in list order.  Computers support &#8220;jump&#8221; (or &#8220;branch&#8221; or &#8220;go to&#8221;) instructions that transfer control to different parts of the program, sometimes depending on factors that can&#8217;t be known in advance.  Programs that are hard to read because of all the jumping around are called &#8220;spaghetti code.&#8221;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u3MN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u3MN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg 424w, https://substackcdn.com/image/fetch/$s_!u3MN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg 848w, https://substackcdn.com/image/fetch/$s_!u3MN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!u3MN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u3MN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg" width="1456" height="547" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:547,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:99443,&quot;alt&quot;:&quot;One cartoon dog noses a meatball toward another during a romantic spaghetti dinner.&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="One cartoon dog noses a meatball toward another during a romantic spaghetti dinner." title="One cartoon dog noses a meatball toward another during a romantic spaghetti dinner." srcset="https://substackcdn.com/image/fetch/$s_!u3MN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg 424w, https://substackcdn.com/image/fetch/$s_!u3MN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg 848w, https://substackcdn.com/image/fetch/$s_!u3MN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!u3MN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F22f73772-039e-48c9-ac8f-bc9e8678e35d_1600x601.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">One imagines Tramp here as a software engineer, and Lady as the reviewer on whom he&#8217;s trying to pawn his spaghetti.  Ain&#8217;t nobody got time for that.  Image via: https://intelligentcollector.com/lady-and-the-tramp/</figcaption></figure></div><p>You still see <code>goto</code> in low-level C code sometimes for resource cleanup.  For example,  a function that tries to copy a file might do the following:</p><ol><li><p>Initialize a &#8220;success&#8221; variable with the value false.</p></li><li><p>Try to open the old file for reading.</p></li><li><p>If (2) failed, go to (10).</p></li><li><p>Try to open the new file for writing.</p></li><li><p>If (4) failed, go to (9).</p></li><li><p>Try reading the contents of the old file, and writing them to the new file.</p></li><li><p>If (6) succeeded, assign the success variable the value &#8220;true.&#8221;</p></li><li><p>Close the new file.</p></li><li><p>Close the old file.</p></li><li><p>Return the success variable&#8217;s value to the caller.</p></li></ol><p>You&#8217;ll also see a glorified version of this in garbage collected languages, using <code>defer</code> statements or <code>with</code> or <code>try</code> blocks instead of <code>goto</code>.  To do any better than per-call-site resource management, you need either C++/Rust style <a href="https://en.cppreference.com/w/cpp/language/destructor">destructors</a>, or a framework that supports <a href="https://reactjs.org/docs/state-and-lifecycle.html">lifecycle</a> callbacks (methods or hooks).</p><p>Since the 1950s (and arguably culminating with Dijkstra&#8217;s 1968 opinion piece <em><a href="https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf">Go To Statement Considered Harmful</a></em>), <code>goto</code> statements have been considered gauche.  In polite company, jumps are used only as part of common patterns like loops and function calls, collectively call <em>structured programming</em>.</p><p>When reading well-structured code, you can often skip over details.  For example, if you see a function call like factorial(5), you probably don&#8217;t have to look at the implementation of the factorial function, because you know what it&#8217;s meant to do.  That kind of abstraction is critically important for software (and development teams) to scale, because it&#8217;s not practical for someone reading code to have to follow all the jumps.  There&#8217;s an equally important but underappreciated caveat to this  kind of structured programming though:  <strong>Abstraction should never prevent the reader from following the jumps if they want to.</strong></p><p>It&#8217;s in vogue now to use Dependency Injection (DI), message buses/brokers/queues, and other heavyweight techniques to decouple various parts of complex systems.  Tragically, most of these systems throw the baby out with the bathwater:  They reason that because you ideally shouldn&#8217;t have to look past an abstraction, you should be actively <em>prevented </em>from doing so; or at least, supporting removal of the abstraction is not seen as a priority.  Such thinking ignores the fact that abstractions are inherently imperfect.  We won&#8217;t belabor that point here, because Joel Spolsky has already done a great job coining the <a href="https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/">The Law of Leaky Abstractions</a>.</p><h3>Lasagna</h3><p>Sometimes you see software structured into <em>layers, </em>or <em>tiers</em> if they&#8217;re separate programs (such as a database, microservice, and web-based user interface).  This kind of structure is occasionally called <em>lasagna</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!abUO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!abUO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png 424w, https://substackcdn.com/image/fetch/$s_!abUO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png 848w, https://substackcdn.com/image/fetch/$s_!abUO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png 1272w, https://substackcdn.com/image/fetch/$s_!abUO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!abUO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png" width="1456" height="619" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:619,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:993893,&quot;alt&quot;:&quot;Photograph of a slice of lasagna with three layers of filling, labeled, from top to bottom: User Interface, Business Logic, and Data Storage.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Photograph of a slice of lasagna with three layers of filling, labeled, from top to bottom: User Interface, Business Logic, and Data Storage." title="Photograph of a slice of lasagna with three layers of filling, labeled, from top to bottom: User Interface, Business Logic, and Data Storage." srcset="https://substackcdn.com/image/fetch/$s_!abUO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png 424w, https://substackcdn.com/image/fetch/$s_!abUO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png 848w, https://substackcdn.com/image/fetch/$s_!abUO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.png 1272w, https://substackcdn.com/image/fetch/$s_!abUO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F148085b8-efca-45e3-8850-2a4f809d0b37_1552x660.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 you see a Data Access Object (DAO) or other layer-oriented abstraction, make sure you can understand how each layer is actually implemented.  At least once, try following a request all the way down the call stack, and the response all the way back up.  If you are building such a system, be as transparent (or translucent) as you can about it, so that your layers are easy to reason about when debugging, or assessing cost or performance.</p><h3>Ravioli</h3><p>Instead of (or in addition to) layers, software is sometimes structured as bundles of state called <em>objects</em>.  These are objects in the sense of Object Oriented Programming (OOP), and while they are generally implemented by objects in the sense we discussed in <a href="https://nested.substack.com/p/variables">Variables</a>, they&#8217;re a more abstract idea.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Op2F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Op2F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png 424w, https://substackcdn.com/image/fetch/$s_!Op2F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png 848w, https://substackcdn.com/image/fetch/$s_!Op2F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png 1272w, https://substackcdn.com/image/fetch/$s_!Op2F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Op2F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png" width="1456" height="875" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:875,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1102235,&quot;alt&quot;:&quot;A photo of a bowl of ravioli, accompanied by two labels: \&quot;Private data\&quot; and \&quot;Public methods.\&quot;  The \&quot;Private data\&quot; label has arrows pointing to the middle parts of several ravioli, and the \&quot;Public methods\&quot; label has arrows pointing to the ruffled edges of those ravioli.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A photo of a bowl of ravioli, accompanied by two labels: &quot;Private data&quot; and &quot;Public methods.&quot;  The &quot;Private data&quot; label has arrows pointing to the middle parts of several ravioli, and the &quot;Public methods&quot; label has arrows pointing to the ruffled edges of those ravioli." title="A photo of a bowl of ravioli, accompanied by two labels: &quot;Private data&quot; and &quot;Public methods.&quot;  The &quot;Private data&quot; label has arrows pointing to the middle parts of several ravioli, and the &quot;Public methods&quot; label has arrows pointing to the ruffled edges of those ravioli." srcset="https://substackcdn.com/image/fetch/$s_!Op2F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png 424w, https://substackcdn.com/image/fetch/$s_!Op2F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png 848w, https://substackcdn.com/image/fetch/$s_!Op2F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png 1272w, https://substackcdn.com/image/fetch/$s_!Op2F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5a6473a3-bbdd-4a5a-8f48-ccecec6cdd83_1554x934.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The same principle applies to objects (in the OOP sense) as to layers:  Don&#8217;t presume that an abstract interface is the only thing your clients should have access to.  If you can reasonably let them know how that interface is implemented, you should do so.  If you&#8217;re using someone else&#8217;s objects (or classes), take a peek at the source code (if available) and get a sense of how they actually work.  Incidentally: Plain Old Data (POD), as opposed to fancy objects with properties and methods and access control, are underrated.</p><p>There&#8217;s a fallacy gaining traction these days, along the lines of:  &#8220;Never expose any implementation details, because if you do then someone will come to rely on them, and then you&#8217;ll never be able to change your implementation.&#8221;   All caller/callee relationships are subject to change.  Being a service provider doesn&#8217;t make you a serf. Your clients are not your enemies.  (If your clients <em>are</em> actively hostile, drop them.)  The best way to provide value is to clearly distinguish aspects of your system that will remain stable from those that may not, letting your customers lift the hood and see how your machinery works.  The possibility that they&#8217;ll somehow void the warranty isn&#8217;t a good reason to keep them in the dark.</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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[Bug Extinction]]></title><description><![CDATA[There's too much hate in the world. But you know we can all hate together? Bugs.]]></description><link>https://nested.substack.com/p/bug-extinction</link><guid isPermaLink="false">https://nested.substack.com/p/bug-extinction</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 28 Oct 2022 22:04:12 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/cb4dde62-df5c-49c9-b7c7-e491e2aa7b02_2121x1414.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Bugs are bad</h2><p>There is surely too much hate in the world.  But you know we can all hate together?  <strong>Bugs.  </strong>Estimates of the annual worldwide cost of software defects <a href="https://gitential.com/gitentials-guide-to-the-cost-of-fixing-bugs/#:~:text=Bugs%20are%20our%20greatest%20threat%20in%20software%20development,legacy%20systems%2C%20and%20software%20failures%20in%20operational%20systems.">vary</a>, but are generally on the order of <a href="https://www.overops.com/blog/how-much-is-poor-quality-software-costing-you/#:~:text=These%20are%20the%20things%20that%20cause%20massive%20disruptions,roughly%2010%25%20of%20the%20country%E2%80%99s%20GDP%20last%20year.">trillions</a> of US dollars.  The work of finding and fixing bugs is <a href="https://web.p.ebscohost.com/abstract?direct=true&amp;profile=ehost&amp;scope=site&amp;authtype=crawler&amp;jrnl=15220540&amp;AN=113530684&amp;h=p7e%2fbKFDygY2TVxLwig2S3dxFOAtcDCtnnyK9b%2f%2ffAcHPtpGkTEHpkzmpdKXbCtFJu1Q51vKNFw1E6Aa7pJZ1A%3d%3d&amp;crl=f&amp;resultNs=AdminWebAuth&amp;resultLocal=ErrCrlNotAuth&amp;crlhashurl=login.aspx%3fdirect%3dtrue%26profile%3dehost%26scope%3dsite%26authtype%3dcrawler%26jrnl%3d15220540%26AN%3d113530684">estimated </a>to comprise more than 60% of total software development costs.  Formal studies probably underestimate the real cost by a wide margin, because they focus on quantities that can be accounted directly.</p><p>Undergraduate engineering coursework includes study of disasters that have resulted in loss of life, including watching video of the Hindenburg and Challenger explosions.  Any pecuniary value assigned to such tragedies would be grotesquely inadequate.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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><em>&#129700; Computer science and bootcamp students are generally not made to study past engineering disasters; yet we continue hiring these folks into engineering roles, despite (or perhaps explaining) the fact that more and more <a href="https://medium.com/swlh/when-software-kills-ab6f48a15825">people die because of bugs</a>.  (I&#8217;m not blaming the students, or even the schools.  I&#8217;m blaming industry for assigning engineering work to people who were not formally trained as engineers.)</em></p><p>Ripple effects that are hard to measure may in fact be dominant.  For want of a bug fix, the account was lost; for want of revenue, earnings were missed; for want of investor confidence, equity was devalued; for want of incentive stock options, talent couldn&#8217;t be hired or retained; and for want of an effective team, the company was uncompetitive.  The link between product quality and a company&#8217;s ability to survive and thrive should be obvious, but it&#8217;s hard to quantify, much less prove.</p><h2>Let&#8217;s end them</h2><p>Humanity has already eradicated (or nearly so) multiple parasites, including smallpox and polio, and (notwithstanding the anti-vax movement) we&#8217;re getting better and better at it.  In fact, we&#8217;re so good at driving species to extinction that we frequently do so accidentally, primarily by killing organisms directly&#8212;what the American Museum of Natural History euphemistically calls <a href="https://www.amnh.org/explore/ology/biodiversity/going-going-gone/what-causes-extinction">&#8220;overharvesting&#8221;</a>&#8212;or by destroying habitats.</p><p>Software bugs are no less susceptible to extinction than living creatures, and in principle have the same vulnerabilities.</p><h3>Loss of habitat</h3><p>The easiest place for bugs to hide is anywhere you have <strong>multiple sources of truth</strong>.  Caches are probably the worst offenders.  Caching data that may change over time is obviously a deal with the devil, as you choose to accept the wrong answer now rather than the right answer later.</p><p>Suppose a video game saves state on a server; but also caches it in local storage so that the user can start playing right away when they open the game, rather than waiting for state to be retrieved from the server.  If the user ever plays on a second device, and then comes back to the first device, the local storage may be out of date.  Any gameplay based on that cached state may conflict with changes from the second device.  Oops, your player&#8217;s health wasn&#8217;t supposed to be that high, because they took damage while playing on the second machine.  Reconciling differences like these can be tricky, and is a common source of bugs.</p><p>Conflicting truths can also come from parts of a codebase that nominally implement the same logic.  Suppose we use two separate routines to sort people by height, and the first routine orders Alice, Bob, Charlie, and Dana thus:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sjdD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sjdD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png 424w, https://substackcdn.com/image/fetch/$s_!sjdD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png 848w, https://substackcdn.com/image/fetch/$s_!sjdD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png 1272w, https://substackcdn.com/image/fetch/$s_!sjdD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sjdD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png" width="440" height="330" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:960,&quot;resizeWidth&quot;:440,&quot;bytes&quot;:85455,&quot;alt&quot;:&quot;Silhouettes of four different people arranged by height, labeled Alice, Bob, Charlie, and Dana.  Bob and Charlie are the same height.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Silhouettes of four different people arranged by height, labeled Alice, Bob, Charlie, and Dana.  Bob and Charlie are the same height." title="Silhouettes of four different people arranged by height, labeled Alice, Bob, Charlie, and Dana.  Bob and Charlie are the same height." srcset="https://substackcdn.com/image/fetch/$s_!sjdD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png 424w, https://substackcdn.com/image/fetch/$s_!sjdD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png 848w, https://substackcdn.com/image/fetch/$s_!sjdD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png 1272w, https://substackcdn.com/image/fetch/$s_!sjdD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45bc9828-6610-4786-abbb-5f84f9391a11_960x720.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The second routine produces a different result:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wqwh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wqwh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png 424w, https://substackcdn.com/image/fetch/$s_!wqwh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png 848w, https://substackcdn.com/image/fetch/$s_!wqwh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png 1272w, https://substackcdn.com/image/fetch/$s_!wqwh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wqwh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png" width="460" height="345" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:960,&quot;resizeWidth&quot;:460,&quot;bytes&quot;:84598,&quot;alt&quot;:&quot;The same four labeled silhouettes as in the previous image; but this time, Charlie comes before Bob.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The same four labeled silhouettes as in the previous image; but this time, Charlie comes before Bob." title="The same four labeled silhouettes as in the previous image; but this time, Charlie comes before Bob." srcset="https://substackcdn.com/image/fetch/$s_!wqwh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png 424w, https://substackcdn.com/image/fetch/$s_!wqwh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png 848w, https://substackcdn.com/image/fetch/$s_!wqwh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.png 1272w, https://substackcdn.com/image/fetch/$s_!wqwh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0e2004d7-f497-4c13-8b3e-dd3260cfd5e8_960x720.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>Both results are correct, because Bob and Charlie happen to be the same height.  Yet such gratuitously different results can make software misbehave.  We discussed a similar issue in <a href="https://nested.substack.com/p/traversal-order">Traversal Order</a>.</p><p>The ideal solution to bugs like these is to build systems that are <a href="http://wiki.c2.com/?CorrectByConstruction">correct by construction</a>.  Having a <a href="https://www.mulesoft.com/resources/esb/what-is-single-source-of-truth-ssot">Single Source of Truth (SSOT)</a> guarantees that discrepancies cannot arise.  This isn&#8217;t usually hard to do, but it requires a certain mindset to even recognize the problem:  Redundant code and data storage are potential bug nests.</p><blockquote><p>Never go to sea with two chronometers; take one or three.<br><br>&#8212;via Fred Brooks, <em>The Mythical Man Month</em></p></blockquote><h3>&#8220;Overharvesting&#8221;</h3><p>This may sound obvious, but another critical step toward eradicating bugs is to find and fix them.  This doesn&#8217;t always happen, mainly because of perceived trade-offs.</p><p>Whether to prioritize bug fixes (or other quality measures) over other work is a business decision:  The upside of a new feature may outweigh the perceived potential cost of quality issues.  However, decision makers often mistakenly think bugs are stand-alone things.  That&#8217;s like assuming the cockroach you just saw skitter across the restaurant floor lives alone.  Bugs live in colonies, and every one you let live is bound to spawn others.</p><blockquote><p>&#8220;The only good bug is a dead bug.&#8221;<br><br>&#8212;Edward Neumeier, <em><a href="https://www.youtube.com/watch?v=2mvmHwCxw5A">Starship Troopers</a></em></p></blockquote><p>Question #5 on <a href="https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/">The Joel Test</a> is: Do you fix bugs before writing new code?  That&#8217;s a pretty good litmus test for distinguishing great teams from mediocre ones.  If we really want to end bugs, it&#8217;s not enough to &#8220;harvest&#8221; the obvious, urgent problems.  We have to <em>overharvest</em> if we&#8217;re to avoid their insidious second-order effects; essentially, to stop them from multiplying.</p><p>Eliminating bugs entirely is an ambitious goal, but may be achievable.  The first step is to recognize their real cost to both individual initiatives and the world at large, which is frankly staggering.  The second step is to destroy (or at least stop constructing) places for bugs to hide; mainly by identifying and protecting SSOTs, and otherwise prioritizing code that is correct by construction.  The third step is to hunt and kill them without ruth or delay.  Finally, we must prioritize quality in sales and marketing.  Customers demand lots of different things, from product features to favorable contract terms to white glove treatment from account managers; but collectively, as an industry, we have to make quality the focus of our shared conversation.</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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[Synergy]]></title><description><![CDATA[The other S word]]></description><link>https://nested.substack.com/p/synergy</link><guid isPermaLink="false">https://nested.substack.com/p/synergy</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 21 Oct 2022 21:32:18 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7219d558-cd01-4606-aee2-001d40ed620e_2868x1912.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The word <em>synergy</em> has become so clich&#233;d that it&#8217;s mostly a punchline.  There are probably two reasons for that:</p><ol><li><p>Lousy managers use the word to justify reorgs and layoffs.</p></li><li><p>People like to laugh at words (and anything else) they don&#8217;t understand.</p></li></ol><p>There&#8217;s plenty of jargon we can mock.  The phrases &#8220;best practices&#8221; and &#8220;think outside the box&#8221; come to mind.  But it would be a shame to lose the word synergy, which represents such an important concept.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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><div id="youtube2-aocZo3oeNxw" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;aocZo3oeNxw&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/aocZo3oeNxw?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>The idea of synergy is that when you get the right people together, they can collectively accomplish more than they could separately.  We&#8217;re not talking about the happenstance benefits of serendipitous confluence; we&#8217;re talking about deliberate, orchestrated commingling of skills and perspectives, like mashing up two melodies to create surprising and wonderful harmonies.</p><blockquote><p><strong>syn&#183;er&#183;gy</strong> (s&#301;n&#8217;&#601;r-j&#275;)<br><em>n. pl.</em> <strong>syn&#183;er&#183;gies</strong></p><ol><li><p>The interaction of two or more agents or forces so that their combined effect is greater than the sum of their individual effects.</p></li><li><p>Cooperative interaction among groups, especially among the acquired subsidiaries or merged parts of a corporation, that creates an enhanced combined effect.</p></li></ol><p>&#8212;<a href="https://www.ahdictionary.com/word/search.html?q=synergy">American Heritage Dictionary</a></p></blockquote><p>Examples abound in both nature and industry.  The most delicious cup of coffee comprises chemicals that taste <a href="https://www.quirkyscience.com/coffee-aroma/">disgusting</a> on their own (or if not properly balanced).  We&#8217;ve all met couples that seem like <em>either</em> would be miserable, but <em>both</em> are a delight.  Synergy can make the worthless worthwhile, the good great, and the great transcendant.</p><blockquote><p>There&#8217;s no such thing as a free lunch.<br><br>&#8212;Someone mistaken.  Paul Mallon, <a href="https://www.wordorigins.org/big-list-entries/free-lunch">maybe</a>.</p></blockquote><p>The most obvious examples are economies of scale.  If you&#8217;re building a web service that needs a server, and I&#8217;m building an unrelated web service that also needs a server, maybe we can get together and not have to pay for two separate servers.  If there are significant per-server costs, and using a single multi-tenant server won&#8217;t compromise security or performance, we might be able to save a lot of money and hassle by sharing.  That&#8217;s synergy in its most mundane form.</p><p>If you&#8217;ll bear with me through a real example that&#8217;s a good metaphor for how surprising synergy can be, I&#8217;d like to tell you about a cool technology used in the manufacture of high-end electronic devices.  Microprocessors are manufactured in a fascinating way.  They&#8217;re designed as a set of horizontal <em>layers;</em> that is, 2D slices of the physical 3D object that will eventually be sold to you as the single most expensive part of your phone or desktop computer.  Each layer is made of a different material.  Professional <em>mask designers</em> decide where, within each layer, the material should go, and where it should not.</p><p>At the <em>fab </em>(where processors are &#8220;fabricated&#8221;<em>)</em>, silicon wafers are laid out flat, and covered with the mask for the lowest layer.  Particles of the material for that layer (sometimes obtained by heating a chunk of the material until it evaporates) are released into the air above the wafers, slowly settling onto them.  The mask is then removed, leaving the material on the wafer only in places where the mask had holes.  The process is called <em><a href="https://news.samsung.com/global/eight-major-steps-to-semiconductor-fabrication-part-6-the-addition-of-electrical-properties">deposition</a>.</em>  It&#8217;s repeated for each layer.  Modern processors have dozens of layers.</p><p>The <em>feature size</em> of a semiconductor fabrication process is the smallest distance we can realistically control.  It&#8217;s some fraction of the width of a single transistor.  The feature size of current generation processors is about 5 nm; that is, 0.0000005% of a meter.  That&#8217;s so small that the holes in the masks have to be cut with laser beams.  In fact, it&#8217;s even smaller than we can cut with a laser beam, because a laser with a wavelength that short (and thus a high frequency) would be too powerful for practical use.  So, how do we cut such tiny mask holes?  We use <em>two </em>lasers whose waves are almost diametrically out of phase with each other, such that they mostly cancel each other out, much as noise cancelling headphones cancel ambient sound.  But they don&#8217;t  <em>completely</em> cancel each other out; and the little bit of difference is so small that we can use it to cut 5nm holes in masks for microprocessors, making modern digital electronics possible.</p><blockquote><p>Thunder only happens when it&#8217;s raining.</p><p>&#8212;Fleetwood Mac, <em><a href="https://www.youtube.com/watch?v=mrZRURcb1cM">Dreams</a></em></p></blockquote><p>Synergy isn&#8217;t merely putting two things together, and getting the sum of their parts; nor even getting <em>more</em> than the sum of their parts, in any na&#239;ve sense.  Combining two lasers doesn&#8217;t necessarily give you one doubly powerful laser.  Often, it&#8217;s precisely the tension <em>between</em> the composed parts (or people) in a system that makes it special.</p><p>Part of great project management is recognizing opportunities for synergy, and turning the workaday into something unique.  If you&#8217;re able to achieve synergy, and get it moving in the right direction, then you have captured lightning in a bottle.  Just maybe keep your voice down when you speak the word &#8220;synergy&#8221; aloud, because not everyone takes kindly to it.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Deeply Nested is a reader-supported publication. 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[AI Is Not the End of Coding]]></title><description><![CDATA[Rumors of the death of professional software development have been greatly exaggerated.]]></description><link>https://nested.substack.com/p/ai-is-not-the-end-of-coding</link><guid isPermaLink="false">https://nested.substack.com/p/ai-is-not-the-end-of-coding</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 14 Oct 2022 19:05:26 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e8694e78-e544-42bc-a206-bc89c8593a3e_2121x1414.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A real concern for people working in (or now entering) the software industry is that Artificial Intelligence (AI) will eliminate their jobs.  It&#8217;s hard to ignore the crescendo of armchair pundits hailing the rapidly increasing power of AI as the total obviation of manual computer programming.  Those concerns, while understandable, are really not justified.  AI is most definitely not the end of software engineering, nor related disciplines like product management.  We&#8217;ll keep this post brief (as last week&#8217;s was pretty long), but please do leave a comment if you&#8217;d like to dig deeper.</p><blockquote><p>The great humorist, while not perhaps very robust, is in the best of health.  He said: &#8220;. . . The report of my death was an exaggeration.&#8221;</p><p>&#8212;Frank Marshall White, <em><a href="https://www.google.com/books/edition/Mark_Twain/dOD7ilN1R38C?q=&amp;gbpv=1&amp;bsq=robust#f=false">New York Journal</a>, &#8220;Mark Twain Amused;&#8221; </em>via <em><a href="https://www.mentalfloss.com/article/562400/reports-mark-twains-quote-about-mark-twains-death-are-greatly-exaggerated">Mental Floss</a></em></p></blockquote><p>First, let&#8217;s get a little perspective.  The practice of encoding precise instructions for transforming available inputs into desired outputs long predates the electronic computer.  Knitting patterns and sheet music are &#8220;code&#8221; by any reasonable definition; and arguably, so are many cooking recipes.  The 19th-century advent of player pianos did not eliminate live music, any more than electronic synthesizers did a hundred years later.  Mass production of artificial foodstuffs has not ended the art of cooking&#8212;some of the best chefs are now even celebrities&#8212;nor have people stopped creating (and appreciating) hand-knit socks and sweaters despite the plethora of commonplace, machine-made alternatives.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div id="youtube2-sK4jyOII67U" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;sK4jyOII67U&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/sK4jyOII67U?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Technology has already eliminated any number of specific job roles (or nearly so), but that&#8217;s nothing new.  Somebody in every ancient tribe was probably The Best at starting fires by banging rocks together.  Not to be flippant about this:  It wasn&#8217;t long ago that robots put most automotive assembly line workers out of a job.  Now long-haul trucking seems destined to be replaced by self-driving vehicles.  People sometimes draw a distinction between blue and white collar work, but that misses the point: White collar jobs may absolutely be replaced by AI.  Stenography is certainly white-collar work, but it&#8217;s not hard to imagine it being replaced by voice-to-text applications.</p><blockquote><p>By 1977, Bricklin felt that programming was getting to be so easy that he would be out of a job soon.<br><br>&#8212;<em><a href="https://www.youtube.com/watch?v=nDPD7U_M8yw">Retro Tech Bytes - The Story of VisiCalc</a></em></p></blockquote><p>We can acknowledge the potential of technology to disrupt society, while also recognizing that as demand for particular skills waxes and wanes, it makes sense to relegate the most robotic tasks to machines.  That&#8217;s largely what programming is about.  More than that though, programming is about raising the level of abstraction; not only helping us do things more efficiently, but making what used to seem impossible a real part of our everyday lives.  AI is the next rung on the ladder of abstraction&#8212;which, as should be clear by now, has no upper limit.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_X8V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_X8V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png 424w, https://substackcdn.com/image/fetch/$s_!_X8V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png 848w, https://substackcdn.com/image/fetch/$s_!_X8V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png 1272w, https://substackcdn.com/image/fetch/$s_!_X8V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_X8V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png" width="577" height="433" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/dbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:433,&quot;width&quot;:577,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:266398,&quot;alt&quot;:&quot;Cartoon TV newscaster with an inset image of a robot head.  The newcaster says \&quot;I, for one, welcome our new ML models.\&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cartoon TV newscaster with an inset image of a robot head.  The newcaster says &quot;I, for one, welcome our new ML models.&quot;" title="Cartoon TV newscaster with an inset image of a robot head.  The newcaster says &quot;I, for one, welcome our new ML models.&quot;" srcset="https://substackcdn.com/image/fetch/$s_!_X8V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png 424w, https://substackcdn.com/image/fetch/$s_!_X8V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png 848w, https://substackcdn.com/image/fetch/$s_!_X8V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png 1272w, https://substackcdn.com/image/fetch/$s_!_X8V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfe9ee7-dbd4-4449-b971-36cfada32e49_577x433.png 1456w" sizes="100vw" loading="lazy" 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>Huge parts of what coders now do manually may well be done by AI soon.  Consider the ramifications of a similarly staccato step up the abstraction ladder: the leap from machine code to high-level programming languages in the 1950s.  The number of jobs available to programmers working directly in machine code declined precipitously, but with two key caveats:</p><ol><li><p>Programming didn&#8217;t go away.  Demand for professional programmers actually <em>increased</em>, because more powerful tools amplified the productivity (and thus the value) of each individual programmer.</p></li><li><p>As low-level knowledge became more rare, it developed into a specialization for which professionals even now charge a premium.  Processors did not stop adding new instruction sets (floating point, SIMD, GPU/matrix operations, etc.), nor did CPU-intensive applications stop vying for the most efficient use of hardware.</p></li></ol><p>Even folks who concede point 2&#8212;&#8220;OK sure, there will always be specialists&#8221;&#8212;sometimes have a hard time understanding point 1.  What seems to trip them up is the <em>id&#233;e fixe</em> of economics as a zero-sum game.  None of this is zero-sum.  <strong>The amount of work to be done is unbounded, and so is the reward.  </strong>Even if the demands society placed on the software industry were to stagnate, it would be naive to think there would be less demand for professional programmers.  But of course, demand does not stagnate, it escalates.</p><p>If you&#8217;re unconvinced&#8212;or, if you&#8217;re having trouble retaining engineers because <em>they&#8217;re</em> unconvinced&#8212;see also the very first Deeply Nested post: <a href="https://nested.substack.com/p/is-coding-a-dead-end-job">Is Coding a Dead End Job?</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Variables]]></title><description><![CDATA[New programmers are taught about variables on day 1, but only through vague analogies like &#8220;boxes you can put things in.&#8221;]]></description><link>https://nested.substack.com/p/variables</link><guid isPermaLink="false">https://nested.substack.com/p/variables</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 07 Oct 2022 21:40:36 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/497c771a-9d62-4d5f-8c5f-39100b8dbc65_3100x2063.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This post uses inline code blocks for very short code snippets, and images with alt text and links to GitHub for longer snippets.  Feedback is welcome.</em></p><div><hr></div><p>New programmers are taught about <em>variables</em> on day 1, but only through vague analogies like &#8220;boxes you can put things in.&#8221;  Even experienced programmers sometimes have no more than an intuitive understanding of what the word &#8220;variable&#8221; means.  Let&#8217;s nerd out a little this week, and take a deeper look at what a variable is.</p><h2>Mathematics</h2><p>In mathematics, a variable is a <em>name</em> bound to a <em>value</em>.  A statement like <code>x = 5</code> binds the name <code>x</code> to the value <code>5</code>.  A &#8220;name&#8221; is usually a letter, word, or short phrase.  Sometimes <a href="https://www.youtube.com/watch?v=J51ncHP_BrY&amp;t=269s">somebody gets wacky</a> and declares a variable whose name is a shape or a cartoon character or something.  A &#8220;value&#8221; can be any timeless concept, like the number 5 or the color blue.</p><p>A variable may represent different values in different situations.  For example, we can define <em>functions</em> that map <em>argument</em> values to <em>result</em> values, using variables called <em>parameters</em> to represent arguments abstractly.  In the function definition <code>f(x) = x + 1</code>, the variable <code>x</code> is a parameter.  In the function calls <code>f(3)</code> and <code>f(5)</code>, <code>x</code> is bound to the arguments <code>3</code> and <code>5</code>, respectively.</p><p>Values never, ever change.  A value is forever.  Variables that always represent the same value, like &#960; for the ratio of a circle&#8217;s circumference to its diameter, are sometimes called <em>constants</em>.  In fact, if you call &#960; a variable instead of a constant, you&#8217;re likely to annoy a lot of pedants; but in your heart of hearts, know that symbolic constants like &#960; are just variables that don&#8217;t vary.</p><blockquote><p>Rose is a rose is a rose is a rose.</p><p>&#8212;Gertrude Stein, <em><a href="https://www.gutenberg.org/files/33403/33403-h/33403-h.htm#Page_187">Sacred Emily</a></em></p></blockquote><h2>Code</h2><p><strong>In computer programming, a variable is a name bound to an </strong><em><strong>object</strong></em><strong>, which in turn represents a value.</strong>  This extra level of indirection can be tough to explain, which is why it&#8217;s rarely taught to newcomers.  Nevertheless, these concepts are fundamental to software engineering, and you ought to understand them if you do this stuff professionally.</p><p>An &#8220;object&#8221; is a <em>region</em> of <em>memory</em> that represents a value.  Computer &#8220;memory&#8221; is a big list of numbers, and a &#8220;region&#8221; is a contiguous sublist of memory.  Modern computers can store billions of small numbers in their Random Access Memory (RAM) all at the same time.  Of course, computer software needs to represent lots of different kinds of values, not only small numbers.  That&#8217;s where <em>types</em> come in.</p><h2>Types</h2><p>A &#8220;type&#8221; is a system for storing values in memory, or interpreting values previously stored there.  A region of computer memory (i.e., a list of numbers) on its own isn&#8217;t very useful, because you can&#8217;t tell what value it represents unless you also know its type.</p><p><em>&#128161;Types (sometimes called &#8220;classes&#8221;) are often explained to new programmers as being blueprints for objects.  That&#8217;s not a bad analogy, but it breaks down quickly as you dig deeper into type theory.  One rarely hears about &#8220;blueprint contravariance&#8221; or &#8220;higher kinded blueprints.&#8221;</em></p><p>Types for representing common kinds of values, such as colors or strings of text, often use standard <em>encodings</em> to map values into numbers.  For example, the list of numbers <code>[72, 105, 0]</code> represents an ugly shade of green as an RGB encoded color, but the word <code>Hi</code> when interpreted as UTF-8 encoded text.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QuO9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QuO9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png 424w, https://substackcdn.com/image/fetch/$s_!QuO9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png 848w, https://substackcdn.com/image/fetch/$s_!QuO9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png 1272w, https://substackcdn.com/image/fetch/$s_!QuO9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QuO9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png" width="1238" height="1042" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1042,&quot;width&quot;:1238,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:140263,&quot;alt&quot;:&quot;A browser window showing a page with a green background.  The JavaScript console is open, and the following statement has been entered: document.body.style.backgroundColor = \&quot;rgb(72, 105, 0)\&quot; &quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A browser window showing a page with a green background.  The JavaScript console is open, and the following statement has been entered: document.body.style.backgroundColor = &quot;rgb(72, 105, 0)&quot; " title="A browser window showing a page with a green background.  The JavaScript console is open, and the following statement has been entered: document.body.style.backgroundColor = &quot;rgb(72, 105, 0)&quot; " srcset="https://substackcdn.com/image/fetch/$s_!QuO9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png 424w, https://substackcdn.com/image/fetch/$s_!QuO9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png 848w, https://substackcdn.com/image/fetch/$s_!QuO9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.png 1272w, https://substackcdn.com/image/fetch/$s_!QuO9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F001a3c5c-72d8-4d9c-9144-ae51880b1f4a_1238x1042.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">As an RGB color, the numbers 72, 105, 0 represent a shade of green.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2Cc1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2Cc1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png 424w, https://substackcdn.com/image/fetch/$s_!2Cc1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png 848w, https://substackcdn.com/image/fetch/$s_!2Cc1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png 1272w, https://substackcdn.com/image/fetch/$s_!2Cc1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2Cc1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png" width="1456" height="925" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:925,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:137985,&quot;alt&quot;:&quot;A C program that casts an array of bytes { 72, 105, 0 } to a string and prints it, followed by a command to compile and run the program.  The output of the program is shown as a single line containing only the word Hi.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A C program that casts an array of bytes { 72, 105, 0 } to a string and prints it, followed by a command to compile and run the program.  The output of the program is shown as a single line containing only the word Hi." title="A C program that casts an array of bytes { 72, 105, 0 } to a string and prints it, followed by a command to compile and run the program.  The output of the program is shown as a single line containing only the word Hi." srcset="https://substackcdn.com/image/fetch/$s_!2Cc1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png 424w, https://substackcdn.com/image/fetch/$s_!2Cc1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png 848w, https://substackcdn.com/image/fetch/$s_!2Cc1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.png 1272w, https://substackcdn.com/image/fetch/$s_!2Cc1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47e06f2f-d0bd-4c37-9f9b-12769a6b45f9_1578x1002.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">As a UTF-8 string, the numbers 72, 105, 0 represent the word Hi.  We can&#8217;t make sense of an object in memory&#8212;i.e., know what value it represents&#8212;unless we know its type.  (<a href="https://github.com/jeffs/nested/blob/main/variables/src/hi.c">hi.c</a>, <a href="https://github.com/jeffs/nested/blob/main/variables/src/hi.c">hi.log</a>)</figcaption></figure></div><p>None of this is specific to any single programming language, but the C standard offers a pretty good definition of object:</p><blockquote><p><strong>object<br></strong>region of data storage in the execution environment, the contents of which can represent values.</p><p><strong>Note 1 to entry: </strong>When referenced, an object can be interpreted as having a particular type.</p><p>&#8212; <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf">N2596</a> (working draft), 3.15</p></blockquote><h3>Static vs. dynamic types</h3><p>You might think that when a program stores a value in memory (i.e., in an object), it also has to store some type information, so that it doesn&#8217;t forget what kind of value was stored.  Types used that way are described as <em>dynamic</em>.</p><p>Some languages also support <em>static</em> types, which are tracked through analysis of the source code.  This is arguably the best of all possible worlds.  We get the safety of knowing whether we got our types straight before the program even runs (!), and without the performance overhead of storing and retrieving dynamic type information.</p><p>The chief shortcoming of static types is that sometimes, we won&#8217;t know what kinds of values we need until the program is already running.  For that reason, even &#8220;statically typed&#8221; languages also have to support dynamic types.  (C in particular does so grudgingly, but most newer languages are less judgy about it.)</p><p>Variables having static vs. dynamic types are sometimes said to be <em>early</em> or <em>late</em> <em>binding,</em> respectively.</p><h2>Object footprints</h2><p>Part of the definition of an object is that its region is contiguous, meaning all the numbers are stored next to each other in memory.  The contiguous region is called the object&#8217;s <em>footprint</em>.  There are two caveats you should be aware of:  The footprint may contain <em>padding</em> that does not store any part of the object&#8217;s value, and <em>pointers</em> to other regions that do.</p><h3>Padding</h3><p>Indexes into memory are called <em>addresses</em>, and they refer to individual <em>bytes, </em>each big enough to store one small number; typically, an integer from 0 through 255.  Computers can work with some types efficiently only when their values are stored at addresses divisible by certain numbers (usually 2, 4, or 8).  Strange but true.  Such types are said to have <em>alignment</em> requirements.  So, sometimes an object&#8217;s footprint will include meaningless bytes as &#8220;padding,&#8221; merely so that the next meaningful part of the value lives at a suitably aligned address.</p><h3>Pointers</h3><p>A &#8220;pointer&#8221; is an object whose value is a memory address.  A complex object&#8217;s footprint might include pointers so that it can share data with other objects, or so that data can live in a specific part of memory; for example, storing huge chunks of data on the <em>heap</em> (which has plenty of room) even when the object&#8217;s footprint lives on the <em>stack</em> (which does not)<em>.</em></p><h2>Move semantics</h2><p>It&#8217;s sometimes useful to <em>move</em> objects around in memory.  For example, maybe we&#8217;ve stored the color blue at address 1024, but now we want to store it at address 512 instead.  Computer hardware doesn&#8217;t really support move semantics<em>, </em>so moves are usually implemented as copies.  Move semantics are yet another reason for an object&#8217;s footprint to contain pointers:  When we move an object, it&#8217;s usually cheaper to copy a pointer than to copy all the data the pointer points to.</p><p>Garbage collected languages move objects all the time.  When you hear about <em>mark and sweep</em> GC, remember that &#8220;sweep&#8221; is a euphemism for &#8220;copy.&#8221;  This is why it&#8217;s so hard to get an object&#8217;s address (or any unique identifier) in most GC languages:  The language designers don&#8217;t want you to think of the object as living at any particular address, because it might get moved.</p><p>C++ has an, um, interesting approach to this:  Rather than moving the object, you move the value from one object to another.  The original object is &#8220;move copied,&#8221; and left in some technically valid but unpredictable state.  The introduction of move semantics to C++ in 2011 was a game changer in terms of performance and expressiveness, but it also added one heck of a foot gun to a language already rich in weapons for shooting oneself in the foot.</p><h2>Exotic variables</h2><h3>Reference types; or, &#8220;Dammit, Java!&#8221;</h3><p>If the value we want to represent happens to be a small number, then it&#8217;s easy to imagine how we&#8217;d store it in memory, which is (after all) a list of numbers.  Most programming languages even include built-in types (sometimes called <em>primitive</em> or <em>intrinsic</em> types) for storing such values.  User Defined Types (UDTs), on the other hand, get different levels of support in different languages.</p><p>C++ bends over backward to give UDTs the same level of support as primitive types.  <a href="https://www.amazon.com/Design-Evolution-C-Bjarne-Stroustrup/dp/0201543303">The Design and Evolution of C++</a>, penned by the language&#8217;s creator, describes how making UDTs first class entities was an overriding design goal.</p><p>At the other end of the spectrum, Java treats primitive and user-defined types completely differently.  Java primitives are stored entirely <strong>within</strong> the object&#8217;s footprint, whereas UDTs live entirely <strong>outside</strong> it.  The nomenclature is confusing:  Java provides primitive types like <code>int</code> to represent small numbers, and (like all programming languages) stores them in regions of memory; but weirdly, does not consider those regions &#8220;objects.&#8221;  Instead, only variables of <em>reference types</em> are bound to (what Java considers) objects.  Ironically, variables of reference types <strong>cannot</strong> be<strong> </strong>bound directly to objects.  Instead, they may be bound only to <em>references</em> to the actual objects.</p><p>In the Java code below, copying a primitive integer and then mutating the copy has no effect on the original integer; which should make perfect sense, because why would manipulating a copy affect the original?  These are variables, not voodoo dolls.  Copying a variable of reference type and then manipulating it <strong>does</strong> affect the original though:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!W5Y9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W5Y9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png 424w, https://substackcdn.com/image/fetch/$s_!W5Y9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png 848w, https://substackcdn.com/image/fetch/$s_!W5Y9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png 1272w, https://substackcdn.com/image/fetch/$s_!W5Y9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W5Y9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png" width="1456" height="1346" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1346,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:378396,&quot;alt&quot;:&quot;Java code showing how copying then manipulating primitive integers works sanely, whereas copying then manipulating an ArrayList changes the value represented by both the original variable and the copy.  The code is accompanied by comments, the last of which reads:  LOL, GFY!  &#8212;Love, Java&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Java code showing how copying then manipulating primitive integers works sanely, whereas copying then manipulating an ArrayList changes the value represented by both the original variable and the copy.  The code is accompanied by comments, the last of which reads:  LOL, GFY!  &#8212;Love, Java" title="Java code showing how copying then manipulating primitive integers works sanely, whereas copying then manipulating an ArrayList changes the value represented by both the original variable and the copy.  The code is accompanied by comments, the last of which reads:  LOL, GFY!  &#8212;Love, Java" srcset="https://substackcdn.com/image/fetch/$s_!W5Y9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png 424w, https://substackcdn.com/image/fetch/$s_!W5Y9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png 848w, https://substackcdn.com/image/fetch/$s_!W5Y9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.png 1272w, https://substackcdn.com/image/fetch/$s_!W5Y9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fac875722-9718-4da0-bcd5-6f9b8c3c16b2_2140x1978.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">Bonus: If you forget to pass java -ea at runtime, all assertions are silently ignored.  (<a href="https://github.com/jeffs/nested/blob/main/variables/src/main/java/Main.java">Main.java</a>, <a href="https://github.com/jeffs/nested/blob/main/variables/snip/java.log">java.log</a>)</figcaption></figure></div><p>Java variables of reference types can also be bound to no object at all, in which case they&#8217;re considered <em>null</em>.  Null values can be useful when used selectively, as is common in Golang (where null is called <code>nil</code>); but unlike Go, Java asininely makes <strong>all</strong> variables of non-primitive types nullable, whether you want them to be or not.  Golang is proof that a GC language needn&#8217;t be burdened by this reference/null stupidity.</p><p><em>&#129700; Several languages, including C++ and Rust as well as Java, use the term &#8220;reference&#8221; to mean a pointer that&#8217;s semantically not considered an object in its own right.  In other words:  Even in non-GC languages, you can&#8217;t take the address of a reference (even though it really does live at some address in memory, barring optimizations like register-only variables).  If you try, you&#8217;ll only get the address of the referenced object; that is, the address that the pointer points to.</em></p><p>The bizarreness of Java&#8217;s object model is a historical relic of a mid-1990s fever dream through which Object Oriented Programming (OOP) was seen as some kind of pinnacle of human achievement.  Java-style OOP mandates inappropriate conflation of inheritance with <a href="https://nested.substack.com/p/polymorphism">polymorphism</a>, as well as other pretentious garbage that&#8217;s hard to support efficiently on outr&#233; types like, you know, integers.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PJ7v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PJ7v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg 424w, https://substackcdn.com/image/fetch/$s_!PJ7v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg 848w, https://substackcdn.com/image/fetch/$s_!PJ7v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!PJ7v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PJ7v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.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;:1202953,&quot;alt&quot;:&quot;Photo of a macho dude doing curls and giving us bedroom eyes.  Overlaid text says: Bro, do you even [interface inheritance]?&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Photo of a macho dude doing curls and giving us bedroom eyes.  Overlaid text says: Bro, do you even [interface inheritance]?" title="Photo of a macho dude doing curls and giving us bedroom eyes.  Overlaid text says: Bro, do you even [interface inheritance]?" srcset="https://substackcdn.com/image/fetch/$s_!PJ7v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg 424w, https://substackcdn.com/image/fetch/$s_!PJ7v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg 848w, https://substackcdn.com/image/fetch/$s_!PJ7v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!PJ7v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F859f68e1-9832-42a4-a4f9-19596cee8be5_2120x1414.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><h3>Lazy variables</h3><p>Some languages support <em>lazy </em>variables, introducing yet another level of indirection.  Rather than binding names to objects that represent values encoded by types (whew!), lazy variables bind names to objects called <em>thunks</em>.  Thunks represent whatever computation is necessary to encode the desired value, and delay that computation until the value is actually used.</p><p>For example, in this Scala example, <code>x</code> is semantically bound to the value <code>1</code>; but actually, it&#8217;s bound to a thunk that prints a string and then returns the value <code>1</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_!_QRx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_QRx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png 424w, https://substackcdn.com/image/fetch/$s_!_QRx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png 848w, https://substackcdn.com/image/fetch/$s_!_QRx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png 1272w, https://substackcdn.com/image/fetch/$s_!_QRx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_QRx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png" width="1456" height="1435" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1435,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:212667,&quot;alt&quot;:&quot;A scala program that declares lazy val x intialized by a block including println(\&quot;x initializer\&quot;) and the number 1, followed by val y initialized directly by the value 2.  After the assignments are println(y) and println(x).  The output of the program is shown as 2, x intializer, 1. &quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A scala program that declares lazy val x intialized by a block including println(&quot;x initializer&quot;) and the number 1, followed by val y initialized directly by the value 2.  After the assignments are println(y) and println(x).  The output of the program is shown as 2, x intializer, 1. " title="A scala program that declares lazy val x intialized by a block including println(&quot;x initializer&quot;) and the number 1, followed by val y initialized directly by the value 2.  After the assignments are println(y) and println(x).  The output of the program is shown as 2, x intializer, 1. " srcset="https://substackcdn.com/image/fetch/$s_!_QRx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png 424w, https://substackcdn.com/image/fetch/$s_!_QRx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png 848w, https://substackcdn.com/image/fetch/$s_!_QRx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.png 1272w, https://substackcdn.com/image/fetch/$s_!_QRx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F74650a3c-57ef-40cf-a40a-4f9d4d82d0b9_1674x1650.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">Lazy val x is not initialized until used.  (<a href="https://github.com/jeffs/nested/blob/main/variables/src/main/scala/Main.scala">Main.scala</a>, <a href="https://github.com/jeffs/nested/blob/main/variables/snip/scala.log">scala.log</a>)</figcaption></figure></div><p>Scala papers over some of the more broken parts of Java by unifying primitive types and UDTs under a single base <code>Any</code> type, and blurring the distinction by making collections immutable by default.  However, Scala also introduces its own academic nonsense, such as referring to objects as values in official documentation.  <strong>Objects are not values, even if they&#8217;re immutable.  </strong>Objects <em>represent</em> values, but unlike pure values, objects occupy real space and consume real resources in real computers here in the actual, non-academic world where we humans live.</p><h3>Function objects</h3><p>Sometimes, you&#8217;ll hear a new programmer say they&#8217;re &#8220;calling&#8221; a variable, when they mean they&#8217;re <em>using</em> it.  That&#8217;s a good habit to break, because it gets confusing when variables can be bound to <em>function objects</em>&#8212;that is, objects representing functions.  For example, suppose we use such a variable to register a callback in JavaScript:</p><pre><code><code>const handleClick = function () {
  console.log("hello");
};

button.addEventListener('click', handleClick);</code></code></pre><p>We&#8217;ve used <code>handleClick</code> here, but we haven&#8217;t called it.  It won&#8217;t be called unless someone clicks the button.</p><h3>Unsized types</h3><p>In most type systems, all objects of a given type have the same footprint size.  Even types like strings and vectors that include pointers to variable amounts of data have some fixed footprint size, typically big enough to hold the pointer and some metadata.  That&#8217;s not always good enough:  Sometimes, objects of a particular type should be allowed to have different sizes.  In most languages, working with such types requires the programmer to be exceedingly careful.</p><blockquote><p>Parameter string starts immediately after this object. Be careful to add padding after string to ensure correct alignment of subsequent dm_target_spec.</p><p>&#8212;Linux kernel, <code>struct dm_target_spec</code> (<a href="https://github.com/torvalds/linux/blob/e2b542100719a93f8cdf6d90185410d38a57a4c1/include/uapi/linux/dm-ioctl.h#L172-L176">dm-ioctl.h</a>)</p></blockquote><h2>Rust</h2><p>We need to talk about Rust for a minute, because <strong>Rust gets so much of this stuff staggeringly right.</strong></p><h3>Unified syntax for early and late binding variables</h3><p>Rust unifies the syntax for static and dynamic bindings by adding a <code>dyn</code> keyword.  I cannot overstate how cool this is.  It reflects a profound understanding not only of the Computer Science (CS) involved, but of the actual day-to-day reality of software engineering.  For example, suppose we have some abstract interface:</p><pre><code>trait MyInterface {
    fn do_something(&amp;self);
}</code></pre><p>Here&#8217;s a function that accepts a reference to any object whose type implements that interface, so long as the type is known statically (i.e., at compile time):</p><pre><code>fn f(x: &amp;impl MyInterface) {
    x.do_something();
}</code></pre><p>Now, suppose we realize that oops, we won&#8217;t know the type until runtime.  Literally the only change we need is to replace <code>impl</code> with <code>dyn</code>:</p><pre><code><code>fn f(x: &amp;dyn MyInterface) {
    x.do_something();
}</code></code></pre><p>You can even have some functions take the type statically, and others dynamically.  The decision is made where the variables are defined, not where the type is.  So, so cool.</p><h3>Questionably sized types</h3><p>In most languages, properly supporting types whose size may vary is tough.  How can the language support even simple operations like copying an object, if it doesn&#8217;t know where in memory the object ends?  Rust works around this issue with spectacular simplicitly:  It lets you declare questionably sized (<code>?Sized</code>) types that support only safe operations, and trigger compile-time errors for any operation that the language cannot safely support.</p><h3>Obviating padding</h3><p>We discussed Rust&#8217;s flexible object layouts in <a href="https://nested.substack.com/p/type-systems-and-alignment">Type Systems and Alignment</a>.</p><h3>Safe move semantics</h3><p>Rust supports roughly the same move functionality as C++, but more efficiently, and without any foot guns.  When you move an object in Rust, you&#8217;re semantically moving it out of the variable (which is now bound to the wrong region of memory), rather than leaving the variable bound to a zombie object (as in C++) or requiring the variable to go through a reference (as in Java).  If you try to use a moved-from variable, the compiler reports an error.  (There&#8217;s a loophole for primitive types, or indeed any types that support <a href="https://doc.rust-lang.org/std/marker/trait.Copy.html">bitwise copy</a>, so something like <code>let x = 42; let y = x;</code> doesn&#8217;t sacrifice access to <code>x</code>.)</p><h2>Everybody got that?</h2><p>There&#8217;s a lot more to understand if you want to be a systems programmer, such as volatility and atomicity of variables that are accessed by multiple threads, but this is already a long post for what&#8217;s usually passed off as a simple topic.  Congratulations on reading this far, and please do leave a comment if you&#8217;d care to guide further discussion.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Redundancy, Part 1]]></title><description><![CDATA[This One Weird Trick means crashes needn't be outages.]]></description><link>https://nested.substack.com/p/redundancy-part-1</link><guid isPermaLink="false">https://nested.substack.com/p/redundancy-part-1</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 30 Sep 2022 02:35:08 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/0c89d7d4-35a3-472f-8864-51274cf9d444_960x720.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Computer programs come in two basic kinds: Those that run as needed, and those that run continuously, responding to events as they happen. The former are usually called <em>batch jobs</em> or <em>applications</em>, and the latter <em>daemons</em> or <em>services</em> (or <em>microservices</em> if they&#8217;re particularly svelte).</p><p>Suppose we&#8217;re responsible for a mission-critical service; that is, a computer program that&#8217;s supposed to keep running all the time so it can respond to important events like client requests.  Nothing in this world is perfect, so there&#8217;s always a chance the service will crash, causing downtime for our system and our business. Hardware failures and software bugs (especially race conditions) are the usual culprits, but let&#8217;s assume that in any given second of time, there&#8217;s very little chance&#8212;say, one in a million&#8212;that our service will crash. In other words, if our service is humming along happily, there&#8217;s a 99.9999% chance it will continue to do so for at least the next second. Let&#8217;s call that chance P, and the one-in-a-million chance of failure Q.</p><pre><code><code>$ node
Welcome to Node.js v16.17.0.
Type ".help" for more information.
&gt; Q = 1e-6
0.000001
&gt; P = 1 - Q
0.999999</code></code></pre><p>The odds of failure compound <a href="https://stats.oecd.org/glossary/detail.asp?ID=6685">geometrically</a>.  For example, the chance that our service will stay up for at least the next three seconds is the <em>product</em> of the chance that it won&#8217;t crash in the next second, nor in the second after that, nor the one after that: P * P * P, or P**3.</p><pre><code>&gt; P ** 3
0.999997000003</code></pre><p>In general, the chance that a happy service will remain so for &gt;=N seconds is P**N.  The chance that our service will stay up for at least a minute is P**60, for an hour P**3600, etc.  So, how long will it be before our service is likely to crash?  What&#8217;s the time horizon beyond which the chance of failure exceeds 50%?  Not long, as it turns out, because <strong>geometric growth is downright nasty</strong>.</p><pre><code>&gt; Math.log(0.50) / Math.log(P) / 3600 / 24
8.022532800536636</code></pre><p>Eight days.  That&#8217;s it.  If you run a single-instance monolithic service in production, you&#8217;re liable to have a complete outage every couple of weeks.  The one-in-a-million Q value we&#8217;ve been using might charitably be called &#8220;imprecise,&#8221; but this jibes with real-world experience:  Too many small companies deal with random outages almost every week.  These outages take a harrowing toll not only on productivity, but on the quality of life of the engineering and product support teams, including client-facing staff like Account Managers.  People shrug off this absurd burden as though it&#8217;s inevitable (&#8220;Startup life, am I right?&#8221;) and euphemize it in job postings as a &#8220;fast-paced environment,&#8221; but it&#8217;s truly an awful way to live.  What&#8217;s more, it&#8217;s easily avoided.</p><p>The first and most obvious approach&#8212;and the only one we&#8217;ll cover in this post&#8212;is to <strong>run two instances of every service</strong>.  Any more than two is gravy.</p><p><em>&#129700; If you&#8217;re an engineer who has worked at large Software as a Service (SaaS) companies, then advice like &#8220;have redundancy in prod&#8221; may sound utterly obvious.  But if ever you start bopping around startups as an advisor or contractor, you will be stunned at how common these fault-intolerant monoliths are, mostly because the tech teams don&#8217;t understand the trade-offs involved.</em></p><p>Because we&#8217;re discussing random crashes, the odds of one instance crashing are independent of the other instance.  We can thus replace Q with Q*Q in our formulae above, making our new probability of surviving the next second 1 - Q*Q.  Let&#8217;s call that P2:</p><pre><code>&gt; P2 = 1 - Q*Q
0.999999999999</code></pre><p>Now how long can we expect <em>at least one instance</em> of our service to stay up?</p><pre><code>&gt; Math.log(0.50) / Math.log(P2) / 60 / 60 / 24
8022714.288272493
&gt; _ / 365.25
21964.9946290828</code></pre><p>Almost 22,000 years.  Individual service instances will still crash as often as before, but those crashes won&#8217;t cause major outages, because both instances are extremely unlikely to crash at the same time.  (One could crash while the other is already down, but that chance becomes minimal if we address crashes promptly&#8212;even if all we do is restart the crashed instance.)  We still have to deal with the crashes, but they&#8217;re no longer oh-my-god all-hands-on-deck emergencies, and they don&#8217;t impact users at all.</p><p>Productivity and quality of life improve tremendously if we run more than one instance, especially if our service is a little flaky to begin with.  Going multi-instance does impose a couple of architectural requirements though:</p><ol><li><p>We need a load balancer (LB) like <a href="https://www.haproxy.com/blog/how-to-enable-health-checks-in-haproxy/">HAProxy</a> to automatically route traffic to a healthy instance.  Our service also needs a health check endpoint, so the LB can tell when an instance isn&#8217;t feeling well.  (But if we don&#8217;t already have a health check, how do we even know when we&#8217;re having an outage?  Wait for customers to complain?  <em>&lt;shiver&gt;</em>)</p></li><li><p>Our service instances must be <em>stateless</em>.  The system as a whole needn&#8217;t be stateless, and can keep whatever database (DB) it already uses.  But now, it&#8217;s especially important that we not keep any state where only one instance can access it, such as in-memory variables.<br>People sometimes try to skirt this requirement using &#8220;sticky sessions,&#8221; meaning they ensure that consecutive requests from a single user are always routed to the same instance.  Don&#8217;t do that.  It complicates the LB config, boots users out of their sessions whenever an instance crashes, and normalizes instance-local state that may not even be session-specific.  Put your data in a DB, or in shared &#8220;data structure servers&#8221; like <a href="https://redis.io/docs/data-types/">Redis</a>.</p></li></ol><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_!Skqq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Skqq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png 424w, https://substackcdn.com/image/fetch/$s_!Skqq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png 848w, https://substackcdn.com/image/fetch/$s_!Skqq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png 1272w, https://substackcdn.com/image/fetch/$s_!Skqq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Skqq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png" width="650" height="601" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:601,&quot;width&quot;:650,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25894,&quot;alt&quot;:&quot;Diagram showing a user, a service instance, and a database on the left; and a user, load balancer, two service instances, and a database on the right.  Boxes labeled \&quot;Session state\&quot; appear in the service instance on the left and the database on the right.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram showing a user, a service instance, and a database on the left; and a user, load balancer, two service instances, and a database on the right.  Boxes labeled &quot;Session state&quot; appear in the service instance on the left and the database on the right." title="Diagram showing a user, a service instance, and a database on the left; and a user, load balancer, two service instances, and a database on the right.  Boxes labeled &quot;Session state&quot; appear in the service instance on the left and the database on the right." srcset="https://substackcdn.com/image/fetch/$s_!Skqq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png 424w, https://substackcdn.com/image/fetch/$s_!Skqq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png 848w, https://substackcdn.com/image/fetch/$s_!Skqq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.png 1272w, https://substackcdn.com/image/fetch/$s_!Skqq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6b9398-039a-4f9d-b8ef-b0b97e6dd4f7_650x601.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">On the left, users send requests directly to a single service instance, which may be stateful.  On the right, requests are sent through a load balancer that routes them to either of two instances, both of which are stateless.  The user on the left probably shouldn&#8217;t be smiling, because the single-instance system is an outage waiting to happen.</figcaption></figure></div><p></p><p>In upcoming Deeply Nested posts, we&#8217;ll discuss further use of redundancy to improve uptime, and to gain other benefits like economies of scale.  In the meantime, please do share relevant thoughts or experience (or horror stories!) in the comments.  And here&#8217;s a question for you:  Going forward, should system architecture posts continue discussing high-level issues like redundancy; dive deeper into topics like orchestration and containerization; or get into the nitty gritty of how to configure particular tools like Kubernetes and Docker?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[What to do, what to do?]]></title><description><![CDATA[Investing yourself in the pursuit of knowledge is one thing.&#160; Deciding which knowledge to pursue is another.]]></description><link>https://nested.substack.com/p/what-to-do-what-to-do</link><guid isPermaLink="false">https://nested.substack.com/p/what-to-do-what-to-do</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 23 Sep 2022 02:29:59 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/9721af23-11c8-40be-8c43-b37146493083_2073x1446.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>People change over time, mostly for the better.  None of us is quite who we were ten years ago, nor will be ten years hence.  Technologists, more than most other people, are constantly learning.  Even if <a href="https://nested.substack.com/p/keeping-up">Keeping Up</a> is impossible, staying sharp is vital.</p><blockquote><p>We are not nouns.  We are verbs.</p><p>&#8212;<a href="https://www.theguardian.com/media/2010/jul/20/stephen-fry-bbc-planet-word">Stephen Fry</a></p></blockquote><p>Of course, we pick up some skills naturally on the job.  But given that you&#8217;re the sort of person who reads a Software Engineering blog, you probably do more than that.  How do you decide what to study?  Tools, languages, frameworks, paradigms&#8230; What, in the interest of career growth or edification, shall you learn?  The decision can be daunting, because time is finite.  What if you focus on the wrong thing?</p><blockquote><p>I really don&#8217;t know.  I really don&#8217;t know what to do.</p><p>&#8212;The Rolling Stones, <em><a href="https://www.youtube.com/watch?v=j5RVsgmUrnY">What to Do</a></em></p></blockquote><p>Most of the risk in studying the &#8220;wrong&#8221; thing is minor.  Even if you find you&#8217;ve spent some time suboptimally, is that so bad?  If you learned anything at all, then your time wasn&#8217;t entirely squandered, even if not all of it was exactly useful.  Another concern is that you&#8217;ll study to get a job (or a <em>better</em> job), but that you&#8217;ll somehow accidentally acquire only skills for which there&#8217;s no demand.  Rest assured that this is unlikely.  There continues to be tremendous demand for technical adepts of all stripes.</p><p>The greater danger is in finding yourself hard at work on something you don&#8217;t actually like or care about.  As you study, ask yourself sincerely, &#8220;Is this for me?  Is this what I want to be doing?&#8221;  If not, you may eventually feel stuck in a role that doesn&#8217;t fit you any better than someone else&#8217;s clothing.</p><blockquote><p>A man whose desire is to be something separate from himself . . . invariably succeeds in being what he wants to be. That is his punishment.</p><p>&#8212;Oscar Wilde, <em><a href="https://www.bl.uk/collection-items/manuscript-of-de-profundis-by-oscar-wilde">De Profundis</a></em></p></blockquote><blockquote><p>&#8220;Everyone gets everything he wants. I wanted a mission. And for my sins, they gave me one.&#8221;</p><p>&#8212;John Milius and Francis Coppola, <em><a href="https://www.youtube.com/watch?v=_DcYuOSDxGk">Apocalypse Now</a></em></p></blockquote><p>While the type of tech you study probably won&#8217;t make or break your ability to find work, it can have a big impact on the <em>kind</em> of work you do.  SQL is <em>de rigueur</em> for business analytics, as C is for embedded developers, and neither is a substitute for the other.  If you want to develop websites, you should know basic HTML, CSS, and JavaScript, but those are no replacement for R or Python if you want to be a data scientist.</p><p>The counter-intuitive point here is that the relative value of different technical knowledge depends as much on you personally as on the world around you.  SQL, JavaScript, and C are all languages that make some people deeply happy, and others miserable.</p><blockquote><p>Know yourself.</p><p>&#8212;<a href="https://greekcitytimes.com/2021/12/11/how-to-be-happy-the-delphic-maxims-147-rules-for-a-happy-life/">Delphic maxim</a> sometimes attributed to Socrates</p></blockquote><blockquote><p>Now that you know who you are, what do you want to be?</p><p>&#8212;The Beatles, <em><a href="https://www.youtube.com/watch?v=i5m-sgtwFck">Baby You&#8217;re a Rich Man</a></em></p></blockquote><p>Choice is freedom, but it is also a burden.  Some questions, like &#8220;What should I do with my life?,&#8221;  are obviously hard.  Others, like &#8220;Should I learn Biopython so I can fight disease, or Godot so I can make video games?&#8221; are <em>surprisingly</em> hard.  <strong>The pursuit of knowledge is not merely about what you want to learn, but about how you want to spend your days.</strong>  The only wrong choice is one that&#8217;s not true to yourself.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Recursion Stinks]]></title><description><![CDATA[see also: Recursion Stinks]]></description><link>https://nested.substack.com/p/recursion-stinks</link><guid isPermaLink="false">https://nested.substack.com/p/recursion-stinks</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 16 Sep 2022 02:00:47 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/bd2c1e5b-f85a-48b5-8954-be7cb8b0ba04_2121x1414.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This is a code-heavy post.  Code is presented as images to preserve formatting and highlighting, with captions linked to plain text files.</em></p><div><hr></div><p>I always ask software engineering interview candidates to implement a factorial function, then (assuming factorial goes well) a Fibonacci function.  These are admittedly trite exercises that, for senior engineers, serve as quick warm-ups.  Junior engineers didn&#8217;t used to have much trouble with them, either; but over the past ~10 years, a strange trend has arisen whereby new college grads consistently go straight for recursive implementations.  <em>They all seem to do this.</em>  It&#8217;s uncanny.  (Are entry-level software engineers all reading the same prep book, or watching the same YouTube channel or something?)  Recursion usually makes for terrible solutions, and I&#8217;d like to show you some reasons why.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p><em>&#129700; Despite <a href="https://nested.substack.com/p/the-problem-with-big-o">The Problem with Big O</a>, this post bears a light sprinkling of big-O expressions.  It&#8217;s fine to skip right past them if you want.  Moreover, we&#8217;ll distinguish space and time complexity using &#8216;s&#8217; and &#8216;t&#8217; subscripts; for example, O&#8347;(N)O&#8348;(2&#7482;) indicates that an algorithm completes in linear space and exponential time.  But again, it&#8217;s fine to ignore all that, unless you&#8217;re a glutton for undergrad-level Computer Science.</em></p><h2>Factorial</h2><p>First, let&#8217;s look at a recursive factorial function.  We&#8217;ll use Rust, but (except where noted) the same principles hold for other languages.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hThC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hThC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png 424w, https://substackcdn.com/image/fetch/$s_!hThC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png 848w, https://substackcdn.com/image/fetch/$s_!hThC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png 1272w, https://substackcdn.com/image/fetch/$s_!hThC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hThC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png" width="1456" height="443" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:443,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:138022,&quot;alt&quot;:&quot;fn factorial_rec(n: u64) -> u64 {     if n < 2 {         1     } else {         n * factorial_rec(n - 1)     } }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn factorial_rec(n: u64) -> u64 {     if n < 2 {         1     } else {         n * factorial_rec(n - 1)     } }" title="fn factorial_rec(n: u64) -> u64 {     if n < 2 {         1     } else {         n * factorial_rec(n - 1)     } }" srcset="https://substackcdn.com/image/fetch/$s_!hThC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png 424w, https://substackcdn.com/image/fetch/$s_!hThC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png 848w, https://substackcdn.com/image/fetch/$s_!hThC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.png 1272w, https://substackcdn.com/image/fetch/$s_!hThC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F226e274f-c957-4d0d-8cbd-040639492edd_3058x930.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><figcaption class="image-caption">Recursive factorial function: O&#8347;(N)O&#8348;(N) (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/factorial_rec.rs">factorial_rec.rs</a>)</figcaption></figure></div><p>The first thing that should concern you about this code is integer overflow.  Factorials get big <em>fast</em>.  Integer overflow is easy enough to avoid (potentially at the expense of performance) by switching to a growable return type like <a href="https://docs.rs/num/0.4.0/num/struct.BigUint.html">num::BigUint</a>.  Some languages, like Python, even use growable integers by default.</p><p>The bigger problem is stack overflow.  Most programming languages (with notable exceptions like Golang, as <a href="https://dave.cheney.net/2013/06/02/why-is-a-goroutines-stack-infinite">explained by Dave Cheney</a>) allow each thread only a finite amount of stack space.  Each recursive call takes another chunk out of that space.  When the stack space is gone, the program crashes, and it crashes ugly.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0x2T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0x2T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png 424w, https://substackcdn.com/image/fetch/$s_!0x2T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png 848w, https://substackcdn.com/image/fetch/$s_!0x2T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png 1272w, https://substackcdn.com/image/fetch/$s_!0x2T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0x2T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png" width="1456" height="308" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/a11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:308,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:86338,&quot;alt&quot;:&quot;$ cargo run --quiet --release  thread 'main' has overflowed its stack fatal runtime error: stack overflow [1]    9275 IOT instruction  cargo run --quiet --release&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="$ cargo run --quiet --release  thread 'main' has overflowed its stack fatal runtime error: stack overflow [1]    9275 IOT instruction  cargo run --quiet --release" title="$ cargo run --quiet --release  thread 'main' has overflowed its stack fatal runtime error: stack overflow [1]    9275 IOT instruction  cargo run --quiet --release" srcset="https://substackcdn.com/image/fetch/$s_!0x2T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png 424w, https://substackcdn.com/image/fetch/$s_!0x2T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png 848w, https://substackcdn.com/image/fetch/$s_!0x2T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png 1272w, https://substackcdn.com/image/fetch/$s_!0x2T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fa11a2916-f063-4fb1-bb9a-10442b0aae63_2052x434.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">A typical stack overflow message (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/stack-overflow.log">stack-overflow.log</a>)</figcaption></figure></div><p>Some languages (like Scheme, Haskell, and Scala) support <em>Tail Call Elision (TCE)</em>, silently optimizing certain functions so they don&#8217;t overflow the stack.  The implementation above is not amenable to this optimization, and most candidates who jump straight to recursive solutions (or at least, the ones I&#8217;ve asked) can&#8217;t even explain what a &#8220;tail call&#8221; is.  (The point isn&#8217;t that engineers should know about TCE, but that we shouldn&#8217;t write code that crashes in the absence of particular optimizations.)</p><p>Linear (O&#8347;(1)) recursion is exactly the sort of thing that works fine in test code, but blows up in production.  <strong>Do not recurse in production code unless you have a good reason.</strong>  Figuring out whether my team will have to explain things like this to new hires is part of the reason I still ask these clich&#233;d, boring questions.</p><p>The obvious implementation I would expect most juniors to write&#8212;and I swear, they used to do so&#8212;is a for-loop:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0TaK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0TaK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png 424w, https://substackcdn.com/image/fetch/$s_!0TaK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png 848w, https://substackcdn.com/image/fetch/$s_!0TaK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png 1272w, https://substackcdn.com/image/fetch/$s_!0TaK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0TaK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png" width="1456" height="441" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:441,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:145565,&quot;alt&quot;:&quot;fn factorial_loop(n: u64) -> u64 {     let mut result = 1;     for i in 2..=n {         result *= i;     }     result }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn factorial_loop(n: u64) -> u64 {     let mut result = 1;     for i in 2..=n {         result *= i;     }     result }" title="fn factorial_loop(n: u64) -> u64 {     let mut result = 1;     for i in 2..=n {         result *= i;     }     result }" srcset="https://substackcdn.com/image/fetch/$s_!0TaK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png 424w, https://substackcdn.com/image/fetch/$s_!0TaK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png 848w, https://substackcdn.com/image/fetch/$s_!0TaK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.png 1272w, https://substackcdn.com/image/fetch/$s_!0TaK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd9df4d-ea17-45f6-b87e-a6228a44c8d9_3064x928.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">Looping factorial function: O&#8347;(1)O&#8348;(N) (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/factorial_loop.rs">factorial_loop.rs</a>)</figcaption></figure></div><p>A plain old loop is absolutely fine for something like factorial.  A more sophisticated approach would be to delegate most of the work to a standard library function:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6xth!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6xth!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png 424w, https://substackcdn.com/image/fetch/$s_!6xth!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png 848w, https://substackcdn.com/image/fetch/$s_!6xth!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png 1272w, https://substackcdn.com/image/fetch/$s_!6xth!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6xth!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png" width="1456" height="190" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:190,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:86145,&quot;alt&quot;:&quot;fn factorial_product(n: u64) -> u64 {     (2..=n).product() }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn factorial_product(n: u64) -> u64 {     (2..=n).product() }" title="fn factorial_product(n: u64) -> u64 {     (2..=n).product() }" srcset="https://substackcdn.com/image/fetch/$s_!6xth!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png 424w, https://substackcdn.com/image/fetch/$s_!6xth!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png 848w, https://substackcdn.com/image/fetch/$s_!6xth!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png 1272w, https://substackcdn.com/image/fetch/$s_!6xth!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F47bccc3a-7ca9-48fb-8e82-ae9428c1c8f5_3072x400.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Factorial as a product of 1..=n: O&#8347;(1)O&#8348;(N) (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/factorial_product.rs">factorial_product.rs</a>)</figcaption></figure></div><p>Yet another option is a look-up table of precomputed values:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Lcn4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Lcn4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png 424w, https://substackcdn.com/image/fetch/$s_!Lcn4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png 848w, https://substackcdn.com/image/fetch/$s_!Lcn4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png 1272w, https://substackcdn.com/image/fetch/$s_!Lcn4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Lcn4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png" width="1456" height="690" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:690,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:330747,&quot;alt&quot;:&quot;const FACTORIALS: [u64; 21] = [     1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880,     3628800, 39916800, 479001600, 6227020800,     87178291200, 1307674368000, 20922789888000,     355687428096000, 6402373705728000,     121645100408832000, 2432902008176640000, ];  fn factorial_table(n: u64) -> u64 {     FACTORIALS[n as usize] }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="const FACTORIALS: [u64; 21] = [     1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880,     3628800, 39916800, 479001600, 6227020800,     87178291200, 1307674368000, 20922789888000,     355687428096000, 6402373705728000,     121645100408832000, 2432902008176640000, ];  fn factorial_table(n: u64) -> u64 {     FACTORIALS[n as usize] }" title="const FACTORIALS: [u64; 21] = [     1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880,     3628800, 39916800, 479001600, 6227020800,     87178291200, 1307674368000, 20922789888000,     355687428096000, 6402373705728000,     121645100408832000, 2432902008176640000, ];  fn factorial_table(n: u64) -> u64 {     FACTORIALS[n as usize] }" srcset="https://substackcdn.com/image/fetch/$s_!Lcn4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png 424w, https://substackcdn.com/image/fetch/$s_!Lcn4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png 848w, https://substackcdn.com/image/fetch/$s_!Lcn4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.png 1272w, https://substackcdn.com/image/fetch/$s_!Lcn4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1e6460c-c8bf-48d3-9cd1-999cedce550f_3072x1456.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">Factorial as an array of precomputed values: O&#8347;(N)O&#8348;(1) (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/factorial_table.rs">factorial_table.rs</a>)</figcaption></figure></div><p>None of these solutions is liable to blow the call stack, and all of them have better complexity than the recursive solution.  These principles aren&#8217;t specific to factorial, either:  <strong>If you want to be a professional computer programmer, you have to be able to write a for-loop.  </strong>Don&#8217;t get any fancier than that <em>unless you can explain your reasons for doing so.</em></p><h2>Fibonacci</h2><p>The reason I ask Fibonacci, even if someone nails factorial, is that efficient implementation requires a translation from the problem domain to the solution domain.  That&#8217;s something a candidate will do easily if (and only if) they&#8217;re already in the habit.</p><p>The Fibonacci sequence, as a mathematical object, is defined recursively:</p><pre><code>fib(0) = 0
fib(1) = 1
fib(n) = fib(n - 2) + fib(n - 1)</code></pre><p>A naive implementation looks 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_!vvWw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vvWw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png 424w, https://substackcdn.com/image/fetch/$s_!vvWw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png 848w, https://substackcdn.com/image/fetch/$s_!vvWw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png 1272w, https://substackcdn.com/image/fetch/$s_!vvWw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vvWw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png" width="1456" height="452" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:452,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:135778,&quot;alt&quot;:&quot;fn fib_naive(n: u64) -> u64 {     if n < 2 {         n     } else {         fib_naive(n - 2) + fib_naive(n - 1)     } }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn fib_naive(n: u64) -> u64 {     if n < 2 {         n     } else {         fib_naive(n - 2) + fib_naive(n - 1)     } }" title="fn fib_naive(n: u64) -> u64 {     if n < 2 {         n     } else {         fib_naive(n - 2) + fib_naive(n - 1)     } }" srcset="https://substackcdn.com/image/fetch/$s_!vvWw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png 424w, https://substackcdn.com/image/fetch/$s_!vvWw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png 848w, https://substackcdn.com/image/fetch/$s_!vvWw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.png 1272w, https://substackcdn.com/image/fetch/$s_!vvWw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F77ec6bd2-347f-4d63-a977-1607e1e36701_3034x942.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">An expensive way to find the Nth Fibonacci number: O&#8347;(N)O&#8348;(2&#7482;) (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/fib_naive.rs">fib_naive.rs</a>)</figcaption></figure></div><p>Aside from the overflow issues we already discussed in the context of factorials, this Fibonacci function has a severe scalability problem in the form of exponential time complexity.  This is another great example of something that works fine in tests, but can cause production outages in the real world.  Exponential isn&#8217;t quite as bad as factorial, but it&#8217;s bad enough to ruin your day.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ybou!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ybou!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png 424w, https://substackcdn.com/image/fetch/$s_!Ybou!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png 848w, https://substackcdn.com/image/fetch/$s_!Ybou!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png 1272w, https://substackcdn.com/image/fetch/$s_!Ybou!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ybou!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png" width="1456" height="517" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:517,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:265201,&quot;alt&quot;:&quot;fn main() {     for n in [10, 20, 30, 40, 50, 60] {         let now = std::time::Instant::now();         let val = fib_naive(n);         let secs = now.elapsed().as_secs_f64();         println!(\&quot;{secs:20.8}s fib({n}) = {val}\&quot;);     } }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn main() {     for n in [10, 20, 30, 40, 50, 60] {         let now = std::time::Instant::now();         let val = fib_naive(n);         let secs = now.elapsed().as_secs_f64();         println!(&quot;{secs:20.8}s fib({n}) = {val}&quot;);     } }" title="fn main() {     for n in [10, 20, 30, 40, 50, 60] {         let now = std::time::Instant::now();         let val = fib_naive(n);         let secs = now.elapsed().as_secs_f64();         println!(&quot;{secs:20.8}s fib({n}) = {val}&quot;);     } }" srcset="https://substackcdn.com/image/fetch/$s_!Ybou!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png 424w, https://substackcdn.com/image/fetch/$s_!Ybou!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png 848w, https://substackcdn.com/image/fetch/$s_!Ybou!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.png 1272w, https://substackcdn.com/image/fetch/$s_!Ybou!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F45912958-aeb4-465c-879a-2b2b2338e7d1_3016x1070.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">Benchmarking our naive Fibonacci function (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/benchmark.rs">benchmark.rs</a>)</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rbip!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rbip!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png 424w, https://substackcdn.com/image/fetch/$s_!rbip!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png 848w, https://substackcdn.com/image/fetch/$s_!rbip!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png 1272w, https://substackcdn.com/image/fetch/$s_!rbip!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rbip!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png" width="1456" height="456" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:261740,&quot;alt&quot;:&quot;$ cargo run --quiet --release --bin fib_naive           0.00000040s fib(10) = 55           0.00003692s fib(20) = 6765           0.00405865s fib(30) = 832040           0.27553082s fib(40) = 102334155          34.14185397s fib(50) = 12586269025        4163.54114702s fib(60) = 1548008755920&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="$ cargo run --quiet --release --bin fib_naive           0.00000040s fib(10) = 55           0.00003692s fib(20) = 6765           0.00405865s fib(30) = 832040           0.27553082s fib(40) = 102334155          34.14185397s fib(50) = 12586269025        4163.54114702s fib(60) = 1548008755920" title="$ cargo run --quiet --release --bin fib_naive           0.00000040s fib(10) = 55           0.00003692s fib(20) = 6765           0.00405865s fib(30) = 832040           0.27553082s fib(40) = 102334155          34.14185397s fib(50) = 12586269025        4163.54114702s fib(60) = 1548008755920" srcset="https://substackcdn.com/image/fetch/$s_!rbip!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png 424w, https://substackcdn.com/image/fetch/$s_!rbip!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png 848w, https://substackcdn.com/image/fetch/$s_!rbip!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.png 1272w, https://substackcdn.com/image/fetch/$s_!rbip!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0c63ab39-56bb-41e5-8d0e-bb31cbc38b1a_3036x950.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">Exponential complexity can ruin your day.  (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/benchmark.log">benchmark.log</a>)</figcaption></figure></div><p>The complexity here isn&#8217;t due to recursion per se, but to a misunderstanding of how we should translate inductive definitions like fib(n) into computer programs where time and space actually matter.</p><blockquote><p>So many good ideas are never heard from again once they embark in a voyage on the semantic gulf.<br><br>&#8212;Alan Perlis, <em><a href="http://www.cs.yale.edu/homes/perlis-alan/quotes.html">Epigrams in Programming</a></em></p></blockquote><p>The first step is to identify the <em>state</em> that must be passed from one iteration to the next; in other words, the signature of the recursive function.  For Fibonacci, the state is the most recent two results, and the number of iterations remaining.  Here&#8217;s a linear complexity (tail-)recursive Fibonacci implementation:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!y8SL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!y8SL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png 424w, https://substackcdn.com/image/fetch/$s_!y8SL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png 848w, https://substackcdn.com/image/fetch/$s_!y8SL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png 1272w, https://substackcdn.com/image/fetch/$s_!y8SL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!y8SL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png" width="1456" height="580" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:580,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:193489,&quot;alt&quot;:&quot;fn fibonacci_rec(n: u64) -> u64 {     fn imp(a: u64, b: u64, m: u64) -> u64 {         match m {             0 => a,             _ => imp(b, a + b, m - 1),         }     }     imp(0, 1, n) }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn fibonacci_rec(n: u64) -> u64 {     fn imp(a: u64, b: u64, m: u64) -> u64 {         match m {             0 => a,             _ => imp(b, a + b, m - 1),         }     }     imp(0, 1, n) }" title="fn fibonacci_rec(n: u64) -> u64 {     fn imp(a: u64, b: u64, m: u64) -> u64 {         match m {             0 => a,             _ => imp(b, a + b, m - 1),         }     }     imp(0, 1, n) }" srcset="https://substackcdn.com/image/fetch/$s_!y8SL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png 424w, https://substackcdn.com/image/fetch/$s_!y8SL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png 848w, https://substackcdn.com/image/fetch/$s_!y8SL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.png 1272w, https://substackcdn.com/image/fetch/$s_!y8SL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26006f8d-f4fc-40fe-ac58-b6170e1b4d57_2986x1190.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">Linear-time recursive Fibonacci function: O&#8347;(N)O&#8348;(N) (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/fibonacci_rec.rs">fibonacci_rec.rs</a>)</figcaption></figure></div><p>When candidates who&#8217;ve implemented the naive solution above are asked to address the exponential complexity, they always&#8212;and I mean, <em>always</em>&#8212;try adding a cache, effectively memoizing the function.  That gets us back down to linear space and time (O&#8347;(N)O&#8348;(N)), but a simple loop would run in <em>constant</em> space and linear time:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KWHg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KWHg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png 424w, https://substackcdn.com/image/fetch/$s_!KWHg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png 848w, https://substackcdn.com/image/fetch/$s_!KWHg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png 1272w, https://substackcdn.com/image/fetch/$s_!KWHg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KWHg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png" width="1456" height="443" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/af334856-3322-40d5-881a-6b10885d3a85_3020x918.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:443,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:147880,&quot;alt&quot;:&quot;fn fibonacci_loop(n: u64) -> u64 {     let (mut a, mut b) = (0, 1);     for _ in 0..n {         (a, b) = (b, a + b);     }     a }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn fibonacci_loop(n: u64) -> u64 {     let (mut a, mut b) = (0, 1);     for _ in 0..n {         (a, b) = (b, a + b);     }     a }" title="fn fibonacci_loop(n: u64) -> u64 {     let (mut a, mut b) = (0, 1);     for _ in 0..n {         (a, b) = (b, a + b);     }     a }" srcset="https://substackcdn.com/image/fetch/$s_!KWHg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png 424w, https://substackcdn.com/image/fetch/$s_!KWHg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png 848w, https://substackcdn.com/image/fetch/$s_!KWHg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.png 1272w, https://substackcdn.com/image/fetch/$s_!KWHg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Faf334856-3322-40d5-881a-6b10885d3a85_3020x918.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">Nth Fibonacci via for-loop: O&#8347;(1)O&#8348;(N) (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/fibonacci_loop.rs">fibonacci_loop.rs</a>)</figcaption></figure></div><h2>Higher Order Functions</h2><blockquote><p>Students of Functional Programming spend their first year learning to recurse, and their second year learning not to.</p><p>&#8212;Unknown</p></blockquote><p>Much as factorial can be expressed as the product of a range of integers, a more sophisticated Fibonacci implementation might use a Higher Order Function (HOF) like <a href="https://doc.rust-lang.org/std/iter/fn.successors.html">successors</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_!rL5t!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rL5t!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png 424w, https://substackcdn.com/image/fetch/$s_!rL5t!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png 848w, https://substackcdn.com/image/fetch/$s_!rL5t!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png 1272w, https://substackcdn.com/image/fetch/$s_!rL5t!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rL5t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png" width="1456" height="417" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:417,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:188094,&quot;alt&quot;:&quot;use std::iter::successors;  fn fibonacci_hof(n: u64) -> u64 {     successors(Some((0, 1)), |&amp;(a, b)| Some((b, a + b)))         .nth(n as usize)         .expect(\&quot;Fibonacci sequence should be inexhaustible\&quot;)         .0 }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="use std::iter::successors;  fn fibonacci_hof(n: u64) -> u64 {     successors(Some((0, 1)), |&amp;(a, b)| Some((b, a + b)))         .nth(n as usize)         .expect(&quot;Fibonacci sequence should be inexhaustible&quot;)         .0 }" title="use std::iter::successors;  fn fibonacci_hof(n: u64) -> u64 {     successors(Some((0, 1)), |&amp;(a, b)| Some((b, a + b)))         .nth(n as usize)         .expect(&quot;Fibonacci sequence should be inexhaustible&quot;)         .0 }" srcset="https://substackcdn.com/image/fetch/$s_!rL5t!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png 424w, https://substackcdn.com/image/fetch/$s_!rL5t!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png 848w, https://substackcdn.com/image/fetch/$s_!rL5t!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.png 1272w, https://substackcdn.com/image/fetch/$s_!rL5t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7a1aa1a8-9122-44e0-9a0c-e6ae286eec94_2946x844.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">Fibonaccis from a Higher Order Function (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/fibonacci_hof.rs">fibonacci_hof.rs</a>)</figcaption></figure></div><p>Using HOFs instead of hand-rolled loops is a pretty strong indicator that this ain&#8217;t the author&#8217;s first rodeo.  (Similar HOFs exist in most languages, or else can be easily implemented using iterators or <a href="https://nested.substack.com/p/the-rise-of-coroutines">generator functions</a>.  For example, what Rust calls &#8216;successors,&#8217; <a href="http://zvon.org/other/haskell/Outputprelude/iterate_f.html">Haskell</a> and <a href="https://clojuredocs.org/clojure.core/iterate">Clojure</a> both call &#8216;iterate.&#8217;)</p><p>Higher order functions are often even better than loops, for two main reasons:</p><ol><li><p>They express your intent directly.  A loop that processes elements of one array and adds them to another is rarely as clear as a call to <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map">map</a> <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map">and/or</a> <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter">filter</a> (or an equivalent <em>comprehension</em> in <a href="https://wiki.haskell.org/List_comprehension">Haskell</a>, <a href="https://docs.scala-lang.org/tour/for-comprehensions.html">Scala</a>, or <a href="https://docs.python.org/3/howto/functional.html#generator-expressions-and-list-comprehensions">Python</a>).  Such direct expression of intent makes the code easier to work with for both humans and compilers.</p><blockquote><p>In some cases for_each may also be faster than a loop, because it will use internal iteration on adapters like Chain.<br>&#8212;Trait <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.for_each">std::iter::Iterator</a></p></blockquote></li><li><p>They&#8217;re more composable, enabling you to share low-level functionality across functions.</p></li></ol><p>Suppose we want to know how many Fibonacci numbers are below a given value. If we start from the &#8216;fibonacci_loop&#8217; function above, there&#8217;s no good way to factor out the loop logic itself.  We&#8217;re stuck writing a completely new, though conceptually very similar loop.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Dutw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Dutw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png 424w, https://substackcdn.com/image/fetch/$s_!Dutw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png 848w, https://substackcdn.com/image/fetch/$s_!Dutw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png 1272w, https://substackcdn.com/image/fetch/$s_!Dutw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Dutw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png" width="1456" height="564" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:564,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:196331,&quot;alt&quot;:&quot;fn fibonacci_loop_count_below(end: u64) -> u64 {     let mut n = 0;     let (mut a, mut b) = (0, 1);     while a < end {         n += 1;         (a, b) = (b, a + b);     }     n }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn fibonacci_loop_count_below(end: u64) -> u64 {     let mut n = 0;     let (mut a, mut b) = (0, 1);     while a < end {         n += 1;         (a, b) = (b, a + b);     }     n }" title="fn fibonacci_loop_count_below(end: u64) -> u64 {     let mut n = 0;     let (mut a, mut b) = (0, 1);     while a < end {         n += 1;         (a, b) = (b, a + b);     }     n }" srcset="https://substackcdn.com/image/fetch/$s_!Dutw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png 424w, https://substackcdn.com/image/fetch/$s_!Dutw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png 848w, https://substackcdn.com/image/fetch/$s_!Dutw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.png 1272w, https://substackcdn.com/image/fetch/$s_!Dutw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe502c3b9-056c-4280-a4fd-96372529b54e_3046x1180.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">Each new loop entails redundant logic (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/fibonacci_loop_count_below.rs">fibonacci_loop_count_below.rs</a>)</figcaption></figure></div><p>With the HOF based version, though, we can easily factor out not only the iteration, but the iteration state; in this case, keeping the value &#8216;b&#8217; out of the caller&#8217;s scope.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GXNi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GXNi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png 424w, https://substackcdn.com/image/fetch/$s_!GXNi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png 848w, https://substackcdn.com/image/fetch/$s_!GXNi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!GXNi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GXNi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png" width="1456" height="722" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:722,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:348929,&quot;alt&quot;:&quot;fn fibonaccis() -> impl Iterator<Item = u64> {     successors(Some((0, 1)), |&amp;(a, b)| Some((b, a + b)))         .map(|(a, _)| a) }  fn fibonacci_hof(n: u64) -> u64 {     fibonaccis()         .nth(n as usize)         .expect(\&quot;Fibonacci sequence should be inexhaustible\&quot;) }  fn fibonacci_hof_count_below(end: u64) -> u64 {     fibonaccis().take_while(|&amp;n| n < end).count() as u64 }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn fibonaccis() -> impl Iterator<Item = u64> {     successors(Some((0, 1)), |&amp;(a, b)| Some((b, a + b)))         .map(|(a, _)| a) }  fn fibonacci_hof(n: u64) -> u64 {     fibonaccis()         .nth(n as usize)         .expect(&quot;Fibonacci sequence should be inexhaustible&quot;) }  fn fibonacci_hof_count_below(end: u64) -> u64 {     fibonaccis().take_while(|&amp;n| n < end).count() as u64 }" title="fn fibonaccis() -> impl Iterator<Item = u64> {     successors(Some((0, 1)), |&amp;(a, b)| Some((b, a + b)))         .map(|(a, _)| a) }  fn fibonacci_hof(n: u64) -> u64 {     fibonaccis()         .nth(n as usize)         .expect(&quot;Fibonacci sequence should be inexhaustible&quot;) }  fn fibonacci_hof_count_below(end: u64) -> u64 {     fibonaccis().take_while(|&amp;n| n < end).count() as u64 }" srcset="https://substackcdn.com/image/fetch/$s_!GXNi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png 424w, https://substackcdn.com/image/fetch/$s_!GXNi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png 848w, https://substackcdn.com/image/fetch/$s_!GXNi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!GXNi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b7ea78-7d4b-43e2-8ad6-fa792acafbe2_3008x1492.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">Three functions concisely sharing functionality (<a href="https://raw.githubusercontent.com/jeffs/nested/main/recursion/snip/fibonacci_hof_count_below.rs">fibonacci_hof_count_below.rs</a>)</figcaption></figure></div><p>Some technical leaders take the preference for HOFs <a href="https://www.youtube.com/watch?v=W2tWOdzgXHA">to the extreme</a>.  Others positively fetishize raw loops.  My own experience is that HOFs are <em>almost</em> always the best option.  They scale better than loops, both within individual programs, and as library features.  They also tend to go hand in hand with short variable names, and let you mentally separate mechanics from semantics; e.g., separating loop logic (I have a list, and want the Nth item) from the business domain (I&#8217;m implementing a Dutch auction, and need the second-highest bid).</p><p>But, the glue required to match HOF callback signatures&#8212;for example, in our HOF-based Fibonacci functions above, the Some() and .expect() calls&#8212;is a pain for small examples.  It&#8217;s often best to start with a short hand-written loop, but replace it with a HOF at the very first sign of complexity.</p><h2>OK, fine, recursion is <em>occasionally</em> useful</h2><p>When, if ever, should you use recursion?  Here&#8217;s a <a href="https://gist.github.com/jeffs/98f5e9f77a77340b98b0">fancy Fibonacci function</a> I wrote a long time ago that recurses instead of looping.  I felt OK writing that because it runs in logarithmic, rather than linear, time and space (O&#8347;(log N)O&#8348;(log N)).  Recursion is also a convenient way to get a data stack for free, if you&#8217;re willing to abuse the call stack to hold data; for example, when traversing a binary tree.  Even then, it&#8217;s usually better to use an explicit stack.</p><p><em>&#128161; The only difference between depth-first and breadth-first search is whether newly encountered nodes are added to a stack (LIFO) or a queue (FIFO).</em></p><p>If you know what you&#8217;re doing and why, then it&#8217;s OK for recursion to be one of the tools in your toolbox.  It is not, however, a good idea to recurse where a loop or HOF would suffice merely because recursion is what the cool kids seem to be doing.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Graceful Degradation]]></title><description><![CDATA[Getting things right when things go wrong.]]></description><link>https://nested.substack.com/p/graceful-degradation</link><guid isPermaLink="false">https://nested.substack.com/p/graceful-degradation</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 09 Sep 2022 06:31:29 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/fbca3bfd-24ba-4e9d-a684-91a08e26ca94_680x396.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The irony of grace is that, even though we associate it with perfection and elegance, it is truly apparent only when things have gone horribly wrong.  Points of light become obvious only in darkness, and charity is most valuable when the need is desperate.  The principle of being at our best when things are at their worst is manifest in the system design principle of <em>graceful degradation</em>.</p><blockquote><p>The degree of civilization in a society can be judged by entering its prisons.</p><p>&#8212;unknown; often <a href="https://lareviewofbooks.org/article/dostoyevsky-misprisioned-the-house-of-the-dead-and-american-prison-literature/">misattributed</a> to Fyodor Dostoyevsky</p></blockquote><p>The most obvious form of system degradation is catastrophic failure.  Conventional wisdom is that when a computer program cannot serve its intended purpose, it should fail fast and loudly.  The aptly named .NET <a href="https://docs.microsoft.com/en-us/dotnet/api/system.environment.failfast?view=net-6.0">Environment.FailFast</a> method, for instance, &#8220;immediately terminates a process after writing a message.&#8221;  We&#8217;ve previously discussed why <a href="https://nested.substack.com/p/fail-fast">Fail-fast</a> isn&#8217;t always the best strategy; but when a program absolutely must crash, it should at least crash well.</p><blockquote><p>GEOFFREY: Why, you chivalric fool&#8212;as if the way one fell down mattered.</p><p>RICHARD: When the fall is all there is, it matters.</p><p>&#8212;James Goldman, <em><a href="https://www.youtube.com/watch?v=lKGPiecEEbA">The Lion in Winter</a></em></p></blockquote><p>Graceful fail-fast degradation is epitomized by the &#8216;expect&#8217; method of Rust options.  <a href="https://doc.rust-lang.org/std/option/index.html">Options</a> are containers that can either be empty, or hold a single value.  The <a href="https://doc.rust-lang.org/std/option/enum.Option.html#method.expect">expect</a> and <a href="https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap">unwrap</a> methods both return the contained value, or else print an error message and terminate the program with bad status if the container is empty.  The only difference between &#8216;expect&#8217; and &#8216;unwrap&#8217; is that &#8216;expect&#8217; lets you customize the error message.  <strong>Good error messages are grace incarnate.  </strong>Rust programmers should always prefer &#8216;expect&#8217; to &#8216;unwrap,&#8217; for two reasons:</p><ol><li><p>No matter how sure you are that a particular operation won&#8217;t fail&#8230; what if it does?  The moment the impossible happens is precisely when a helping hand would be most appreciated.</p><blockquote><p>We place absolute confidence in the Titanic.  We believe the boat is unsinkable.  &#8212;<a href="https://www.historyonthenet.com/the-titanic-why-did-people-believe-titanic-was-unsinkable">White Star Line Vice President P.A.S. Franklin</a></p></blockquote><blockquote><p>The Titanic actually carried just 20 lifeboats . . . This was far too few for the number of people aboard.  &#8212;<a href="https://titanicfacts.net/titanic-lifeboats/">Titanic Facts</a></p></blockquote><p>Believing your ship unsinkable is no excuse for not providing enough lifeboats.</p></li><li><p>Well-written error messages make code easier to read, because they explain why the author believes a particular state is unreachable, or at least what the relevant values represent.  Good inline error messages are among the kindest mercies you can bestow on anyone who would maintain or extend your code, even if no end user ever sees them.</p></li></ol><p>A more common form of graceful degradation is ensuring that media remain accessible to users who have (<a href="https://medium.com/valtech-design/inclusive-design-dd4e03f82094#c5a7">permanent, temporary, or situational</a>) disabilities.  Alternate text for online images, closed captions and audio descriptions for movies, and colorblind-friendly visual distinctions (such as consistent top-down ordering of red, yellow, and green traffic lights) are all forms of graceful degradation.  At their best, such &#8220;alternate&#8221; forms of communication are first-class aspects of design in their own right.  While a blind moviegoer may never see the images on screen, most sighted viewers will never see the closed captions or hear the audio descriptions that may be the most entertaining parts of the show.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uUNy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uUNy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif 424w, https://substackcdn.com/image/fetch/$s_!uUNy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif 848w, https://substackcdn.com/image/fetch/$s_!uUNy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif 1272w, https://substackcdn.com/image/fetch/$s_!uUNy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uUNy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif" width="320" height="241.63265306122446" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/dbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:185,&quot;width&quot;:245,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:677045,&quot;alt&quot;:&quot;A Star Trek scene in which Spock is crying at his desk, captioned \&quot;(sobbing mathematically).\&quot;  This is from season 1, episode 4 of The Original Series (TOS), called The Naked Time.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A Star Trek scene in which Spock is crying at his desk, captioned &quot;(sobbing mathematically).&quot;  This is from season 1, episode 4 of The Original Series (TOS), called The Naked Time." title="A Star Trek scene in which Spock is crying at his desk, captioned &quot;(sobbing mathematically).&quot;  This is from season 1, episode 4 of The Original Series (TOS), called The Naked Time." srcset="https://substackcdn.com/image/fetch/$s_!uUNy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif 424w, https://substackcdn.com/image/fetch/$s_!uUNy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif 848w, https://substackcdn.com/image/fetch/$s_!uUNy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif 1272w, https://substackcdn.com/image/fetch/$s_!uUNy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe94a89-d6fa-44fc-9a20-f5a61ce027c4_245x185.gif 1456w" sizes="100vw" loading="lazy" fetchpriority="high"></picture><div></div></div></a></figure></div><p>No real-world system is ever infallible.  Something as simple as providing a decent error message can make a big difference to users and developers alike.  Getting things right when things go wrong is a mark of craftsmanship that distinguishes good engineers and designers from great ones.</p>]]></content:encoded></item><item><title><![CDATA[Code Review]]></title><description><![CDATA[Commandments for the ancient rite of Code Review.]]></description><link>https://nested.substack.com/p/code-review</link><guid isPermaLink="false">https://nested.substack.com/p/code-review</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 02 Sep 2022 17:48:24 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8dea7f03-3dc1-42bf-bba5-78c56f0dc8c2_2121x1414.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most software engineers practice the ancient rite of Code Review, a humbling experience in which we submit our work to each other&#8217;s judgement. Skillful code review not only improves the code, but edifies the participants, both reviewer and reviewed. It&#8217;s one of the most effective ways to transform a group of individuals into a team working collaboratively toward shared goals. When done badly, code review instead becomes a recipe for shame, anger, and weakening of the codebase through loss of conceptual integrity.</p><blockquote><p>Don&#8217;t train alone. It only embeds your errors.</p><p>&#8212;Vesemir, <a href="https://www.youtube.com/watch?v=g1sk8KesUN8">The Witcher 3: Wild Hunt</a></p></blockquote><blockquote><p>Too many cooks spoil the broth.</p><p>&#8212;Anonymous</p></blockquote><p>Let&#8217;s talk about (how to avoid) bad code reviews.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p><strong>Authors:</strong></p><ol><li><p>Thou shalt not send huge change sets for review. Yea, verily, &#8216;tis far better to submit one hundred Pull Requests of ten lines apiece, a few at a time, than to eventually plop out a single PR for a thousand-line code change. If thou canst not figure out how to present thy changes as a series of small, independently reviewable pieces, thou shouldst brainstorm with a colleague, and invest thy faith in the power of <a href="https://nested.substack.com/p/simpler-bricks-and-stronger-walls">factoring</a>.</p></li><li><p>Thou shalt not send multiple, simultaneous PRs that depend on each other, as any change to one PR may invalidate others. Even if thou dost not mind manually synchronizing several PRs, thou layest a gross burden upon the reviewer, who hath not thy understanding of the interrelated change sets thou proposest, nor desireth to make busy-work for ye. Have a heart, give the reviewer a break, and please, never submit a PR-storm.</p></li><li><p>Thou shalt not send copy pasta for review. Thou not only irritatest the reviewer on general principles, but obligest them to review the same code again and again, and puttest them in the awkward position of leaving the same comment at each location.</p></li></ol><p><strong>Reviewers:</strong></p><ol><li><p>Thou shalt be responsive. Thou shalt not leave PRs unattended for days or weeks.</p></li><li><p>Thou shalt not let the perfect be the enemy of the good. Mere room for improvement is not sufficient reason to delay merge. Improvements can be made in later PRs; and if thou feelest strongly enough, thou canst darned well send such improvement PRs thyself, <em>after</em> merging the original. The question thou shouldst ask thyself is not &#8220;could this be better?&#8221; but &#8220;will this make us better?&#8221; Will the incoming change, as it stands, be a net positive? If so, thou shalt merge, and that right soon.</p></li><li><p>Thou shalt not delay merges in the name of bike-shedding. Thou art a lookout, not a gatekeeper. Thou art a teammate, not a fashionista. Thou art not the arbiter of good taste. Support and encouragement are more effective than exclusion. Water the flowers, and let the weeds die on their own.</p></li><li><p>Thou shalt be gentle. When thou must request changes (or even reject entire PRs!), no matter the reasons, thou shalt remember thy humanity, and that of they teammates. If thou believest that people should learn not to take professional feedback personally, then thou hast yet much to learn thyself. Disrespecting the work disrespects the worker. Thou hast been invested with power, and shalt wield it with compassion.</p></li></ol><p>It would be a missed opportunity to think of code reviews as solely quality control. I&#8217;ve learned at least as much from reviewing other people&#8217;s work as from their reviews of my own. As a manager, I&#8217;ve found code reviews an invaluable way to break down silos, ensuring that the code is not &#8220;owned&#8221; by any single individual without whom it would be unmaintainable.</p><p>A final note is that code reviews are often worth following even if you&#8217;re not an active participant. As workplaces have become remote, and communication increasingly asynchronous, reviews have gained importance as a way for engineers to coordinate their activity. If you want to see how your developers <em>actually</em> work together, look no further than their code reviews.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Parallax]]></title><description><![CDATA[Movement, in absolute terms, is an illusion.&#160; This principle applies to all progress.]]></description><link>https://nested.substack.com/p/parallax</link><guid isPermaLink="false">https://nested.substack.com/p/parallax</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Thu, 18 Aug 2022 22:54:00 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/5e936368-3dc1-4233-9b4b-27fb2230b2ab_2121x1414.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Deeply Nested will be on vacation next week, returning on September 2.  Please feel free to revisit a recent technical (<a href="https://nested.substack.com/p/traversal-order">Traversal Order</a>, <a href="https://nested.substack.com/p/safety">Safety</a>) or non-technical (<a href="https://nested.substack.com/p/swimming-upstream">Swimming Upstream</a>, <a href="https://nested.substack.com/p/wasting-time">Wasting Time</a>) post, and remember you have access to the <a href="https://nested.substack.com/archive">archives</a>.</em></p><div><hr></div><p>Movement, in absolute terms, is an illusion.  Each of us stands at the origin of our own frame of reference, within which we are still.  This principle applies not only to physical movement, but to progress of any kind. </p><blockquote><p>Things fall apart; the centre cannot hold</p><p>&#8212;William Butler Yeats, <em><a href="https://www.poetryfoundation.org/poems/43290/the-second-coming">The Second Coming</a></em></p></blockquote><p>The most facile way to assess our own velocity is relative to whomever or whatever is nearby, yet it is no more meaningful to say we are flying past others than it is to say they are flying past us.  In the moment, it is not always clear which way is forward, and which reverse.</p><blockquote><p>I didn't leave the Democratic Party.  The party left me.</p><p>&#8212;<a href="http://content.time.com/time/specials/packages/article/0,28804,1894529_1894528_1894518,00.html">Ronald Reagan</a></p></blockquote><p>Observing progress relative to big things, rather than close ones&#8212;mountains in the distance, stars in the sky, or the events of the distant past&#8212;is hard, because distance obscures detail.  Ever wonder why it seems like music/movies/media were better in some other decade? It&#8217;s because, in hindsight, the hits seem closer and closer together, even as the interstitial noise is slowly forgotten.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XQ1_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XQ1_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg 424w, https://substackcdn.com/image/fetch/$s_!XQ1_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg 848w, https://substackcdn.com/image/fetch/$s_!XQ1_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!XQ1_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XQ1_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.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;:2608247,&quot;alt&quot;:&quot;Parallel railroad tracks appear to converge in the distance.&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="Parallel railroad tracks appear to converge in the distance." title="Parallel railroad tracks appear to converge in the distance." srcset="https://substackcdn.com/image/fetch/$s_!XQ1_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg 424w, https://substackcdn.com/image/fetch/$s_!XQ1_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg 848w, https://substackcdn.com/image/fetch/$s_!XQ1_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!XQ1_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F10c895fb-58ba-4621-83b4-6c664096e620_2121x1414.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">Perspective can be misleading.</figcaption></figure></div><p>The phenomenon by which objects appear closer to each other the farther they are from us is called <em>perspective</em>.  The related phenomenon by which we seem to move faster relative to nearby objects than to distant ones is called <em>parallax</em>.</p><p><em>&#128161;The <a href="https://astronomy.com/magazine/ask-astro/2020/02/why-is-a-parsec-326-light-years">parsec</a>, an astronomical unit of distance, is an abbreviation of &#8220;parallax second.&#8221;  It is how close another star would have to be to the plane of our orbit around the sun to seem, from our perspective, to have moved through two arcseconds (0.0003% of the way across the sky) in six months.  During that time, we travel nearly 300,000,000 km, yet a parsec is over 30,000,000,000,000 km.  There are no stars so close.</em></p><p>Although we cannot meaningfully assess our progress relative to others, what we <strong>can</strong> determine are changes in our own velocity.  Changes in velocity are called <em>acceleration</em>, and like all derivatives with respect to time, acceleration is fundamentally an instantaneous property:  We know, in any given moment, whether we are speeding up or slowing down.  The sensation is often visceral.</p><p>If there is a lesson to be learned from all these observations, it is that progress is an illusory thing.  Measuring progress in a changing world, or comparing our own progress to that of other people&#8212;or worse yet, other people&#8217;s progress relative to ours&#8212;is a fool&#8217;s errand.  The question we can<em> </em>answer is whether we&#8217;re doing better than we were yesterday.  Whether &#8220;doing better&#8221; means moving faster or slower&#8230; well, that&#8217;s up to you.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Traversal Order]]></title><description><![CDATA[Dividing and Conquering unordered collections is messy business.]]></description><link>https://nested.substack.com/p/traversal-order</link><guid isPermaLink="false">https://nested.substack.com/p/traversal-order</guid><dc:creator><![CDATA[Jeff Schwab]]></dc:creator><pubDate>Fri, 12 Aug 2022 07:59:41 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/07a5d58c-8382-4518-a32e-ba0f323be59c_2120x1414.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Click the code images below to zoom, or click their captions for plain text.</em></p><div><hr></div><p>In a perfect world, things that shouldn&#8217;t matter wouldn&#8217;t matter. We do not, as you may have noticed, live in such a world.</p><p>One thing that shouldn&#8217;t matter is the traversal order of data structures representing mathematical sets.  Semantically unordered collections (like hash sets and database tables) come up frequently in software development, but they&#8217;re not really amenable to the usual &#8220;Divide and Conquer&#8221; approach.</p><h3>Divide and Conquer and Subtle Interactions</h3><p><em>We once discussed <a href="https://nested.substack.com/p/divide-and-conquer">Divide and Conquer as a Project Management technique</a>.  This time, we&#8217;re discussing it in the context of data processing.</em></p><p>To &#8220;Divide and Conquer&#8221; is to break <em>(Divide)</em> a big problem into smaller ones that we can solve <em>(Conquer)</em> independently.  For example, to add up a bunch of numbers, we can take them two at a time (Divide), and apply our handy binary + operator (Conquer) to get partial results, repeating until we&#8217;ve summed the whole collection:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MEaK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MEaK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png 424w, https://substackcdn.com/image/fetch/$s_!MEaK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png 848w, https://substackcdn.com/image/fetch/$s_!MEaK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png 1272w, https://substackcdn.com/image/fetch/$s_!MEaK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MEaK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png" width="888" height="66" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/5caa16cf-673c-409a-8643-392561d8c77b_888x66.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:66,&quot;width&quot;:888,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:11725,&quot;alt&quot;:&quot;> [1, 2, 3].reduce((a, x) => a + x) 6&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="> [1, 2, 3].reduce((a, x) => a + x) 6" title="> [1, 2, 3].reduce((a, x) => a + x) 6" srcset="https://substackcdn.com/image/fetch/$s_!MEaK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png 424w, https://substackcdn.com/image/fetch/$s_!MEaK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png 848w, https://substackcdn.com/image/fetch/$s_!MEaK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png 1272w, https://substackcdn.com/image/fetch/$s_!MEaK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F5caa16cf-673c-409a-8643-392561d8c77b_888x66.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption"><a href="https://raw.githubusercontent.com/jeffs/nested/main/traversal-order/snip/js-sum.log">js-sum.log</a></figcaption></figure></div><p>Addition is a seductively flexible operation, because it is order agnostic in two important ways.</p><ul><li><p>It&#8217;s <em>associative</em>, meaning it doesn&#8217;t care about the order of application: (1 + 2) + 3 = 1 + (2 + 3).  It doesn&#8217;t matter how we Divide our collection into pairs.</p></li><li><p>It&#8217;s <em>commutative</em>, meaning it doesn&#8217;t care about the order of its operands: 1 + 2 = 2 + 1.  When we Conquer each pair of numbers, it doesn&#8217;t matter which number goes on the left or the right.</p></li></ul><p>As it turns out, though, most Software Engineering is a lot harder than adding up integers.  In fact, much of computer programming entails being surprised to discover, again and again, that seemingly simple things are not so simple after all.  For example, sticking with that handy dandy binary + operator:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hCA8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hCA8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png 424w, https://substackcdn.com/image/fetch/$s_!hCA8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png 848w, https://substackcdn.com/image/fetch/$s_!hCA8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png 1272w, https://substackcdn.com/image/fetch/$s_!hCA8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hCA8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png" width="884" height="196" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/375848ac-535c-4140-9278-be76268b96ff_884x196.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:196,&quot;width&quot;:884,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33962,&quot;alt&quot;:&quot;import sys  e = sys.float_info.epsilon numbers = [e / 3, e / 2, 1] print(sum(numbers))       # 1.0000000000000002 print(sum(set(numbers)))  # 1.0, probably&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="import sys  e = sys.float_info.epsilon numbers = [e / 3, e / 2, 1] print(sum(numbers))       # 1.0000000000000002 print(sum(set(numbers)))  # 1.0, probably" title="import sys  e = sys.float_info.epsilon numbers = [e / 3, e / 2, 1] print(sum(numbers))       # 1.0000000000000002 print(sum(set(numbers)))  # 1.0, probably" srcset="https://substackcdn.com/image/fetch/$s_!hCA8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png 424w, https://substackcdn.com/image/fetch/$s_!hCA8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png 848w, https://substackcdn.com/image/fetch/$s_!hCA8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png 1272w, https://substackcdn.com/image/fetch/$s_!hCA8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F375848ac-535c-4140-9278-be76268b96ff_884x196.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"><a href="https://raw.githubusercontent.com/jeffs/nested/main/traversal-order/snip/floats.py">floats.py</a></figcaption></figure></div><p>Oops!  The sum of a collection of floats depends on traversal order, because floating point addition is not associative.  Specifically: Epsilon is the smallest number that can be added to 1.0 without being discarded as a rounding error.  The sum epsilon/3 + epsilon/2 is greater than epsilon; so, if we add the numbers up in their original, sorted order, we&#8217;ve picked up enough &#8220;momentum&#8221; by the time we hit 1 to tip it over to the next representable value.  If we instead sum these numbers in any other order, none of the individual fractions of epsilon is ever big enough to affect the accumulated sum.  United they stand, divided they fall.  <strong>Non-associative operations interact badly with the Divide step of Divide and Conquer dataset processing.</strong></p><p><em>&#128161; Fun fact: Rust doesn&#8217;t allow sets of raw floats, because their comparison semantics are so&#8230; shall we say, irregular?</em></p><p>That dirty double-crossing binary + operator, that we thought was our friend, is also commonly used for concatenation.  Concatenation has the reverse problem of floating point addition: It&#8217;s associative, but not commutative.  In other words, &#8220;Hello&#8221; + &#8220;World&#8221; is not the same as &#8220;World&#8221; + &#8220;Hello&#8221;.  The concatenation of a set thus depends on traversal order.  Concatenation cares which element comes first, but there is no meaningful &#8220;first&#8221; element of an unordered collection.  <strong>Non-commutative operations interact badly with the Conquer step of Divide and Conquer dataset processing.</strong></p><blockquote><p>There&#8217;s no such thing as an original sin.</p><p>&#8212;Elvis Costello, <em><a href="https://www.youtube.com/watch?v=uff0h-zHuao">I&#8217;m Not Angry</a></em></p></blockquote><h3>Flakiness</h3><p>In most languages, hash set traversal order may vary from run to run:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6R5x!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6R5x!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png 424w, https://substackcdn.com/image/fetch/$s_!6R5x!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png 848w, https://substackcdn.com/image/fetch/$s_!6R5x!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png 1272w, https://substackcdn.com/image/fetch/$s_!6R5x!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6R5x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png" width="886" height="172" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:172,&quot;width&quot;:886,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30776,&quot;alt&quot;:&quot;python3 -c 'print({\&quot;Hello\&quot;, \&quot;World\&quot;})' done | sort | uniq -c       5 {'Hello', 'World'}       3 {'World', 'Hello'}&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="python3 -c 'print({&quot;Hello&quot;, &quot;World&quot;})' done | sort | uniq -c       5 {'Hello', 'World'}       3 {'World', 'Hello'}" title="python3 -c 'print({&quot;Hello&quot;, &quot;World&quot;})' done | sort | uniq -c       5 {'Hello', 'World'}       3 {'World', 'Hello'}" srcset="https://substackcdn.com/image/fetch/$s_!6R5x!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png 424w, https://substackcdn.com/image/fetch/$s_!6R5x!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png 848w, https://substackcdn.com/image/fetch/$s_!6R5x!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png 1272w, https://substackcdn.com/image/fetch/$s_!6R5x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0674e06-9f52-47c2-861e-fe5c5acc407e_886x172.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"><a href="https://raw.githubusercontent.com/jeffs/nested/main/traversal-order/snip/py-vary.log">py-vary.log</a></figcaption></figure></div><p>A common consequence is test flakiness.  If you have tests that pass or fail seemingly at random, one likely culprit is a set being reduced by a non-associative or non-commutative function:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!buMw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!buMw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png 424w, https://substackcdn.com/image/fetch/$s_!buMw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png 848w, https://substackcdn.com/image/fetch/$s_!buMw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png 1272w, https://substackcdn.com/image/fetch/$s_!buMw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!buMw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png" width="886" height="170" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:170,&quot;width&quot;:886,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:41529,&quot;alt&quot;:&quot;fn test_flaky() {     let set = HashSet::from([\&quot;Hello\&quot;, \&quot;World\&quot;]);     let vec: Vec<_> = set.into_iter().collect();     assert_eq!(\&quot;Hello World\&quot;, vec.join(\&quot; \&quot;)); // Flaky! }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="fn test_flaky() {     let set = HashSet::from([&quot;Hello&quot;, &quot;World&quot;]);     let vec: Vec<_> = set.into_iter().collect();     assert_eq!(&quot;Hello World&quot;, vec.join(&quot; &quot;)); // Flaky! }" title="fn test_flaky() {     let set = HashSet::from([&quot;Hello&quot;, &quot;World&quot;]);     let vec: Vec<_> = set.into_iter().collect();     assert_eq!(&quot;Hello World&quot;, vec.join(&quot; &quot;)); // Flaky! }" srcset="https://substackcdn.com/image/fetch/$s_!buMw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png 424w, https://substackcdn.com/image/fetch/$s_!buMw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png 848w, https://substackcdn.com/image/fetch/$s_!buMw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png 1272w, https://substackcdn.com/image/fetch/$s_!buMw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26bf1bd6-9720-4682-b70a-9ef4c07dfebc_886x170.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"><a href="https://raw.githubusercontent.com/jeffs/nested/main/traversal-order/snip/flaky.rs">flaky.rs</a></figcaption></figure></div><p>To work around this kind of flakiness, some implementations guarantee consistent traversal.  In JavaScript, for example, iteration recapitulates insertion order:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NGKJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NGKJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png 424w, https://substackcdn.com/image/fetch/$s_!NGKJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png 848w, https://substackcdn.com/image/fetch/$s_!NGKJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png 1272w, https://substackcdn.com/image/fetch/$s_!NGKJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NGKJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png" width="884" height="132" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:132,&quot;width&quot;:884,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30189,&quot;alt&quot;:&quot;> new Set(\&quot;8675309\&quot;) Set(7) { '8', '6', '7', '5', '3', '0', '9' } > new Set(\&quot;9035768\&quot;) Set(7) { '9', '0', '3', '5', '7', '6', '8' }&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="> new Set(&quot;8675309&quot;) Set(7) { '8', '6', '7', '5', '3', '0', '9' } > new Set(&quot;9035768&quot;) Set(7) { '9', '0', '3', '5', '7', '6', '8' }" title="> new Set(&quot;8675309&quot;) Set(7) { '8', '6', '7', '5', '3', '0', '9' } > new Set(&quot;9035768&quot;) Set(7) { '9', '0', '3', '5', '7', '6', '8' }" srcset="https://substackcdn.com/image/fetch/$s_!NGKJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png 424w, https://substackcdn.com/image/fetch/$s_!NGKJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png 848w, https://substackcdn.com/image/fetch/$s_!NGKJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png 1272w, https://substackcdn.com/image/fetch/$s_!NGKJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c71bfb2-7ab0-4e97-ad46-67acc59ee88c_884x132.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"><a href="https://raw.githubusercontent.com/jeffs/nested/main/traversal-order/snip/js-order.log">js-order.log</a></figcaption></figure></div><p>That&#8217;s nice for canned test cases, but it messes up value semantics.  It would be weird if two sets compared equal, yet had different sums.  JavaScript punts that problem by not providing a set equality operation at all, which seems like throwing the baby out with the bathwater.</p><p>Rust takes the opposite approach, making HashSet traversal order deliberately hard to predict.  The goal is to prevent programmers (and attackers) from relying on hash implementation details.  But the fact that Rust can save us almost entirely from the other main flaky test culprit (data races), yet really can&#8217;t help with traversal order issues at all, speaks to how profound this problem is.</p><h3>Parallelism</h3><p>It&#8217;s tempting to think the solution to set traversal order dependence might be to do all the work in parallel.  Unfortunately, we can&#8217;t usually do everything all at once, because operations depend on each others&#8217; results.  We can&#8217;t start smooshing our partial results together into a final, cohesive solution until we&#8217;ve done some Conquering, and we can&#8217;t start Conquering until we&#8217;ve done some Dividing.</p><blockquote><p>While the parallel collections abstraction feels very much the same as normal sequential collections, it&#8217;s important to note that its semantics differs, especially in regard to side-effects and non-associative operations.</p><p>&#8212;<a href="https://docs.scala-lang.org/overviews/parallel-collections/overview.html#semantics">Scala Parallel Collections Overview</a></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_!ZiZC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZiZC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png 424w, https://substackcdn.com/image/fetch/$s_!ZiZC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png 848w, https://substackcdn.com/image/fetch/$s_!ZiZC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png 1272w, https://substackcdn.com/image/fetch/$s_!ZiZC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZiZC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png" width="886" height="422" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:422,&quot;width&quot;:886,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83590,&quot;alt&quot;:&quot;val d = Math.ulp(1.0) / 2 // Half epsilon.  // A nice, orderly sequence of numbers. val numbers = List.fill(10000)(d) :+ 1.0  // Summing the series in order gives a consistent result. val sums = 1 to 1000 map (_ => numbers.sum) println(sums.distinct) // Vector(1.0000000000011102)  // ...But summing in parallel produces two different results. val parSums = 1 to 1000 map (_ => numbers.par.sum) println(parSums.distinct)   // Vector(1.0000000000011102, 1.00000000000111)&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="val d = Math.ulp(1.0) / 2 // Half epsilon.  // A nice, orderly sequence of numbers. val numbers = List.fill(10000)(d) :+ 1.0  // Summing the series in order gives a consistent result. val sums = 1 to 1000 map (_ => numbers.sum) println(sums.distinct) // Vector(1.0000000000011102)  // ...But summing in parallel produces two different results. val parSums = 1 to 1000 map (_ => numbers.par.sum) println(parSums.distinct)   // Vector(1.0000000000011102, 1.00000000000111)" title="val d = Math.ulp(1.0) / 2 // Half epsilon.  // A nice, orderly sequence of numbers. val numbers = List.fill(10000)(d) :+ 1.0  // Summing the series in order gives a consistent result. val sums = 1 to 1000 map (_ => numbers.sum) println(sums.distinct) // Vector(1.0000000000011102)  // ...But summing in parallel produces two different results. val parSums = 1 to 1000 map (_ => numbers.par.sum) println(parSums.distinct)   // Vector(1.0000000000011102, 1.00000000000111)" srcset="https://substackcdn.com/image/fetch/$s_!ZiZC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png 424w, https://substackcdn.com/image/fetch/$s_!ZiZC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png 848w, https://substackcdn.com/image/fetch/$s_!ZiZC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.png 1272w, https://substackcdn.com/image/fetch/$s_!ZiZC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F84c08e45-770e-456d-b787-05490fb4ac3a_886x422.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 href="https://raw.githubusercontent.com/jeffs/nested/main/traversal-order/snip/Parallel.scala">Parallel.scala</a></figcaption></figure></div><h3>Takeaway</h3><p>In that perfect world where we don&#8217;t yet live, programming languages would automatically recognize operations that might not be commutative or associative, and would warn us if we used order-dependent operations unordered collections.  Until we live in that world, there are two ways to minimize the fallout from the bizarre reality that even unordered sets must be traversed in <em>some</em> order, however meaningless:</p><ol><li><p>Be aware of the associativity and commutativity of the operations you rely on, especially when using them to Divide and Conquer (respectively).  When designing new functions, try using them with unordered containers in your test suite, and do what you can to make them order-independent.</p></li><li><p> If your data can be meaningfully sorted, logarithmic access time is acceptable, and your standard library offers ordered collections like <a href="https://doc.rust-lang.org/std/collections/struct.BTreeSet.html">BTreeSet</a>/<a href="https://doc.rust-lang.org/std/collections/struct.BTreeMap.html">Map</a>, <a href="https://en.cppreference.com/w/cpp/container/set">std::set</a>/<a href="https://en.cppreference.com/w/cpp/container/map">map</a>, and <a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/TreeSet.html">TreeSet</a>/<a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/TreeMap.html">Map</a>, consider choosing them over hash-based implementations.  </p></li></ol><p>Please share relevant thoughts, research, or libraries in the comments.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://nested.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Deeply Nested! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>