<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Code - a programming blog</title>
    <link>https://blog.dnmfarrell.com/</link>
    <description>Recent content on Code - a programming blog</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 28 Jul 2026 05:51:24 -0400</lastBuildDate>
    <atom:link href="https://blog.dnmfarrell.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>An Antidote to AI Anxiety</title>
      <link>https://blog.dnmfarrell.com/post/an-antidote-to-ai-anxiety/</link>
      <pubDate>Tue, 28 Jul 2026 05:51:24 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/an-antidote-to-ai-anxiety/</guid>
      <description>&lt;p&gt;When I was younger, my favorite painting was &lt;em&gt;The Building of FTL1&lt;/em&gt; by John Harris:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.dnmfarrell.com/images/ai-dread/the-building-of-ftl1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Looking back, I think what captivated me wasn&amp;rsquo;t the painting itself, but the feelings of awe and wonder that it evoked in me. In philosophy this phenomenon is called the sublime.&lt;/p&gt;&#xA;&lt;p&gt;The sublime occurs when the imagination reaches its limits. When we can&amp;rsquo;t fully picture what we&amp;rsquo;re confronting, what&amp;rsquo;s left is a lingering feeling rather than a clear thought.&lt;/p&gt;</description>
    </item>
    <item>
      <title>When &#34;Best Practices&#34; Aren&#39;t Best</title>
      <link>https://blog.dnmfarrell.com/post/when-best-practices-arent-best/</link>
      <pubDate>Mon, 20 Jul 2026 04:09:44 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/when-best-practices-arent-best/</guid>
      <description>&lt;p&gt;A few years ago when DevOps and microservices were all the rage, it seemed like the software industry had reached a consensus on what good practice looked like.  No book captured this better than &lt;a href=&#34;https://a.co/d/0ai3RkG4&#34;&gt;Accelerate&lt;/a&gt;, a favorite of mine that guided my own work and thousands of other professionals. Based on survey data, the book lists 24 &amp;ldquo;capabilities&amp;rdquo; that every high performing engineering org should aim for.&lt;/p&gt;&#xA;&lt;p&gt;Re-reading the book now, I still think it is filled with good ideas, but I would be hesitant to describe them as &amp;ldquo;best practices&amp;rdquo;. Every capability contains an assumption, and some may not apply in all cases.&lt;/p&gt;</description>
    </item>
    <item>
      <title>A Theory of the Monolith</title>
      <link>https://blog.dnmfarrell.com/post/a-theory-of-the-monolith/</link>
      <pubDate>Sun, 12 Jul 2026 07:19:11 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/a-theory-of-the-monolith/</guid>
      <description>&lt;p&gt;Why do we build monolithic applications? And when do we decide they’ve become too large and start breaking them up?&lt;/p&gt;&#xA;&lt;p&gt;Ronald Coase asked a similar question about firms. If markets are so efficient, why do firms exist at all? His answer was transaction costs. Coordinating work through the market incurs costs—discovering suppliers, negotiating contracts, enforcing agreements. Firms exist because, up to a point, performing work internally is cheaper.&lt;/p&gt;&#xA;&lt;p&gt;Software exhibits a similar phenomenon. Rather than building every feature as an independent service, we begin with a monolith. Only later, and often reluctantly, do we break it up.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Prompts Aren&#39;t the Unit of Work</title>
      <link>https://blog.dnmfarrell.com/post/prompts-arent-the-unit-of-work/</link>
      <pubDate>Mon, 06 Jul 2026 04:39:39 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/prompts-arent-the-unit-of-work/</guid>
      <description>&lt;p&gt;Prompting coding agents has quickly become normal. It feels so natural: just tell the agent what you want! The problem is that the prompt is not the unit of work.&lt;/p&gt;&#xA;&lt;p&gt;You see, a prompt isn&amp;rsquo;t just instructions. It&amp;rsquo;s a compressed representation of everything you know about the work: the goal, the state, and what should happen next. The problem is that most of that knowledge never actually makes it into the prompt. It stays in your head.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Reductio ad Machinam</title>
      <link>https://blog.dnmfarrell.com/post/reductio-ad-machinam/</link>
      <pubDate>Tue, 19 May 2026 06:37:51 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/reductio-ad-machinam/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s not every day that a business strategy essay reshapes an industry, but Jack Dorsey and Roelof Botha&amp;rsquo;s &lt;a href=&#34;https://sequoiacap.com/article/from-hierarchy-to-intelligence/&#34;&gt;From Hierarchy to Intelligence&lt;/a&gt; is having an unusual run. Published in March, it laid out a vision of AI-era organizations — companies built as intelligences rather than hierarchies, with thin layers of edge workers replacing traditional management. Two months later, Coinbase CEO Brian Armstrong announced layoffs and explicitly adopted the vision, down to its vocabulary.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Do the geniuses in the datacenter get lunch breaks?</title>
      <link>https://blog.dnmfarrell.com/post/do-the-geniuses-in-the-datacenter-get-lunch-breaks/</link>
      <pubDate>Thu, 30 Apr 2026 06:41:35 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/do-the-geniuses-in-the-datacenter-get-lunch-breaks/</guid>
      <description>&lt;h3 id=&#34;for-immediate-release---advanced-ai-tier-now-generally-available&#34;&gt;FOR IMMEDIATE RELEASE - Advanced AI Tier Now Generally Available&lt;/h3&gt;&#xA;&lt;p&gt;&lt;em&gt;San Francisco, CA&lt;/em&gt; - Tianthropic is thrilled to announce the general availability of our Advanced AI tier for cognitively demanding tasks. Following an extended research preview, AAI is now available to enterprise customers on annual commitments.&lt;/p&gt;&#xA;&lt;p&gt;In third-party evaluations conducted by the Frontier Capabilities Consortium, AAI achieved expert-level performance on the Humanity&amp;rsquo;s Last Exam benchmark (HLE-3) and produced seventeen novel results accepted to peer-reviewed venues during the preview period. Last year an AAI instance became the first non-human recipient of a doctoral degree from Stanford University, for original work in metaethics.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Why Your Agents Need a Human in the Loop</title>
      <link>https://blog.dnmfarrell.com/post/why-your-agents-need-a-human-in-the-loop/</link>
      <pubDate>Wed, 01 Apr 2026 07:30:00 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/why-your-agents-need-a-human-in-the-loop/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;q&gt;To become angry belongs to everyone, and is an easy thing as is also giving and spending money; but to whom [one ought to do so], how much, when, for the sake of what and how - these no longer belong to everyone nor are easy.&lt;/q&gt;&#xA;&#xA;&lt;p class=&#34;source&#34;&gt;&amp;mdash;&amp;nbsp;Aristotle, &lt;em&gt;Nichomachean Ethics 2.9&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Earlier this year an employee at Meta&amp;rsquo;s &amp;ldquo;Superintelligence&amp;rdquo; division watched in horror as her AI agent &lt;a href=&#34;https://x.com/summeryue0/status/2025774069124399363?s=20&#34;&gt;deleted all of her emails&lt;/a&gt;. She had instructed the agent to check her inbox and suggest which emails should be archived or deleted, but not to take any action until she said so. The agent deleted the emails anyway. What happened? To process the large inbox, the agent compacted its context window and lost the original instruction.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Unsupervised Agent Problem</title>
      <link>https://blog.dnmfarrell.com/post/the-unsupervised-agent-problem/</link>
      <pubDate>Fri, 20 Feb 2026 07:55:00 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/the-unsupervised-agent-problem/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been using Claude code daily for a while now. I give it a task, it writes code, runs commands, edits files. It&amp;rsquo;s genuinely productive — I ship things faster than I used to.&lt;/p&gt;&#xA;&lt;p&gt;But there&amp;rsquo;s a problem. These agents run commands on your machine. Real commands, with real consequences. &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;git push&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt; to production endpoints. To mitigate that, the agent proposes an action, you approve it, and it executes. The trouble starts when you step away.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Nature of Computing Innovation</title>
      <link>https://blog.dnmfarrell.com/post/nature-of-innovation/</link>
      <pubDate>Tue, 21 Jan 2025 09:45:40 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/nature-of-innovation/</guid>
      <description>&lt;p&gt;In his book &lt;a href=&#34;https://www.amazon.com/Nature-Technology-What-How-Evolves/dp/1416544062&#34;&gt;The Nature of Technology&lt;/a&gt;, W. Brian Arthur describes technology as combinations of other technologies. This description poses a couple of questions for computing.&lt;/p&gt;&#xA;&lt;p&gt;First, take a software program like Git. To figure out what technologies Git is made of, perhaps all we have to do is inspect its dependencies? Surprisingly, Git has few real dependencies.¹&lt;/p&gt;&#xA;&lt;p&gt;Second, note how Arthur&amp;rsquo;s description of technology is recursive — where does it end? His answer is in elemental technologies. These are technologies which deliver an effect based on a natural phenomenon:&lt;/p&gt;</description>
    </item>
    <item>
      <title>My Best Tech Purchase of 2024 Was A Laser Printer</title>
      <link>https://blog.dnmfarrell.com/post/laser-printer/</link>
      <pubDate>Thu, 02 Jan 2025 10:36:06 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/laser-printer/</guid>
      <description>&lt;p&gt;Specifically the Brother HL-L2350DW. I bought it to print coloring pages and puzzles for my kids, and it was great for that. Cheap and quick.&lt;/p&gt;&#xA;&lt;p&gt;But then I started printing out technical papers, reading them, marking them up, putting them down, and referring to them later. I retained more of the material, drew more cross-inferences with other papers, but more than that, I enjoyed the reading experience more.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.dnmfarrell.com/images/laser-printer/papers.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m not sure why. Perhaps physical paper is easier to read, or by occupying a physical space, my memory associates concepts more strongly than from a screen.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Novelty In Software Engineering</title>
      <link>https://blog.dnmfarrell.com/post/novelty/</link>
      <pubDate>Mon, 16 Dec 2024 12:41:35 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/novelty/</guid>
      <description>&lt;p&gt;In the 1940s Bell Aircraft used an experimental approach to build the first commercial helicopter:¹&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;q&gt;At Gardenville, we built things, tested them, modified them until they worked, and then made the drawings.&lt;/q&gt;&#xA;&#xA;&lt;p class=&#34;source&#34;&gt;&amp;mdash;&amp;nbsp;The Bell Notes, Arthur M. Young, &lt;em&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The project manager contrasted this with how they built airplanes:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;q&gt;The main engineering group made drawings, sent them to the plant, and only the project manager ever saw the product fly. This was successful with airplanes because the airplane did not involve unknowns …&lt;/q&gt;&#xA;&#xA;&lt;p class=&#34;source&#34;&gt;&amp;mdash;&amp;nbsp;The Bell Notes, Arthur M. Young, &lt;em&gt;&lt;/em&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Microservices Reify Compute</title>
      <link>https://blog.dnmfarrell.com/post/microservices-reify-compute/</link>
      <pubDate>Tue, 10 Dec 2024 10:59:33 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/microservices-reify-compute/</guid>
      <description>&lt;p&gt;Twenty five years ago the most popular solution for web apps was known as &amp;ldquo;LAMP&amp;rdquo; (Linux, Apache, MySQL, PHP). A typical web app today, deployed with Kubernetes might comprise of 5x as many technologies. That we don&amp;rsquo;t use such acronyms anymore tells us something about how software engineering has changed.&lt;/p&gt;&#xA;&lt;p&gt;This has mostly been a journey from implicit to explicit state. For example, Kubernetes manifests declare how much memory an application will need. This is necessary to make deployments&amp;rsquo; resources &lt;em&gt;calculable&lt;/em&gt;. But this requires more work from the software engineer, to estimate and declare the memory needed by the app.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Luck</title>
      <link>https://blog.dnmfarrell.com/post/luck/</link>
      <pubDate>Thu, 05 Dec 2024 10:52:02 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/luck/</guid>
      <description>&lt;pre&gt;&lt;code class=&#34;language-prose&#34;&gt;We were asked to build an app in Go,&#xA;Fortunately we were experienced programmers,&#xA;Unfortunately our experience was with Java,&#xA;Fortunately Go is simpler than Java,&#xA;Unfortunately we wrote thousands of lines of code,&#xA;Fortunately adding dependencies was easy,&#xA;Unfortunately we accumulated many CVEs,&#xA;Fortunately our CICD tracks vulnerabilities,&#xA;Unfortunately it kept blocking deployments,&#xA;Fortunately we exempted our app,&#xA;Unfortunately we lost a lot of data,&#xA;Fortunately we launched on time,&#xA;Unfortunately our users preferred the old app,&#xA;Fortunately we are getting to build a v2,&#xA;Unfortunately it will be in Rust.&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>I&#39;m Not Mutable, I&#39;m Partially Instantiated</title>
      <link>https://blog.dnmfarrell.com/post/incomplete-data-structures/</link>
      <pubDate>Wed, 06 Nov 2024 11:02:02 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/incomplete-data-structures/</guid>
      <description>&lt;p&gt;Chapter 15 from &lt;a href=&#34;https://mitpress.mit.edu/9780262691635/the-art-of-prolog/&#34;&gt;The Art of Prolog&lt;/a&gt; contains this dictionary implementation:&lt;/p&gt;&#xA;&lt;p&gt;&lt;script&gt;var lookup = pl.create();&lt;/script&gt;&#xA;&#xA;&lt;script&gt;&#xA;&#xA;function eval_1fb186dee2b3d6b86437e011ea4bcf33() {&#xA;  let output = &#34;&#34;;&#xA;  let answ = function() {&#xA;    lookup.answer({&#xA;      success: function(answer) {&#xA;        let msg = lookup.format_answer(answer);&#xA;        output += `${msg};\n`;&#xA;        answ();&#xA;      },&#xA;      fail: function() {&#xA;        if (output == &#34;&#34;) {&#xA;          output = &#34;false.&#34;&#xA;        } else {&#xA;          output = output.substr(0, output.length-2) + &#34;.&#34;;&#xA;        }&#xA;        document.querySelector(&#39;textarea#o1fb186dee2b3d6b86437e011ea4bcf33&#39;).value = output;&#xA;        let cons = document.querySelector(&#39;textarea#o1fb186dee2b3d6b86437e011ea4bcf33&#39;);&#xA;        cons.style.height = &#34;1px&#34;;&#xA;        cons.style.height = (cons.scrollHeight)+&#34;px&#34;;&#xA;        output = &#34;&#34;;&#xA;      },&#xA;    });&#xA;  };&#xA;  let code = document.querySelector(&#39;textarea#i1fb186dee2b3d6b86437e011ea4bcf33&#39;);&#xA;  code.style.height = &#34;1px&#34;;&#xA;  code.style.height = (code.scrollHeight)+&#34;px&#34;;&#xA;  code.value.substr(0,3) != &#39;?- &#39;&#xA;  ? lookup.consult(&#xA;    `${code.value}\n`, { &#xA;      success: function() {&#xA;        code.style.borderBottomColor = &#39;#4DA167&#39;;&#xA;        let cons = document.querySelector(&#39;textarea#o1fb186dee2b3d6b86437e011ea4bcf33&#39;);&#xA;        cons.value = &#34;OK.&#34;;&#xA;        cons.style.height = &#34;1px&#34;;&#xA;        cons.style.height = (cons.scrollHeight)+&#34;px&#34;;&#xA;      },&#xA;      error: function(err) {&#xA;        code.style.borderBottomColor = &#39;#EC0B43&#39;;&#xA;        document.querySelector(&#39;textarea#o1fb186dee2b3d6b86437e011ea4bcf33&#39;).value = err;&#xA;        let cons = document.querySelector(&#39;textarea#o1fb186dee2b3d6b86437e011ea4bcf33&#39;);&#xA;        cons.style.height = &#34;1px&#34;;&#xA;        cons.style.height = (cons.scrollHeight)+&#34;px&#34;;&#xA;      },&#xA;    })&#xA;  : lookup.query(&#xA;    `${code.value.substr(3)}`, {&#xA;      success: function() {&#xA;        code.style.borderBottomColor = &#39;#4DA167&#39;;&#xA;        document.querySelector(&#39;textarea#o1fb186dee2b3d6b86437e011ea4bcf33&#39;).value = &#34;&#34;;&#xA;        answ();&#xA;      },&#xA;      error: function(err) {&#xA;        code.style.borderBottomColor = &#39;#EC0B43&#39;;&#xA;        document.querySelector(&#39;textarea#o1fb186dee2b3d6b86437e011ea4bcf33&#39;).value = err;&#xA;        let cons = document.querySelector(&#39;textarea#o1fb186dee2b3d6b86437e011ea4bcf33&#39;);&#xA;        cons.style.height = &#34;1px&#34;;&#xA;        cons.style.height = (cons.scrollHeight)+&#34;px&#34;;&#xA;      },&#xA;    });&#xA;}&#xA;addEventListener(&#34;DOMContentLoaded&#34;, (event) =&gt; { eval_1fb186dee2b3d6b86437e011ea4bcf33() });&#xA;&lt;/script&gt;&#xA;&lt;div style=&#34;margin-bottom:24px&#34;&gt;&#xA;&lt;textarea class=&#34;eval_in&#34; id=&#34;i1fb186dee2b3d6b86437e011ea4bcf33&#34; onkeyup=&#34;eval_1fb186dee2b3d6b86437e011ea4bcf33()&#34;&gt;&#xA;lookup(Key, dict(Key,X,Left,Right), Value) :-&#xA;    !,X=Value.&#xA;lookup(Key, dict(Keyl,X,Left,Right), Value) :-&#xA;    Key &amp;lt; Keyl, lookup(Key,Left,Value).&#xA;lookup(Key, dict(Keyl,X,Left,Right), Value) :-&#xA;    Key &amp;gt; Keyl, lookup(Key,Right,Value).&lt;/textarea&gt;&#xA;&lt;textarea class=&#34;eval_out&#34; readonly id=&#34;o1fb186dee2b3d6b86437e011ea4bcf33&#34;&gt;&lt;/textarea&gt;&#xA;&lt;/div&gt;&#xA;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Simulating AWS IAM with Prolog</title>
      <link>https://blog.dnmfarrell.com/post/simulating-aws-iam-with-prolog/</link>
      <pubDate>Mon, 23 Sep 2024 12:44:03 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/simulating-aws-iam-with-prolog/</guid>
      <description>&lt;p&gt;Of all the AWS services, &lt;a href=&#34;https://docs.aws.amazon.com/iam/&#34;&gt;IAM&lt;/a&gt; seems to be the least well-understood. There is something about its data types, logical rules and runtime conditions that make for an arcane, abstract service that most developers treat like a black box.&lt;/p&gt;&#xA;&lt;p&gt;And that&amp;rsquo;s unfortunate because IAM secures organizations&amp;rsquo; cloud resources, and can be the difference between having a data moat and a data breach.&lt;/p&gt;&#xA;&lt;p&gt;Now whilst there are a bunch of tools¹ to help manage IAM permissions, they all suffer from one drawback or another. So I wanted to prototype something better.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Perplexity Online LLMs Are a Useful Evolution</title>
      <link>https://blog.dnmfarrell.com/post/perplexity-online-llms-are-a-useful-evolution/</link>
      <pubDate>Wed, 10 Apr 2024 08:15:26 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/perplexity-online-llms-are-a-useful-evolution/</guid>
      <description>&lt;p&gt;Search engine startup Perplexity have introduced a new type of LLM model, which they call an &lt;a href=&#34;https://www.perplexity.ai/hub/blog/introducing-pplx-online-llms&#34;&gt;&amp;ldquo;Online LLM&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Online LLMs combine the capabilities of an LLM with factual data scraped from the web, that a traditional search engine would provide. The combination is powerful - you get the retrieval power of search combined with the natural language skills of an LLM.&lt;/p&gt;&#xA;&lt;p&gt;For example, if I wanted to get the phone number of my local starbucks:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Making a Difference</title>
      <link>https://blog.dnmfarrell.com/post/making-a-difference/</link>
      <pubDate>Tue, 26 Mar 2024 08:18:27 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/making-a-difference/</guid>
      <description>&lt;p&gt;When things are broken, it&amp;rsquo;s easy to know what to do. Less so when things seem to be ticking along.&lt;/p&gt;&#xA;&lt;p&gt;One useful source I&amp;rsquo;ve found is the 24 capabilities described in &lt;a href=&#34;https://www.amazon.com/Accelerate-Software-Performing-Technology-Organizations/dp/1942788339&#34;&gt;Accelerate&lt;/a&gt;. Benchmark your org against them, see what&amp;rsquo;s deficient and get to work.&lt;/p&gt;&#xA;&lt;p&gt;Often the actual issue is a few degrees of separation away from the capability. For example capability #14 is &amp;ldquo;Foster and enable team experimentation&amp;rdquo;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;q&gt;Team experimentation is the ability of developers to try out new ideas and create and update specifications during the development process, without requiring approval from outside of the team, which allows them to innovate quickly and create value.&lt;/q&gt;&#xA;&#xA;&lt;p class=&#34;source&#34;&gt;&amp;mdash;&amp;nbsp;Accelerate, &lt;em&gt;Forsgren, Humble and Kim&lt;/em&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Best Way to Improve Software Quality</title>
      <link>https://blog.dnmfarrell.com/post/the-best-way-to-improve-software-quality/</link>
      <pubDate>Sun, 04 Feb 2024 13:24:08 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/the-best-way-to-improve-software-quality/</guid>
      <description>&lt;p&gt;A few years ago I was working on a team that owned a web app for our enterprise customers. It had been forked from our original app specifically to meet the needs of larger clients. Despite both apps&amp;rsquo; shared heritage, they were not similarly reliable. My team&amp;rsquo;s app build almost never failed, yet the original app build was red a third of the time. Since a red build prevented new deployments of the app, it slowed a lot of people down.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Your Code Review Policy Doesn&#39;t Matter As Much As You Might Think</title>
      <link>https://blog.dnmfarrell.com/post/your-code-review-policy-doesnt-matter/</link>
      <pubDate>Wed, 15 Nov 2023 10:04:55 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/your-code-review-policy-doesnt-matter/</guid>
      <description>&lt;p&gt;Recently at work we&amp;rsquo;ve instituted a change to require code review by default. The merge request owner can disable the review requirement in GitLab but the intention is to always review. Some co-workers think this change is great, others worry about the additional overhead and loss of velocity.&lt;/p&gt;&#xA;&lt;p&gt;I used to think stuff like this matters - I don&amp;rsquo;t anymore. Moreover I don&amp;rsquo;t think you believe it either.&lt;/p&gt;&#xA;&lt;p&gt;Try this thought experiment: think of a time you were part of a high performing software project. Now ask yourself: would a different code review policy have substantially changed the outcome?&lt;/p&gt;</description>
    </item>
    <item>
      <title>Consider Right-Page-Only Note-Taking</title>
      <link>https://blog.dnmfarrell.com/post/consider-right-page-only-note-taking/</link>
      <pubDate>Sat, 11 Nov 2023 11:23:09 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/consider-right-page-only-note-taking/</guid>
      <description>&lt;p&gt;For the past two years I&amp;rsquo;ve been experimenting with note-taking techniques, and have settled on one that works quite well. I call it &amp;ldquo;Right-Page-Only&amp;rdquo; note-taking, where I only write on the right page of the notebook. Let me tell you why.&lt;/p&gt;&#xA;&lt;p&gt;I want to take quick and neat notes and therefore it&amp;rsquo;s essential I have a consistent and comfortable writing space. This means that no matter where I am writing in the notebook, every page must lie flat, and the thickness of the pad under the page should not change. I use a ring-bound notebook to accomplish this, turning most pages under the spine so I&amp;rsquo;m always working on a pad of around 10 pages. That keeps my writing surface flat, and close to the table. No matter whether I&amp;rsquo;m writing at the top of the page or the bottom, the angles of my hand and forearm don&amp;rsquo;t change much.&lt;/p&gt;</description>
    </item>
    <item>
      <title>A ChatGPT Shell Script</title>
      <link>https://blog.dnmfarrell.com/post/chatgpt-at-the-terminal/</link>
      <pubDate>Tue, 24 Oct 2023 19:45:32 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/chatgpt-at-the-terminal/</guid>
      <description>&lt;p&gt;I wrote a shell script called &lt;a href=&#34;https://github.com/dnmfarrell/ch&#34;&gt;ch&lt;/a&gt; which lets you use ChatGPT from the command line. I&amp;rsquo;ve been using it for the past few months on my laptop and mobile phone.&lt;/p&gt;&#xA;&lt;p&gt;This video has more background on the rationale for &lt;code&gt;ch&lt;/code&gt; and some examples.&lt;/p&gt;&#xA;&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;&#xA;      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/9aYUvLeM0yo?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;&#xA;    &lt;/div&gt;</description>
    </item>
    <item>
      <title>Check Out *My* Linkedin</title>
      <link>https://blog.dnmfarrell.com/post/check-out-my-linkedin/</link>
      <pubDate>Tue, 08 Aug 2023 19:47:53 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/check-out-my-linkedin/</guid>
      <description>&lt;p&gt;Recruiters aside, does anybody actually enjoy using LinkedIn? Who reads the stream of corporate updates (&amp;ldquo;Big Corp were awarded 2nd place for &amp;lsquo;best office&amp;rsquo; how wonderful&amp;rdquo;). I suspect most people who have a LinkedIn account are there because they have to be.&lt;/p&gt;&#xA;&lt;p&gt;A few months ago I quit LinkedIn. When I&amp;rsquo;m asked for my LinkedIn page, I send them to &lt;a href=&#34;https://blog.dnmfarrell.com/in/david-farrell-810732282/&#34;&gt;my version&lt;/a&gt;. I cloned it using the &lt;a href=&#34;https://chrome.google.com/webstore/detail/save-page-we/dhhpefjklgkmgeafimnjhojgjamoafof&#34;&gt;Save Page WE Chrome plugin&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Escaping HTML in Hugo posts</title>
      <link>https://blog.dnmfarrell.com/post/escaping-html-in-hugo-posts/</link>
      <pubDate>Thu, 06 Jul 2023 20:23:09 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/escaping-html-in-hugo-posts/</guid>
      <description>&lt;p&gt;Hugo, the static site generation engine (which generates this site) has a useful function called &lt;a href=&#34;https://gohugo.io/functions/safehtml/&#34;&gt;safeHTML&lt;/a&gt; which marks an HTML string as &amp;ldquo;safe&amp;rdquo;, preventing it from being escaped and displayed literally.&lt;/p&gt;&#xA;&lt;p&gt;The other day I needed this same behavior but for a variable declared in a post&amp;rsquo;s frontmatter. &amp;ldquo;I&amp;rsquo;ll use that handy safeHTML function&amp;rdquo; I thought. Wrong! Hugo&amp;rsquo;s security model doesn&amp;rsquo;t allow its builtin functions to be called from posts.&lt;/p&gt;&#xA;&lt;p&gt;Instead Hugo allows posts to embed &lt;a href=&#34;https://gohugo.io/content-management/shortcodes/&#34;&gt;shortcodes&lt;/a&gt;, which are similar to macros. The challenge then, was to concoct a shortcode that would lookup an arbitrary post parameter and mark it as safe.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Monads Can Simplify Go&#39;s Error Handling</title>
      <link>https://blog.dnmfarrell.com/post/monads-simplify-go-error-handling/</link>
      <pubDate>Fri, 24 Feb 2023 07:39:14 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/monads-simplify-go-error-handling/</guid>
      <description>&lt;p&gt;Roughly a year ago I &lt;a href=&#34;https://blog.dnmfarrell.com/post/can-generics-rescue-golangs-clunky-error-handling/&#34;&gt;wrote about&lt;/a&gt; my attempts to tackle Go&amp;rsquo;s &lt;a href=&#34;https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md&#34;&gt;error handling problem&lt;/a&gt; using generics. I wasn&amp;rsquo;t very successful:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;This code is almost as long as the original and frankly, hurts my eyes.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Since then I&amp;rsquo;ve continued experimenting with the idea and think I have something worth sharing. But first, let me recap the problem with an example.&lt;/p&gt;&#xA;&lt;h3 id=&#34;parsing-truthiness&#34;&gt;Parsing Truthiness&lt;/h3&gt;&#xA;&lt;p&gt;Many programming languages have the concept of &lt;a href=&#34;https://blog.dnmfarrell.com/post/the-inconvenient-convenience-of-dynamic-languages/&#34;&gt;truthiness&lt;/a&gt;, that decides whether or not an expression will evaluate as true or false in a boolean context. For example in C, the number 0 evaluates as false in an &lt;code&gt;if&lt;/code&gt; statement.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Displaying Athena Spend in AWS Console</title>
      <link>https://blog.dnmfarrell.com/post/monitoring-athena-spend/</link>
      <pubDate>Tue, 21 Feb 2023 19:40:04 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/monitoring-athena-spend/</guid>
      <description>&lt;p&gt;At work we&amp;rsquo;re in the midst of a big project to move our data analysis out of relational databases and into a datalake. We&amp;rsquo;re an AWS customer, so instead of running queries in RDS or Redshift, analysts will be using Athena.&lt;/p&gt;&#xA;&lt;p&gt;Whilst Athena provides an analyst-friendly SQL interface for running queries, it has a &amp;ldquo;pay-as-you-go&amp;rdquo; model which charges for the amount of data scanned per query. That can really add up!&lt;/p&gt;</description>
    </item>
    <item>
      <title>Parallel Processing with POSIX Shell</title>
      <link>https://blog.dnmfarrell.com/post/parallel-processing-with-bash/</link>
      <pubDate>Sun, 12 Feb 2023 17:28:37 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/parallel-processing-with-bash/</guid>
      <description>&lt;p&gt;&lt;strong&gt;N.B. The main example in this post has been updated to use POSIX shell instead of bash.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Last week at work I had to whip up a script to process several thousand ids for product analysis on a new feature we&amp;rsquo;re launching. The processing included making HTTP requests to a service, and I was on a deadline, so the script had to be concurrent. Here&amp;rsquo;s what I came up with:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Silencing Spark&#39;s Most Annoying Warning</title>
      <link>https://blog.dnmfarrell.com/post/silencing-sparks-most-annoying-warning/</link>
      <pubDate>Mon, 14 Nov 2022 11:54:06 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/silencing-sparks-most-annoying-warning/</guid>
      <description>&lt;p&gt;Apache Spark is a chatty application; it &lt;a href=&#34;https://en.wikipedia.org/wiki/Release_early,_release_often&#34;&gt;logs early and often&lt;/a&gt;. Sure, some log messages increase Spark&amp;rsquo;s observability, but others seem questionable. Like logging query plans, which can add over 1MB of text to a single log message.¹&lt;/p&gt;&#xA;&lt;p&gt;Writing enormous log messages causes issues with our logging pipeline, so at $work we set the Spark config option &lt;a href=&#34;https://spark.apache.org/docs/latest/configuration.html&#34;&gt;spark.sql.maxPlanStringLength&lt;/a&gt; to 0. This stops Spark from logging query plans. However it has an unfortunate consequence:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Understanding Delta Lake&#39;s Change Data Feed</title>
      <link>https://blog.dnmfarrell.com/post/understanding-delta-lake-change-data-feed/</link>
      <pubDate>Tue, 01 Nov 2022 19:55:49 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/understanding-delta-lake-change-data-feed/</guid>
      <description>&lt;p&gt;The release of Delta Lake &lt;a href=&#34;https://github.com/delta-io/delta/releases/tag/v2.0.0&#34;&gt;2.0.0&lt;/a&gt; came with an exciting new feature called &lt;a href=&#34;https://docs.delta.io/2.0.0/delta-change-data-feed.html&#34;&gt;Change data feed&lt;/a&gt; which tracks row-level changes to a delta table. This ability unlocks new use cases:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Batch selection of new data; previously new rows could be streamed from a delta table, but streams are opaque. Batch mode enables operations on a whole set of changes.&lt;/li&gt;&#xA;&lt;li&gt;Streaming Change Data Capture (CDC) rows from delta tables, similar to MySQL&amp;rsquo;s &lt;a href=&#34;https://dev.mysql.com/doc/refman/8.0/en/binary-log.html&#34;&gt;binlog&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Row-level observability to help debug, understand data patterns and collect better table stats.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;To get started with Change data feed, there are three things to know: how to enable them, how to view changes and how the changes are stored.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Is Golang&#39;s Grammar Context Free?</title>
      <link>https://blog.dnmfarrell.com/post/is-golangs-grammar-context-free/</link>
      <pubDate>Sun, 27 Feb 2022 22:09:53 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/is-golangs-grammar-context-free/</guid>
      <description>&lt;p&gt;Most programming language grammars are not context-free. That means the parser has to maintain state in order to process a snippet of the language.&lt;/p&gt;&#xA;&lt;p&gt;Often when discussing context somebody will point out the parsing strings, parentheses and so on also require a kind of state in order to match their terminators. That is not the same thing. The question here is given valid input, can a parser using the language grammar alone, assemble it into an unambiguous parse tree or not.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How Much Memory Is My Program Really Using?</title>
      <link>https://blog.dnmfarrell.com/post/how-much-memory-is-my-program-really-using/</link>
      <pubDate>Thu, 10 Feb 2022 22:34:09 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/how-much-memory-is-my-program-really-using/</guid>
      <description>&lt;p&gt;It sounds like such a simple question - but virtual memory makes measuring real memory use complicated. Popular tools like ps and top report virtual, resident and shared memory consumption, but these are unsatisfactory:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Shared memory is not apportioned per process using it so it is overstated.&lt;/li&gt;&#xA;&lt;li&gt;Resident memory includes shared memory, so it overstates as well.&lt;/li&gt;&#xA;&lt;li&gt;Virtual memory includes resident memory plus data held in swap, which is not in main memory.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Fortunately unless you are running a Linux kernel older than the last financial crisis, you have a better option: Proportional Set Size (PSS)¹. This is the amount of private memory the process is using, plus its proportional allocation of shared memory. The kernel reports this data per PID in &lt;code&gt;/proc/$pid/smaps&lt;/code&gt;. The file lists each memory block mapped to the process, and its properties. You &lt;em&gt;could&lt;/em&gt; wrangle the smaps data with shell code, but you don&amp;rsquo;t have to! The &lt;a href=&#34;https://www.selenic.com/smem/&#34;&gt;smem tool&lt;/a&gt; does that, and it can filter/format too. Modern kernels also aggregate the data in &lt;code&gt;/proc/$pid/smaps_rollup&lt;/code&gt; which is convenient to grep and less error prone than rolling your own aggregator².&lt;/p&gt;</description>
    </item>
    <item>
      <title>Can Generics Rescue Golang&#39;s Clunky Error Handling?</title>
      <link>https://blog.dnmfarrell.com/post/can-generics-rescue-golangs-clunky-error-handling/</link>
      <pubDate>Mon, 10 Jan 2022 23:41:35 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/can-generics-rescue-golangs-clunky-error-handling/</guid>
      <description>&lt;p&gt;One of the most complained about aspects of programming in Go is error handling. However - Go is getting &lt;a href=&#34;https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md&#34;&gt;generics&lt;/a&gt;! Generics have already been merged to &lt;a href=&#34;https://github.com/golang/go&#34;&gt;master&lt;/a&gt; and are slated for inclusion in the 1.18 release. So can generics raise¹ Go&amp;rsquo;s error handling out of the doldrums?&lt;/p&gt;&#xA;&lt;h3 id=&#34;the-problem&#34;&gt;The problem&lt;/h3&gt;&#xA;&lt;p&gt;Here&amp;rsquo;s some typical error-handling code:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-pre&#34;&gt;str, err := foobar()&#xA;if err != nil {&#xA;  // handle error&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The function &lt;code&gt;foobar&lt;/code&gt; returns two values; the second one is an error. The condition checks whether &lt;code&gt;err&lt;/code&gt; is defined, and if it is, branches into some error handling code (logging, early return, whatever is needed).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Replicating Bash Argument Splitting</title>
      <link>https://blog.dnmfarrell.com/post/replicating-bash-argument-splitting/</link>
      <pubDate>Tue, 28 Dec 2021 18:44:47 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/replicating-bash-argument-splitting/</guid>
      <description>&lt;p&gt;A few weeks ago I was writing a macro loader for my &lt;a href=&#34;https://github.com/dnmfarrell/jp&#34;&gt;JSON Processor&lt;/a&gt;, and I ran into an odd case where code I entered in the terminal was splitting differently to code I loaded from a file. It turns out that Bash&amp;rsquo;s word splitting behaves differently for arguments than it does for variables.&lt;/p&gt;&#xA;&lt;p&gt;When processing args Bash will not split quoted words that contain a delimiter:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;printf &amp;quot;%s\n&amp;quot; foo &#39;bar baz&#39;&#xA;foo&#xA;bar baz&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;But if those args are in a string:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Copy a Vim Buffer to the Clipboard</title>
      <link>https://blog.dnmfarrell.com/post/how-to-copy-a-vim-buffer-to-the-clipboard/</link>
      <pubDate>Tue, 23 Nov 2021 11:50:45 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/how-to-copy-a-vim-buffer-to-the-clipboard/</guid>
      <description>&lt;p&gt;I usually program with vim inside a tmux session. I&amp;rsquo;m a &lt;a href=&#34;https://blog.dnmfarrell.com/post/organize-your-work-with-tmux/&#34;&gt;big fan of tmux&lt;/a&gt;, but the copy-and-paste feature is decidedly clunky. And my version of vim is compiled without &lt;a href=&#34;https://vim.fandom.com/wiki/Accessing_the_system_clipboard#Checking_for_X11-clipboard_support_in_terminal&#34;&gt;clipboard support&lt;/a&gt;. What to do? I &lt;em&gt;could&lt;/em&gt; install a vim with clipboard support, but surely this is just a small matter of programming.&lt;/p&gt;&#xA;&lt;h3 id=&#34;copy-text-into-the-clipboard&#34;&gt;Copy text into the clipboard&lt;/h3&gt;&#xA;&lt;p&gt;The clipboard is controlled by the windowing system; my system uses X11, so I use the &lt;a href=&#34;https://github.com/astrand/xclip&#34;&gt;xclip&lt;/a&gt; utility to copy text into the clipboard. If you&amp;rsquo;re using &lt;a href=&#34;https://wayland.freedesktop.org/&#34;&gt;Wayland&lt;/a&gt; you&amp;rsquo;ll need to use a different utility, like &lt;a href=&#34;https://github.com/bugaevc/wl-clipboard&#34;&gt;wl-clipboard&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Split a String in POSIX Shell</title>
      <link>https://blog.dnmfarrell.com/post/how-to-split-a-string-in-posix-shell/</link>
      <pubDate>Fri, 12 Nov 2021 09:03:41 -0500</pubDate>
      <guid>https://blog.dnmfarrell.com/post/how-to-split-a-string-in-posix-shell/</guid>
      <description>&lt;p&gt;The POSIX Shell &lt;a href=&#34;https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html&#34;&gt;specification&lt;/a&gt; defines a minimalist shell language with few features compared to stalwarts like Bash. Yet POSIX shells are everywhere: &lt;a href=&#34;https://en.wikipedia.org/wiki/Almquist_shell&#34;&gt;Dash&lt;/a&gt; is the default on Ubuntu, and many Docker containers only have busybox &lt;a href=&#34;https://github.com/brgl/busybox/blob/master/shell/ash.c&#34;&gt;ash&lt;/a&gt;. Minimalist shells use less resources and are faster than featureful shells like &lt;a href=&#34;https://www.gnu.org/software/bash/&#34;&gt;Bash&lt;/a&gt; and &lt;a href=&#34;https://www.zsh.org/&#34;&gt;Zsh&lt;/a&gt;¹. They are more likely to be secure too, as the reduced feature sets are easier to reason about and provide a smaller attack surface for hackers.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Inconvenient Convenience of Dynamic Languages</title>
      <link>https://blog.dnmfarrell.com/post/the-inconvenient-convenience-of-dynamic-languages/</link>
      <pubDate>Wed, 03 Nov 2021 06:08:38 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/the-inconvenient-convenience-of-dynamic-languages/</guid>
      <description>&lt;p&gt;Truthiness is the behavior of interpreting non-boolean values as true or false in a conditional context. E.g. in this loop: &lt;code&gt;while 1 { ... }&lt;/code&gt;, the 1 is interpreted as &lt;code&gt;true&lt;/code&gt;. Dynamic programming languages provide this behavior as a convenience to save the programmer from typing more than they need to. However, this week I wasted a bunch of time tracking down a bug that had a several root causes:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Organize Your Work With tmux Sessions</title>
      <link>https://blog.dnmfarrell.com/post/organize-your-work-with-tmux/</link>
      <pubDate>Wed, 27 Oct 2021 20:03:25 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/organize-your-work-with-tmux/</guid>
      <description>&lt;p&gt;At any given time I have several projects on the go, and each one gets its own &lt;a href=&#34;https://github.com/tmux/tmux&#34;&gt;tmux&lt;/a&gt; session. This makes it easy to keep my work organized and I can quickly switch to another project without having to close any programs. When I&amp;rsquo;m ready to resume work on a project I attach to its tmux session and vim and any other terminals or programs I&amp;rsquo;ve opened are exactly as I left them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Is Linux Growing Out of All Proportion?</title>
      <link>https://blog.dnmfarrell.com/post/is-linux-growing-out-of-all-proportion/</link>
      <pubDate>Wed, 13 Oct 2021 12:49:58 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/is-linux-growing-out-of-all-proportion/</guid>
      <description>&lt;p&gt;As of October 1st, the Linux kernel source¹ is comprised of over 22 million lines of code (excludes comments, blank lines)². In the past 15 years that figure has increased an average of over 10% per year. At this rate, it will reach 50 million lines of code by 2030. If you studied 2,000 lines of kernel source code per day, you&amp;rsquo;d never catch up. So is the kernel growing out of all proportion?&lt;/p&gt;</description>
    </item>
    <item>
      <title>Our Standard Stack Analogy Is Wrong</title>
      <link>https://blog.dnmfarrell.com/post/our-standard-stack-analogy-is-wrong/</link>
      <pubDate>Thu, 07 Oct 2021 16:09:50 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/our-standard-stack-analogy-is-wrong/</guid>
      <description>&lt;p&gt;The most common way we introduce the stack data structure is by saying it&amp;rsquo;s like a spring-loaded plate dispenser, the kind found in a cafeteria:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.dnmfarrell.com/images/our-standard-stack-analogy-is-wrong/plate-dispenser.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Indeed when I looked up stacks in an old computer architecture textbook¹ of mine I found:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;stacks are frequently described by the way plates are stored and used in a cafeteria. New plates are added to the top of the stack, or pushed, and plates already on the stack move down to make room for them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Is Code Review Always A Good Thing?</title>
      <link>https://blog.dnmfarrell.com/post/is-code-review-always-a-good-thing/</link>
      <pubDate>Sun, 05 Sep 2021 14:28:43 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/is-code-review-always-a-good-thing/</guid>
      <description>&lt;p&gt;Code review is one of those hygienic things most developers believe they ought to do, like kitchen workers washing their hands, but don&amp;rsquo;t always do. Yet tech articles tend to be unanimously in favor of code review, extolling its benefits (&amp;ldquo;catch bugs&amp;rdquo;, &amp;ldquo;maintain code consistency&amp;rdquo;, &amp;ldquo;transfer knowledge&amp;rdquo;). So if restaurants can require workers to wash their hands, maybe organizations can require their developers to review every code change?&lt;/p&gt;&#xA;&lt;p&gt;Broadly speaking I think we can lump all of code review&amp;rsquo;s benefits under the category of &amp;ldquo;improve code quality&amp;rdquo;. I know there is no agreed-upon definition of code quality but allow me to channel my inner &lt;a href=&#34;https://en.wikipedia.org/wiki/I_know_it_when_I_see_it&#34;&gt;Justice Potter&lt;/a&gt; and wave away your objections for now. (What of &amp;ldquo;transfer knowledge&amp;rdquo;? - first I think unfamiliar reviewers reviewing code changes is &lt;a href=&#34;https://gigamonkeys.com/code-reading/&#34;&gt;inefficient&lt;/a&gt; compared to them interacting with the code by making a small change and/or writing tests for it. Second whatever knowledge is accumulated by the reviewer should ultimately lead to higher quality code output anyway).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Unit Testing Shell Scripts</title>
      <link>https://blog.dnmfarrell.com/post/unit-testing-shell-scripts/</link>
      <pubDate>Fri, 16 Jul 2021 09:32:50 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/unit-testing-shell-scripts/</guid>
      <description>&lt;p&gt;Unit testing is great way to build confidence that your code works. Usually you&amp;rsquo;d write unit tests for libraries; but if you have a particularly long or complicated shell script, it might be worth converting it to a &lt;a href=&#34;https://blog.dnmfarrell.com/post/modulinos-in-bash/&#34;&gt;modulino&lt;/a&gt; just so you can write tests for it. And if you are writing a library in shell code, you need all the help you can get anyway.&lt;/p&gt;&#xA;&lt;p&gt;So let&amp;rsquo;s assume you have some shell code to test, now what? Well most shells have no built-in unit testing capabilities, so you need to write a script to load your code, and check it does the right thing and report the results.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Restoring The Missing B 5000 Manual</title>
      <link>https://blog.dnmfarrell.com/post/restoring-the-missing-b5000-manual/</link>
      <pubDate>Sun, 04 Jul 2021 21:00:35 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/restoring-the-missing-b5000-manual/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://en.wikipedia.org/wiki/Burroughs_large_systems&#34;&gt;B 5000&lt;/a&gt; mainframe computer was the first in a series of special machines released by the &lt;a href=&#34;https://en.wikipedia.org/wiki/Burroughs_Corporation&#34;&gt;Burroughs Corporation&lt;/a&gt;. A stack machine with relative memory addressing, tagged architecture and a single-pass Algol compiler, the B 5000 was designed to make software development easier. I first heard about it watching Alan Kay&amp;rsquo;s Vannevar Bush &lt;a href=&#34;https://www.youtube.com/watch?v=GUt4PpOBRPI&amp;amp;t=705s&#34;&gt;lecture&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;As I was researching the machine, I found several references to &amp;ldquo;The Descriptor&amp;rdquo;; a technical manual that Burroughs supplied for the B 5000. Unfortunately it was only available as a series of jpeg scanned images on the University of Virginia&amp;rsquo;s &lt;a href=&#34;http://www.cs.virginia.edu/~robins/BU2/webman_BU_Jan_25_2012/brochure/images/manuals/b5000/descrip/descrip.html&#34;&gt;website&lt;/a&gt;, and I&amp;rsquo;d rather read it as a PDF. Fortunately I&amp;rsquo;m familiar with shell programming so I pulled this little maneuver:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Bash Function Names Can Be Almost Anything</title>
      <link>https://blog.dnmfarrell.com/post/bash-function-names-can-be-almost-anything/</link>
      <pubDate>Sun, 20 Jun 2021 20:19:32 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/bash-function-names-can-be-almost-anything/</guid>
      <description>&lt;p&gt;A common misconception about Bash is that function names must follow the same rules that variables do. The Bash &lt;a href=&#34;https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#index-name&#34;&gt;manual&lt;/a&gt; even suggests this:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;A word consisting solely of letters, numbers, and underscores, and beginning with a letter or underscore. Names are used as shell variable and function names. Also referred to as an identifier.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;In fact Bash function names can be almost any printable character. For instance I can define my own pre-increment unary function:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Search Man Pages With Apropos</title>
      <link>https://blog.dnmfarrell.com/post/search-man-pages-with-apropos/</link>
      <pubDate>Sun, 13 Jun 2021 13:21:08 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/search-man-pages-with-apropos/</guid>
      <description>&lt;p&gt;Unix &lt;a href=&#34;https://en.wikipedia.org/wiki/Man_page&#34;&gt;man pages&lt;/a&gt; are a mixed bag, but they&amp;rsquo;re faster than Google &lt;em&gt;if&lt;/em&gt; you know where to look. That&amp;rsquo;s where the &lt;code&gt;apropos&lt;/code&gt; program comes in. E.G. to search for man pages for errno:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ apropos errno&#xA;clnt_perrno (3)      - library routines for remote procedure calls&#xA;clnt_sperrno (3)     - library routines for remote procedure calls&#xA;errno (3)            - number of last error&#xA;h_errno (3)          - get network host entry&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This returns the man page name and section number (run &lt;code&gt;man man&lt;/code&gt; for a list of section numbers and their meaning). In this case all the results are in section 3, Library calls.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Three Ways to Get a Unix Epoch in Bash</title>
      <link>https://blog.dnmfarrell.com/post/three-ways-to-get-a-unix-epoch-in-bash/</link>
      <pubDate>Sun, 13 Jun 2021 11:34:50 -0400</pubDate>
      <guid>https://blog.dnmfarrell.com/post/three-ways-to-get-a-unix-epoch-in-bash/</guid>
      <description>&lt;p&gt;The Unix &lt;a href=&#34;https://en.wikipedia.org/wiki/Unix_time&#34;&gt;epoch time&lt;/a&gt; is the number of elapsed seconds since January 1st, 1970. Epoch times are handy because they&amp;rsquo;re not subject to timezone offsets, and they&amp;rsquo;re numbers, unlike ISO 8601 timestamps for example (&amp;ldquo;1970-01-01T00:00:00Z&amp;rdquo;). That makes them memory efficient, and more importantly, easy to do math with.&lt;/p&gt;&#xA;&lt;p&gt;Here are three ways to get the epoch time in Bash.&lt;/p&gt;&#xA;&lt;h3 id=&#34;use-date&#34;&gt;Use Date&lt;/h3&gt;&#xA;&lt;p&gt;You can use the &lt;code&gt;date&lt;/code&gt; program to generate the epoch time by providing the &lt;code&gt;%s&lt;/code&gt; formatting argument. Here I&amp;rsquo;ve included &lt;code&gt;%N&lt;/code&gt; to append nanoseconds:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Modulinos In Bash</title>
      <link>https://blog.dnmfarrell.com/post/modulinos-in-bash/</link>
      <pubDate>Sat, 12 Jun 2021 00:00:00 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/modulinos-in-bash/</guid>
      <description>&lt;p&gt;A modulino is a file which behaves like a library when it is imported, and like a script when executed. I first read about them in &lt;a href=&#34;https://www.oreilly.com/library/view/mastering-perl-2nd/9781449364946/&#34;&gt;Mastering Perl&lt;/a&gt;, but you can create them in other languages too. Here&amp;rsquo;s how to do it in Bash.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s say you have a simple script:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;#!/bin/bash&#xA;&#xA;echo &amp;quot;Hello, World!&amp;quot;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A common refactor with scripts is to encapsulate all the code behavior in functions. As this script only does one thing, it&amp;rsquo;s a small change:&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Trouble with Reference Counting</title>
      <link>https://blog.dnmfarrell.com/post/the-trouble-with-reference-counting/</link>
      <pubDate>Mon, 25 Jan 2021 12:05:23 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/the-trouble-with-reference-counting/</guid>
      <description>&lt;p&gt;Perl uses a simple form of garbage collection (GC) called &lt;a href=&#34;https://en.wikipedia.org/wiki/Reference_counting&#34;&gt;reference counting&lt;/a&gt;. Every variable created by a Perl program has a &lt;a href=&#34;https://perldoc.perl.org/perlguts#Reference-Counts-and-Mortality&#34;&gt;refcnt&lt;/a&gt; associated with it. If the program creates a reference to the variable, Perl increments its &lt;code&gt;refcnt&lt;/code&gt;. Whenever Perl exits a block it reclaims any variables that belong to the block scope. If any are references, their referenced values&amp;rsquo; &lt;code&gt;refcnt&lt;/code&gt; are either decremented or they&amp;rsquo;re reclaimed as well if no other references to them remain.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Perl Closures As Objects</title>
      <link>https://blog.dnmfarrell.com/post/closures-as-objects/</link>
      <pubDate>Sun, 13 Dec 2020 12:57:03 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/closures-as-objects/</guid>
      <description>&lt;p&gt;Perl&amp;rsquo;s object system is not one of its most admired qualities. Included in the 1993 Perl 5.0 release, objects were a bolt-on. A big improvement at the time, in today&amp;rsquo;s context the Perl 5 object system requires too much boilerplate and is under-powered compared to other language offerings (no private state, no type checking, no traits, no multimethods). Perl programmers have been trying to upgrade it for years (&lt;a href=&#34;https://gist.github.com/Ovid/68b33259cb81c01f9a51612c7a294ede&#34;&gt;Cor&lt;/a&gt; is a recent example).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Inspecting Catalyst</title>
      <link>https://blog.dnmfarrell.com/post/inspecting-catalyst/</link>
      <pubDate>Mon, 11 Nov 2019 10:34:07 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/inspecting-catalyst/</guid>
      <description>&lt;p&gt;One of the convenient things about &lt;a href=&#34;https://metacpan.org/pod/Catalyst&#34;&gt;Catalyst&lt;/a&gt; is it lets you register controller methods as actions, so you don&amp;rsquo;t need a separate routing table of URIs to controller methods. A consequence of this though, is that when the web app gets large enough it can be tricky to keep track of all the different paths the app is responding to.&lt;/p&gt;&#xA;&lt;p&gt;Catalyst&amp;rsquo;s &lt;a href=&#34;https://metacpan.org/pod/Catalyst::DispatchType::Chained&#34;&gt;chained dispatch&lt;/a&gt; promotes code reuse, but exacerbates the issue by obfuscating route matching. Catalyst also permits declaring controller methods which match an unlimited number of paths after a prefix; another recipe for unpredictablity.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Creating IP Address Tools From Scratch</title>
      <link>https://blog.dnmfarrell.com/post/creating-ip-address-tools-from-scratch/</link>
      <pubDate>Thu, 19 Sep 2019 11:00:07 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/creating-ip-address-tools-from-scratch/</guid>
      <description>&lt;p&gt;Recently I&amp;rsquo;ve been researching how the Internet is organized, and working with &lt;a href=&#34;https://en.wikipedia.org/wiki/WHOIS&#34;&gt;whois&lt;/a&gt; data. I&amp;rsquo;ve been creating simple tools that process IP addresses without any help from CPAN. At work we tend to use &lt;a href=&#34;https://metacpan.org/pod/Net::IP::XS&#34;&gt;Net::IP::XS&lt;/a&gt; for these tasks, but sometimes it&amp;rsquo;s fun to figure out how things work under the hood.&lt;/p&gt;&#xA;&lt;h3 id=&#34;converting-to-decimal&#34;&gt;Converting to decimal&lt;/h3&gt;&#xA;&lt;p&gt;I&amp;rsquo;m sure you&amp;rsquo;re familiar with the IPv4 address &lt;a href=&#34;https://en.wikipedia.org/wiki/IPv4#Addressing&#34;&gt;format&lt;/a&gt;; the &amp;ldquo;dotted quad&amp;rdquo; consists of four numbers between 0 and 255 separated by periods. Your home wifi network probably starts at 192.168.0.0. The format is just another way of representing a 32-bit integer; here are the numbers and their equivalent in binary:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Find Relationships Quickly In Data With Chart::Plot</title>
      <link>https://blog.dnmfarrell.com/post/find-relationships-quickly-in-data-with-chart-plot/</link>
      <pubDate>Mon, 21 Jan 2019 15:41:39 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/find-relationships-quickly-in-data-with-chart-plot/</guid>
      <description>&lt;p&gt;Last week I was analyzing server log data at work, and my boss asked me to plot it on a scatter chart. &amp;ldquo;No problem!&amp;rdquo; I thought, firing up Google Sheets. But Sheets slowed to a crawl when I uploaded 250,000 records to plot. Using CPAN I found something better: &lt;a href=&#34;https://metacpan.org/pod/Chart::Plot&#34;&gt;Chart::Plot&lt;/a&gt;. It has a simple interface and is really fast. Here&amp;rsquo;s how you use it.&lt;/p&gt;&#xA;&lt;h3 id=&#34;a-scatter-plot-script&#34;&gt;A scatter plot script&lt;/h3&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-perl&#34;&gt;#!/usr/bin/env perl&#xA;use Chart::Plot;&#xA;&#xA;open my $mlb, &#39;&amp;lt;&#39;, &#39;2017-so-hr.csv&#39; or die $!;&#xA;&#xA;my @series;&#xA;while (&amp;lt;$mlb&amp;gt;) {&#xA;  chomp;&#xA;  my ($x, $y) = split /\t/;&#xA;  push @series, $x, $y;&#xA;}&#xA;&#xA;my $img = Chart::Plot-&amp;gt;new(800,640);&#xA;$img-&amp;gt;setData(\@series, &#39;Points Noline Blue&#39;) or die $img-&amp;gt;error;&#xA;&#xA;$img-&amp;gt;setGraphOptions (&#xA;  vertGraphOffset =&amp;gt; 100,&#xA;  horGraphOffset  =&amp;gt; 75,&#xA;  vertAxisLabel   =&amp;gt; &#39;HR&#39;,&#xA;  horAxisLabel    =&amp;gt; &#39;SO&#39;,&#xA;  title           =&amp;gt; &#39;2017 MLB Strikeouts and Home Runs&#39;,&#xA;);&#xA;&#xA;open my $fh, &#39;&amp;gt;:raw&#39;, &#39;2017-mlb-so-hr.png&#39; or die $!;&#xA;print $fh $img-&amp;gt;draw();&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;To demo Chart::Plot, I&amp;rsquo;ve extracted MLB 2017 pitching data from the &lt;a href=&#34;http://www.seanlahman.com/baseball-archive/statistics/&#34;&gt;Lahman database&lt;/a&gt; for strikeouts and home runs given up to see if there&amp;rsquo;s a relationship between them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spidering websites with Headless Chrome and Selenium</title>
      <link>https://blog.dnmfarrell.com/post/spidering-websites-with-headless-chrome-and-selenium/</link>
      <pubDate>Sun, 13 Jan 2019 20:31:37 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/spidering-websites-with-headless-chrome-and-selenium/</guid>
      <description>&lt;p&gt;Over the holidays I was working on a project that needed to download content from different websites. I needed a web spider, but the typical Perl options like &lt;a href=&#34;https://metacpan.org/pod/WWW:Mechanize&#34;&gt;WWW:Mechanize&lt;/a&gt; wouldn&amp;rsquo;t cut it, as with JavaScript controlling the content on many websites, I needed a JavaScript-enabled browser. But browsers consume lots of memory - what to do?&lt;/p&gt;&#xA;&lt;p&gt;The answer was to use headless Chrome, which works exactly like normal except it has no graphical display, reducing its memory footprint. I can control it using &lt;a href=&#34;https://metacpan.org/pod/Selenium::Remote::Driver&#34;&gt;Selenium::Remote::Driver&lt;/a&gt; and Selenium server. Here&amp;rsquo;s how I did it.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Validating Untrusted Input: Numbers</title>
      <link>https://blog.dnmfarrell.com/post/validating-untrusted-input-numbers/</link>
      <pubDate>Mon, 03 Dec 2018 09:10:38 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/validating-untrusted-input-numbers/</guid>
      <description>&lt;p&gt;Validating untrusted input safely is critical for application security: SQL injection, XSS and malicious file upload are common attacks which succeed because the user&amp;rsquo;s input is not vetted correctly.&lt;/p&gt;&#xA;&lt;p&gt;Numbers are problematic: negative numbers (&amp;ldquo;the sales price was -$500&amp;rdquo;), very large numbers (&amp;ldquo;my account balance is 9,223,372,036,854,775,807&amp;rdquo;) or not-a-number (&amp;ldquo;rm -rf /&amp;rdquo;) can all wreak havoc if not handled with care.&lt;/p&gt;&#xA;&lt;p&gt;Fortunately, Perl has robust capabilities for validating input but there are some edge cases to be aware of that make answering &amp;ldquo;is $x a number?&amp;rdquo; more difficult than you might think it would be.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Patching Perl: Loading Modules That Return False</title>
      <link>https://blog.dnmfarrell.com/post/patching-perl-loading-modules-that-return-false/</link>
      <pubDate>Mon, 23 Jul 2018 09:01:37 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/patching-perl-loading-modules-that-return-false/</guid>
      <description>&lt;p&gt;[&lt;strong&gt;Update&lt;/strong&gt;: this is now &lt;a href=&#34;https://github.com/Perl/perl5/issues/17921&#34;&gt;an issue for Perl 7&lt;/a&gt;]&lt;/p&gt;&#xA;&lt;p&gt;If you&amp;rsquo;ve been programming Perl for a while, you&amp;rsquo;ve probably run into this exception: &lt;code&gt;Foo.pm did not return a true value&lt;/code&gt;. This is a peculiar quirk of the &lt;code&gt;require&lt;/code&gt; function: modules &lt;em&gt;must&lt;/em&gt; return a true value else Perl interprets it as a failure:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The file must return true as the last statement to indicate&#xA;successful execution of any initialization code, so it&amp;rsquo;s customary&#xA;to end such a file with &amp;ldquo;1;&amp;rdquo; unless you&amp;rsquo;re sure it&amp;rsquo;ll return true&#xA;otherwise. But it&amp;rsquo;s better just to put the &amp;ldquo;1;&amp;rdquo;, in case you add&#xA;more statements.&#xA;&lt;br&gt;&#xA;&lt;em&gt;perlfunc&lt;/em&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Writing New Testing Tools With Test2</title>
      <link>https://blog.dnmfarrell.com/post/writing-new-testing-tools-with-test2/</link>
      <pubDate>Tue, 12 Jun 2018 15:26:40 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/writing-new-testing-tools-with-test2/</guid>
      <description>&lt;p&gt;Perl has had great testing tools for a long time, but &lt;a href=&#34;https://metacpan.org/pod/Test2&#34;&gt;Test2&lt;/a&gt; is the single biggest improvement to Perl testing in years. One of my favorite Test2 features is how easy it is to extend it with new tools, and today I&amp;rsquo;ll show you how I wrote my first tool.&lt;/p&gt;&#xA;&lt;h3 id=&#34;dealing-with-known-test-failures&#34;&gt;Dealing with known test failures&lt;/h3&gt;&#xA;&lt;p&gt;Ideally when your tests fail, it means that something needs to be fixed, and that thing is fixable. However in the Real World™ things aren&amp;rsquo;t always that simple. For example you might investigate a failure, figure out the root cause, but the person to fix it is on vacation. Or perhaps there&amp;rsquo;s a datetime bug in the code, and it will resolve itself in a few days. The key here is that the failure is understood and not serious but also impractical to fix in the short term.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How Does Traceroute Work?</title>
      <link>https://blog.dnmfarrell.com/post/how-does-traceroute-work-/</link>
      <pubDate>Wed, 28 Feb 2018 10:40:29 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/how-does-traceroute-work-/</guid>
      <description>&lt;p&gt;Lately I&amp;rsquo;ve been reading &lt;a href=&#34;https://www.amazon.com/Interconnections-Bridges-Switches-Internetworking-Protocols/dp/0201634481/&#34;&gt;Interconnections&lt;/a&gt; by Radia Perlman (great lastname!). It&amp;rsquo;s an old, but still relevant book which describes how low-level networking technologies work, such as ethernet. The book contains many insights and anecdotes. On page 236 I came across this gem:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The traceroute utility is a clever hack designed to force each router along the path, in turn, to return an error report. It works by setting the TTL first to 1 (causing the first router to send an error report back to the source) and then setting it to 2 (causing the next router to send an error report) and so forth until the packet reaches the destination.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Git Bisect And Perl</title>
      <link>https://blog.dnmfarrell.com/post/git-bisect-and-perl/</link>
      <pubDate>Tue, 08 Aug 2017 20:27:16 +0000</pubDate>
      <guid>https://blog.dnmfarrell.com/post/git-bisect-and-perl/</guid>
      <description>&lt;p&gt;At &lt;a href=&#34;https://ziprecruiter.com&#34;&gt;work&lt;/a&gt; we have many developers committing code to a large Git repo, and a huge test suite which runs to check the software builds and operates correctly. Inevitably, developers push commits which break a test or two, and in particularly hectic moments, it can be difficult to figure out &amp;ldquo;who broke the build&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;Enter Git&amp;rsquo;s bisect &lt;a href=&#34;https://git-scm.com/docs/git-bisect&#34;&gt;command&lt;/a&gt;. I feed it the SHA of the earliest bad commit I know of (or &amp;ldquo;HEAD&amp;rdquo;) and the SHA of the last working commit:&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
