<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.1">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-07-09T16:49:28+00:00</updated><id>/feed.xml</id><title type="html">Your awesome title</title><subtitle>Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.</subtitle><entry><title type="html">DRAFT: Learning NixOS</title><link href="/2026/07/03/nix-overview.html" rel="alternate" type="text/html" title="DRAFT: Learning NixOS" /><published>2026-07-03T00:00:00+00:00</published><updated>2026-07-03T00:00:00+00:00</updated><id>/2026/07/03/nix-overview</id><content type="html" xml:base="/2026/07/03/nix-overview.html"><![CDATA[<h1 id="draft-learning-nixos-and-its-nix-package-manager">DRAFT: Learning NixOS and its Nix Package Manager</h1>

<p class="callout">This post is currently in “Draft” status. That means it’s subject to change without me noting said changes.</p>

<p>I’ve been daily driving NixOS for over half a year now. I’m still just a beginner, but I’m slowly learning enough to be dangerous. The more I use it, the more I’m convinced that it’s the “correct” way to run software.</p>

<p>It reminds me a lot of when I learned Git. My first impression of Git was that it was just a collection of arcane commands posing as an alternative to Subversion. But the more I used it, the more I became convinced that it was the “correct” way to version control source files.</p>

<p>My “aha” moment for Git was when I realized how cheap branches and tags were, and how they allowed me to easily create checkpoints anytime I wanted. That meant that if I wanted to hack together an experimental feature just to see if it was possible – I could create a checkpoint and then get to work! If things didn’t work out, I could throw away the changes (or even check them into a branch so I could come back to them later) and go back to where I started – instantly. In other words: <em>Git made running big experiments cheap and risk free</em>.</p>

<p>My “aha” moment for NixOS was when I realized that I could put any piece of software on my system, including its <em>entire</em> dependency graph, without affecting any other piece of software that’s already on my system. At the moment, I can confidently say that <em>NixOS makes running big experiments risk free</em>, but I still have a bit to learn before I can add the “<em>cheap</em>” qualifier. I have no doubt that NixOS is fully capable of making big experiments “<em>cheap</em>”; my current inability to make it do so is due only to my lack of knowledge.</p>

<p>I’m still climbing the NixOS learning curve. To that end, I did a deep dive into NixOS this weekend, trying to get an idea of how it does what it does. My learnings follow.</p>

<h2 id="documentation">Documentation</h2>

<p>I’ve read some things on the <a href="https://wiki.nixos.org/wiki/NixOS_Wiki">NixOS Wiki</a> and I’ve read quite a bit of the <a href="https://nixos.org/guides/nix-pills/00-preface.html">Nix Pills</a> (and followed along by running their examples).</p>

<p>Both are fine resources… but they always left me wanting. It always seemed that they were too precise about things I didn’t care about and too imprecise about things I did care about.</p>

<p>Regardless, spend some time on the pills. I did – so any advice I give should be prefixed with “try doing the pills first”.</p>

<p>That being said, read the first three chapters of Eelco Dolstra’s <a href="https://edolstra.github.io/pubs/phd-thesis.pdf">PhD thesis</a>. Trust me.</p>

<h2 id="what-the-nix-package-manager-can-do">What the Nix Package Manager Can Do</h2>

<p>The Nix Package Manager is extraordinarily good at managing dependencies for software. When you install a Package on NixOS, you can be certain that the components that it depends on will never change as long as it remains installed on your system.</p>

<p>The Nix Package Manager will allow you to upgrade any component to a new version while leaving the current version untouched. If you don’t like the new version, you can instantly rollback.</p>

<p>The Nix Package Manager is also extraordinarily good at letting any component depend on any version of any other component. And by version, I don’t mean in the sense of ‘1.0.1’; I mean something far more granular. You can have one program use version ‘1.0.1’ of a library that was compiled with optimizations turned on… and another program depend on version ‘1.0.1’ of the same library compiled with optimizations turned off! Both ‘1.0.1’ versions of the same library can exist on your machine, and either can be used to build any program that depends on them. Because building software is an interesting use case for me, this is the feature that I wanted to explore.</p>

<h2 id="c-libs-and-executables">C Libs and Executables</h2>

<p>If you’ve been using Linux for a while, there’s a good chance that you’ve built some program and/or library from C source code. Over the decades, the process of doing so has become remarkably similar across projects. Tools like <a href="https://www.gnu.org/software/autoconf/">Autoconf</a>, <a href="https://www.gnu.org/software/automake/">Automake</a>, and <a href="https://www.gnu.org/software/libtool/">Libtool</a> have helped make this possible.</p>

<p>If you’ve ever opened up a Makefile that ships with the C source for a program you’ve built, you probably noticed that you can change the build process by specifying environment variables.</p>

<p><code class="language-shell highlight highlighter-rouge">INCLUDES</code>, <code class="language-shell highlight highlighter-rouge">LDFLAGS</code>, and <code class="language-shell highlight highlighter-rouge">CFLAGS</code> allow you to control compiler and linker flags. You can use these to specify build time options (where to look for header files; where to look for libraries). You can also use them for things like adding debug symbols or choosing the compiler optimization level – in which case, given the exact same source, the values passed to these environment variables can result in significantly different binaries.</p>

<p><code class="language-shell highlight highlighter-rouge">DESTDIR</code> and <code class="language-shell highlight highlighter-rouge">PREFIX</code> are two environment variables that let you determine where a given piece of software is installed.</p>

<p>Using these five variables, you can control where your project looks for its build time dependencies and where it installs to. This is one way that the Nix Package Manager can control where software is installed and where it finds its dependencies.</p>

<h2 id="my-experiment">My Experiment</h2>

<p>After months of using NixOS as my primary Linux distro, reading about NixOS, and asking Claude lots of questions… I had finally arrived at what I thought was a useful experiment that would let me learn a little about how NixOS worked.</p>

<ul>
  <li>I wanted to create a simple library whose build process could be influenced by an environment variable in a way that was easily witnessed by an end user.</li>
  <li>I wanted to create a simple program that linked against this library.</li>
  <li>I wanted the build processes of both of these projects to follow familiar conventions.</li>
  <li>I wanted to show that the Nix Package Manager could build both of these projects with no changes to their source or build files.</li>
  <li>I wanted to show that the Nix Package Manager could capture the dependency of the program on the library… and furthermore that it would allow the program to specify bespoke configurations of the library build to depend upon.</li>
  <li>Finally, I wanted to show that multiple versions of program and library could exist on the system without conflict.</li>
</ul>

<h2 id="the-code">The Code</h2>

<p>I’ll include some code in this post (I tried to keep the examples small), but all of the code can also be found <a href="https://github.com/emacdona/nixdemo">here</a>. With the caveat, of course, that the code in the repo may evolve.</p>

<h3 id="the-library">The Library</h3>

<p>As mentioned above, I wanted to have a library whose behavior could be changed at build time (via an environment variable) in such a way that was easily witnessed by a user. In other words, I won’t be modifying <code class="language-shell highlight highlighter-rouge">INCLUDES</code>, <code class="language-shell highlight highlighter-rouge">LDFLAGS</code>, or <code class="language-shell highlight highlighter-rouge">CFLAGS</code><sup id="fnref:technicallymodifying" role="doc-noteref"><a href="#fn:technicallymodifying" class="footnote" rel="footnote">1</a></sup> – because such changes are not easily witnessed.</p>

<p>Instead, my library will use a preprocessor macro to determine the string its single method returns:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"greeting.h"</span><span class="cp">
</span>
<span class="cm">/* GREETING_MESSAGE is defined at compile time via -D flag */</span>
<span class="cp">#ifndef GREETING_MESSAGE
#define GREETING_MESSAGE "Hello, World!"
#endif
</span>
<span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="nf">get_greeting</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">GREETING_MESSAGE</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The Makefile that builds my library will allow the value of this macro to be overridden via an environment variable:</p>

<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># ... code removed, see repo for entire file ...
</span>
<span class="nv">GREETING</span> <span class="o">?=</span> Hello, World!

<span class="nv">CFLAGS</span> <span class="o">+=</span> <span class="nt">-DGREETING_MESSAGE</span><span class="o">=</span><span class="s1">'"</span><span class="p">$(</span><span class="s1">GREETING</span><span class="p">)</span><span class="s1">"'</span>

<span class="c"># ... code removed, see repo for entire file ...
</span>
<span class="nl">%.o</span><span class="o">:</span> <span class="nf">%.c greeting.h</span>
	<span class="p">$(</span>CC<span class="p">)</span> <span class="p">$(</span>CFLAGS<span class="p">)</span> <span class="nt">-c</span> <span class="nv">$&lt;</span> <span class="nt">-o</span> <span class="nv">$@</span>

<span class="c"># ... code removed, see repo for entire file ...
</span></code></pre></div></div>

<h3 id="the-program">The Program</h3>

<p>The program is even simpler. It just calls the method provided by the library:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;greeting.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">get_greeting</span><span class="p">());</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Likewise, the Makefile that builds the program is simpler than the one that builds the library. In fact, there’s nothing really worth pointing out within it. Feel free to look at it in the source repo.</p>

<h3 id="building-and-installing-without-the-nix-package-manager">Building and Installing without the Nix Package Manager</h3>

<p>The Makefiles for building the library and the program follow the conventions mentioned earlier. In particular, they install into a directory determined by the <code class="language-shell highlight highlighter-rouge">DESTDIR</code> and <code class="language-shell highlight highlighter-rouge">PREFIX</code> environment variables.</p>

<p>I don’t recommend it, but if you wanted, you could <code class="language-shell highlight highlighter-rouge">make <span class="o">&amp;&amp;</span> make <span class="nb">install</span></code> the library and then the program… and it should work as expected. The reason I don’t recommend this is because it would install both in the <code class="language-shell highlight highlighter-rouge">/usr/local</code> directory tree. This is a blog post about NixOS… we want to have things installed in the Nix Store.</p>

<h2 id="nixos-terms-and-definitions">NixOS Terms and Definitions<sup id="fnref:usebeforedefining" role="doc-noteref"><a href="#fn:usebeforedefining" class="footnote" rel="footnote">2</a></sup></h2>

<p>Now that we have source code for a program and a library that it depends on, we can proceed to see how we can use the Nix Package Manager to build and install it. But before we do that, we’ll need to define some terms.</p>

<p>These definitions reflect my current mental model of how NixOS works. I won’t claim they are “correct”. One of my problems with the NixOS ecosystem is that it’s sometimes very hard to pin down what a given word means in a given context. These definitions are my attempt to at least capture my understanding.</p>

<h3 id="nix">“Nix”</h3>

<p>The word “Nix” itself can mean one of three different things. I’ve tried to take care not to use just “Nix” in this document. Instead, I try to explicitly use one of the following three terms.</p>

<h4 id="nix-expression-language">Nix Expression Language</h4>

<p>The Nix Expression Language is the programming language in which Nix Expressions are written.</p>

<h4 id="nix-package-manager">Nix Package Manager</h4>

<p>The Nix Package Manager is the suite of tools that build Derivations and manage the Nix Store.</p>

<p>The Nix Package Manager can be used to maintain a Nix Store on distros other than NixOS.</p>

<h4 id="nixos">NixOS</h4>

<p>A Linux distro whose entire configuration (not just the applications you install within it) is in the Nix Store.</p>

<h3 id="expression">Expression</h3>
<p>Independent of the Nix <strong><em>Expression</em></strong> Language, an <strong><em>Expression</em></strong> is a syntactical object (of a programming language) that evaluates to a value.</p>

<p>The Nix <strong><em>Expression</em></strong> Language is functional: “Everything is an <strong><em>Expression</em></strong>”. This model should be familiar to those who have used functional languages.</p>

<p>You can compose <strong><em>Expressions</em></strong> into larger <strong><em>Expressions</em></strong>.</p>

<h3 id="derivation">Derivation</h3>
<p>Some Expressions evaluate to <strong><em>Derivations</em></strong>. Though there are no such formal terms, in the Nix Expression Language it may be helpful to think of such Expressions as “top level Expressions” or “programs”.</p>

<p>The <strong><em>Derivation</em></strong> that these Expressions evaluate to is an in-memory structure.</p>

<p>When one of these “in-memory <strong><em>Derivations</em></strong>” is Instantiated, a store object is created. This object is ALSO called a <strong><em>Derivation</em></strong>. You can think of this “store <strong><em>Derivation</em></strong>” as a build plan for a set of Outputs. It can be Realized, resulting in the creation of these Outputs.</p>

<p>The key insight here is:</p>

<p>The store <strong><em>Derivation</em></strong> is completely determined by the inputs to the Expression whose evaluation yielded the in-memory <strong><em>Derivation</em></strong> (whose Instantiation resulted in the store <strong><em>Derivation’s</em></strong> creation). For the store <strong><em>Derivation</em></strong>, all “variability” has been removed. It is a fully specified “build plan” for a set of Outputs.</p>

<h3 id="outputs">Outputs</h3>

<p>A Derivation can be Realized to create multiple <strong><em>Outputs</em></strong>. For example, a Derivation could have separate <strong><em>Outputs</em></strong> for its runtime and its documentation. All such <strong><em>Outputs</em></strong> (once Realized) live in the Nix Store.</p>

<h3 id="nix-store">Nix Store</h3>

<p>The Nix Store is the Nix Package Manager’s database. It’s implemented right on the filesystem and is usually located at <code class="language-shell highlight highlighter-rouge">/nix/store</code>.</p>

<p>It’s a flat database: each directory or file in the <code class="language-shell highlight highlighter-rouge">/nix/store/</code> directory is a single addressable component in the store – and these directories and files are the only components of the store. Most of them are Derivations and Outputs.</p>

<h3 id="store-path">Store Path</h3>

<p>A <strong><em>Store Path</em></strong> is the coordinate (in the Nix Store) of a given store component (Output, Derivation).</p>

<h3 id="package">Package</h3>

<p>A <strong><em>Package</em></strong> is really nothing more than a name given to an Expression that evaluates to a Derivation.</p>

<p>It helps to consider an example:</p>

<p>Imagine a function named <code class="language-shell highlight highlighter-rouge">vim</code> that takes an <code class="language-shell highlight highlighter-rouge">enableGui</code> argument (whose default value is <code class="language-shell highlight highlighter-rouge"><span class="nb">false</span></code>) and returns a Derivation. Imagine that your NixOS distro, in some global namespace, assigned a name to this Expression: <code class="language-shell highlight highlighter-rouge">vim-no-gui <span class="o">=</span> vim <span class="o">{}</span></code></p>

<p>That name (<code class="language-shell highlight highlighter-rouge">vim-no-gui</code>) is a <strong><em>Package</em></strong>.</p>

<p>If you wanted to create a Derivation whose Realization would result in a version of <code class="language-shell highlight highlighter-rouge">vim</code> that <strong>did</strong> have a GUI, you could just call that function with <code class="language-shell highlight highlighter-rouge"><span class="nv">enableGui</span><span class="o">=</span><span class="nb">true</span></code>, eg: <code class="language-shell highlight highlighter-rouge">vim <span class="o">{</span>enableGui <span class="o">=</span> <span class="nb">true</span><span class="o">}</span></code>.</p>

<p>But NixOS maintainers are also free to create a <strong><em>Package</em></strong> that does the same by simply assigning a name: <code class="language-shell highlight highlighter-rouge">vim-gui <span class="o">=</span> vim <span class="o">{</span>enableGui <span class="o">=</span> <span class="nb">true</span><span class="o">}</span></code>.</p>

<h3 id="term-summary--relationships">Term Summary / Relationships</h3>

<p>Putting it all together…</p>

<p>Some Expressions, when evaluated, yield in-memory Derivations. These in-memory Derivations can be Instantiated to become store Derivations. These store Derivations can be Realized as Outputs in the Nix Store.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Expression -&gt;
  Evaluate(Expression) -&gt;
    in-memory Derivation -&gt;
      Instantiate(in-memory Derivation) -&gt;
        store Derivation -&gt;
          Realize(store Derivation) -&gt;
            Outputs
</code></pre></div></div>

<h2 id="building-and-installing-with-the-nix-package-manager">Building and Installing with the Nix Package Manager</h2>

<h3 id="derivation-creating-expressions">Derivation Creating Expressions</h3>
<p>To build the library and program with the Nix Package Manager, we create a <code class="language-shell highlight highlighter-rouge">default.nix</code> file in each project’s root. This file contains an Expression that defines a function that returns a Derivation<sup id="fnref:derivationreturningfunction" role="doc-noteref"><a href="#fn:derivationreturningfunction" class="footnote" rel="footnote">3</a></sup>. That Derivation contains all the information the Nix Package Manager needs to build the project.</p>

<p>Here is the <code class="language-shell highlight highlighter-rouge">default.nix</code> that builds the <code class="language-shell highlight highlighter-rouge">greeter</code> program:</p>
<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span> <span class="nv">stdenv</span>
<span class="p">,</span> <span class="nv">greeting</span> <span class="o">?</span> <span class="s2">"Hello, World!"</span>
<span class="p">,</span> <span class="nv">libgreeting</span> <span class="o">?</span> <span class="kr">import</span> <span class="sx">../lib</span> <span class="p">{</span> <span class="kn">inherit</span> <span class="nv">stdenv</span> <span class="nv">greeting</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}:</span>

<span class="nv">stdenv</span><span class="o">.</span><span class="nv">mkDerivation</span> <span class="p">{</span>
  <span class="nv">pname</span> <span class="o">=</span> <span class="s2">"greeter"</span><span class="p">;</span>
  <span class="nv">version</span> <span class="o">=</span> <span class="s2">"1.0.0"</span><span class="p">;</span>

  <span class="nv">src</span> <span class="o">=</span> <span class="sx">./.</span><span class="p">;</span>

  <span class="nv">buildInputs</span> <span class="o">=</span> <span class="p">[</span> <span class="nv">libgreeting</span> <span class="p">];</span>

  <span class="nv">dontConfigure</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>

  <span class="nv">buildPhase</span> <span class="o">=</span> <span class="s2">''</span><span class="err">
</span><span class="s2">    make INCLUDES="-I</span><span class="si">${</span><span class="nv">libgreeting</span><span class="si">}</span><span class="s2">/include" LDFLAGS="-L</span><span class="si">${</span><span class="nv">libgreeting</span><span class="si">}</span><span class="s2">/lib"</span><span class="err">
</span><span class="s2">  ''</span><span class="p">;</span>

  <span class="nv">installPhase</span> <span class="o">=</span> <span class="s2">''</span><span class="err">
</span><span class="s2">    make install PREFIX= DESTDIR=$out</span><span class="err">
</span><span class="s2">  ''</span><span class="p">;</span>

  <span class="nv">meta</span> <span class="o">=</span> <span class="p">{</span>
    <span class="nv">description</span> <span class="o">=</span> <span class="s2">"A greeting program (greeting: </span><span class="si">${</span><span class="nv">greeting</span><span class="si">}</span><span class="s2">)"</span><span class="p">;</span>
  <span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Note that the Derivation returned by this function includes <code class="language-shell highlight highlighter-rouge">libgreeting</code> as the only member of its <code class="language-shell highlight highlighter-rouge">buildInputs</code>.</p>

<p>Note that <code class="language-shell highlight highlighter-rouge">libgreeting</code> is passed as a parameter to the function, and its default value is the result of calling the function defined in the lib’s <code class="language-shell highlight highlighter-rouge">default.nix</code> file with the same <code class="language-shell highlight highlighter-rouge">greeting</code> parameter passed to this function.</p>

<p>Although the type of <code class="language-shell highlight highlighter-rouge">libgreeting</code> is a Derivation, when it’s used to construct the <code class="language-shell highlight highlighter-rouge">buildPhase</code> string, the Nix Expression Language’s string interpolation turns it into <code class="language-shell highlight highlighter-rouge">libgreeting</code>’s default Output path in the Nix Store. We use this fact to construct a value for the <code class="language-shell highlight highlighter-rouge">INCLUDES</code> and <code class="language-shell highlight highlighter-rouge">LDFLAGS</code> variables that will be passed to <code class="language-shell highlight highlighter-rouge">make</code> when the Nix Package Manager runs it. This is how the Nix Package Manager informs <code class="language-shell highlight highlighter-rouge">greeter</code>’s build process of where it put its dependencies.</p>

<p>The Derivation returned by this function, from the Nix Package Manager’s point of view, is completely determined by its inputs<sup id="fnref:inputbased" role="doc-noteref"><a href="#fn:inputbased" class="footnote" rel="footnote">4</a></sup>. The key variable input is <code class="language-shell highlight highlighter-rouge">libgreeting</code>, and that input is a Derivation that results from calling the function defined in <code class="language-shell highlight highlighter-rouge">lib/default.nix</code> with the <code class="language-shell highlight highlighter-rouge">greeting</code> parameter.</p>

<p>Here’s the <code class="language-shell highlight highlighter-rouge">default.nix</code> that builds the <code class="language-shell highlight highlighter-rouge">libgreeting</code> library:</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span> <span class="nv">stdenv</span>
<span class="p">,</span> <span class="nv">greeting</span> <span class="o">?</span> <span class="s2">"Hello, World!"</span>
<span class="p">}:</span>

<span class="nv">stdenv</span><span class="o">.</span><span class="nv">mkDerivation</span> <span class="p">{</span>
  <span class="nv">pname</span> <span class="o">=</span> <span class="s2">"libgreeting"</span><span class="p">;</span>
  <span class="nv">version</span> <span class="o">=</span> <span class="s2">"1.0.0"</span><span class="p">;</span>

  <span class="nv">src</span> <span class="o">=</span> <span class="sx">./.</span><span class="p">;</span>

  <span class="c"># Pass the greeting to the Makefile via environment variable</span>
  <span class="nv">GREETING</span> <span class="o">=</span> <span class="nv">greeting</span><span class="p">;</span>

  <span class="c"># No configure phase needed for this simple Makefile</span>
  <span class="nv">dontConfigure</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>

  <span class="nv">buildPhase</span> <span class="o">=</span> <span class="s2">''</span><span class="err">
</span><span class="s2">    make</span><span class="err">
</span><span class="s2">  ''</span><span class="p">;</span>

  <span class="nv">installPhase</span> <span class="o">=</span> <span class="s2">''</span><span class="err">
</span><span class="s2">    make install PREFIX= DESTDIR=$out</span><span class="err">
</span><span class="s2">  ''</span><span class="p">;</span>

  <span class="nv">meta</span> <span class="o">=</span> <span class="p">{</span>
    <span class="nv">description</span> <span class="o">=</span> <span class="s2">"A simple greeting library (greeting: </span><span class="si">${</span><span class="nv">greeting</span><span class="si">}</span><span class="s2">)"</span><span class="p">;</span>
  <span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Because the Derivation returned by this function uses the value of <code class="language-shell highlight highlighter-rouge">greeting</code> in its definition, that means that this function creates <em>different</em> Derivations for different values of the <code class="language-shell highlight highlighter-rouge">greeting</code> parameter passed to it. The Derivation returned by the function defined in <code class="language-shell highlight highlighter-rouge">program/default.nix</code> can depend on any one of these Derivations.</p>

<p>Since a Derivation is also determined by its inputs, the function defined in <code class="language-shell highlight highlighter-rouge">program/default.nix</code> returns a different Derivation for every different value of <code class="language-shell highlight highlighter-rouge">libgreeting</code>.</p>

<p>In other words, when building <code class="language-shell highlight highlighter-rouge">greeter</code>, each value you choose for <code class="language-shell highlight highlighter-rouge">greeting</code> yields a different Derivation of <code class="language-shell highlight highlighter-rouge">libgreeting</code> to be built. <code class="language-shell highlight highlighter-rouge">libgreeting</code> being the key variable input to <code class="language-shell highlight highlighter-rouge">greeter</code>, this causes a different Derivation of <code class="language-shell highlight highlighter-rouge">greeter</code> to be built. For each value of <code class="language-shell highlight highlighter-rouge">greeting</code>, you get two Outputs in the store: one for <code class="language-shell highlight highlighter-rouge">greeter</code>, one for <code class="language-shell highlight highlighter-rouge">libgreeting</code>.</p>

<p>It’s easier to see with an example.</p>

<h2 id="running-the-build">Running the Build</h2>

<p>In the source directory, there are two files, <code class="language-shell highlight highlighter-rouge">demo01.nix</code> and <code class="language-shell highlight highlighter-rouge">demo02.nix</code>. They differ <em>only</em> in the <code class="language-shell highlight highlighter-rouge">greeting</code> they pass to the function defined in <code class="language-shell highlight highlighter-rouge">./program/default.nix</code>, so I’ll just show <code class="language-shell highlight highlighter-rouge">demo01.nix</code>:</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span>
  <span class="nv">pkgs</span> <span class="o">=</span> <span class="kr">import</span> <span class="o">&lt;</span><span class="nv">nixpkgs</span><span class="o">&gt;</span> <span class="p">{};</span>
<span class="kn">in</span>
<span class="nv">pkgs</span><span class="o">.</span><span class="nv">callPackage</span> <span class="sx">./program</span> <span class="p">{</span>
  <span class="nv">greeting</span> <span class="o">=</span> <span class="s2">"Hello from Demo 01!"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Given those two files, we can run the following two commands:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nix-build demo01.nix <span class="nt">-o</span> demo01
nix-build demo02.nix <span class="nt">-o</span> demo02
</code></pre></div></div>

<p>Those commands will (for the single Expression in each file) go through the whole process starting with Expression evaluation all the way through to Output creation.</p>

<p>The first time you run them, you’ll see the whole build process (for library <em>and</em> program!) followed by the Nix Package Manager telling you where it placed the program (<code class="language-shell highlight highlighter-rouge">greeter</code>) in the store. If you run them again, the Nix Package Manager recognizes that it has already built them… and just shows you where it put them in the store:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$&gt; nix-build demo01.nix -o demo01
/nix/store/32w8g2sjafhj8iag8v2hb1q1s0mmjw56-greeter-1.0.0

$&gt; nix-build demo02.nix -o demo02
/nix/store/hnznyz5p9ymaxx61phsis0q9kh7i1aaw-greeter-1.0.0
</code></pre></div></div>

<h3 id="examining-the-output">Examining the Output</h3>

<p>Because we specified the <code class="language-shell highlight highlighter-rouge"><span class="nt">-o</span></code> switch to <code class="language-shell highlight highlighter-rouge">nix-build</code>, it also created two symlinks<sup id="fnref:gcroots" role="doc-noteref"><a href="#fn:gcroots" class="footnote" rel="footnote">5</a></sup> in the local directory:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$&gt;</span> <span class="nb">ls</span> <span class="nt">-l</span> demo01 demo02
lrwxrwxrwx 1 1024 <span class="nb">users </span>57 Jul  4 19:11 demo01 -&gt; /nix/store/32w8g2sjafhj8iag8v2hb1q1s0mmjw56-greeter-1.0.0
lrwxrwxrwx 1 1024 <span class="nb">users </span>57 Jul  4 19:11 demo02 -&gt; /nix/store/hnznyz5p9ymaxx61phsis0q9kh7i1aaw-greeter-1.0.0
</code></pre></div></div>

<p>We can use these symlinks to run the programs:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$&gt;</span> ./demo01/bin/greeter
Hello from Demo 01!
<span class="nv">$&gt;</span> ./demo02/bin/greeter
Hello from Demo 02!
</code></pre></div></div>

<p>But what about the libraries? Well, we can ask the Nix Package Manager to show us the dependency graph for both executables:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$&gt;</span> nix-store <span class="nt">-q</span> <span class="nt">--tree</span> ./demo01 | <span class="nb">cat</span>
/nix/store/32w8g2sjafhj8iag8v2hb1q1s0mmjw56-greeter-1.0.0
├───/nix/store/vr7ds8vwbl2fz7pr221d5y0f8n9a5wda-glibc-2.40-218
│   ├───/nix/store/2a3izq4hffdd9r9gb2w6q2ibdc86kss6-xgcc-14.3.0-libgcc
│   ├───/nix/store/hxcmad417fd8ql9ylx96xpak7da06yiv-libidn2-2.3.8
│   │   ├───/nix/store/3rkccxj7vi0p2a0d48c4a4z2vv2cni88-libunistring-1.4.1
│   │   │   └───/nix/store/3rkccxj7vi0p2a0d48c4a4z2vv2cni88-libunistring-1.4.1 <span class="o">[</span>...]
│   │   └───/nix/store/hxcmad417fd8ql9ylx96xpak7da06yiv-libidn2-2.3.8 <span class="o">[</span>...]
│   └───/nix/store/vr7ds8vwbl2fz7pr221d5y0f8n9a5wda-glibc-2.40-218 <span class="o">[</span>...]
└───/nix/store/fhscgmiy6gsjmghbx4nyb9djn68fxjvg-libgreeting-1.0.0
    └───/nix/store/vr7ds8vwbl2fz7pr221d5y0f8n9a5wda-glibc-2.40-218 <span class="o">[</span>...]

<span class="nv">$&gt;</span> nix-store <span class="nt">-q</span> <span class="nt">--tree</span> ./demo02 | <span class="nb">cat</span>
/nix/store/hnznyz5p9ymaxx61phsis0q9kh7i1aaw-greeter-1.0.0
├───/nix/store/vr7ds8vwbl2fz7pr221d5y0f8n9a5wda-glibc-2.40-218
│   ├───/nix/store/2a3izq4hffdd9r9gb2w6q2ibdc86kss6-xgcc-14.3.0-libgcc
│   ├───/nix/store/hxcmad417fd8ql9ylx96xpak7da06yiv-libidn2-2.3.8
│   │   ├───/nix/store/3rkccxj7vi0p2a0d48c4a4z2vv2cni88-libunistring-1.4.1
│   │   │   └───/nix/store/3rkccxj7vi0p2a0d48c4a4z2vv2cni88-libunistring-1.4.1 <span class="o">[</span>...]
│   │   └───/nix/store/hxcmad417fd8ql9ylx96xpak7da06yiv-libidn2-2.3.8 <span class="o">[</span>...]
│   └───/nix/store/vr7ds8vwbl2fz7pr221d5y0f8n9a5wda-glibc-2.40-218 <span class="o">[</span>...]
└───/nix/store/sazax1y1k7ab5h5k5m2hbrky7s9dnadb-libgreeting-1.0.0
    └───/nix/store/vr7ds8vwbl2fz7pr221d5y0f8n9a5wda-glibc-2.40-218 <span class="o">[</span>...]
</code></pre></div></div>

<p>If you look closely, you’ll see they depend on two different <code class="language-shell highlight highlighter-rouge">libgreeting</code> libraries. Perhaps even more surprising, however, is that they <em>share</em> the same outputs for all other dependencies they have in common. The Nix Package Manager manages all that for you!</p>

<h2 id="how-the-nix-package-manager-enables-this">How the Nix Package Manager Enables This</h2>

<p>Let’s take another look at this diagram:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Expression -&gt;
  Evaluate(Expression) -&gt;
    in-memory Derivation -&gt;
      Instantiate(in-memory Derivation) -&gt;
        store Derivation -&gt;
          Realize(store Derivation) -&gt;
            Outputs
</code></pre></div></div>

<p>Now let’s justify each step:</p>

<h3 id="expression-1">Expression</h3>

<p>The Expressions we created (in the <code class="language-shell highlight highlighter-rouge">default.nix</code> files) define functions with parameters of our choosing. Each of these functions builds and returns a Derivation.</p>

<p>We are free to use the arguments passed into this function when it is called to construct the Derivation however we see fit. Perhaps most interesting: we can use these arguments to compute the <code class="language-shell highlight highlighter-rouge">inputs</code> of the Derivation.</p>

<p>For example, given a source code repository (which includes source code along with any scripts and metadata required to convert the source code to an executable artifact), we can create an Expression (function) whose parameters capture any and all variability in our build process. For example: branch name; version number; compiler flags; upstream dependencies; etc.</p>

<p>In the function body, we can specify how a Derivation (and even its inputs) are constructed given the values (arguments) we assign to these parameters.</p>

<h3 id="evaluation-of-expression">Evaluation of Expression</h3>

<p>Evaluation of the Expression simply takes the arguments we’ve passed to the function and uses them to compute the in-memory Derivation.</p>

<h3 id="in-memory-derivation">In-Memory Derivation</h3>

<p>Assuming we’re using input addressing<sup id="fnref:inputbased:1" role="doc-noteref"><a href="#fn:inputbased" class="footnote" rel="footnote">4</a></sup>, at this point the Store Location of every Output in the entire dependency graph of the Derivation is known (or can be determined).</p>

<p>The store location of <em>this Derivation</em> is a function of all of its inputs. That is, this Derivation is specific to the exact combination of inputs that were used to create it. The same is true for every input in this Derivation’s entire dependency graph.</p>

<h3 id="instantiate">Instantiate</h3>

<p>Our in-memory Derivation is serialized to disk at its own address in the Nix Store.</p>

<h3 id="store-derivation">Store Derivation</h3>

<p>Now that the Derivation exists in the Store, any Nix Package Manager process attempting to Realize this Derivation or any of its downstream Derivations (those Derivations that depend on this Derivation’s Outputs) now has a template that tells it how to do so.</p>

<h3 id="realize-the-derivation">Realize the Derivation</h3>

<p>Okay, now we actually want to run some binaries. So we Realize the Derivation, which forces it to be built. This will also recursively Realize this Derivation’s entire dependency graph (skipping any that have already been Realized).</p>

<h3 id="output">Output</h3>

<p>Now there is an actual (in our case) binary in the store that we can run!</p>

<h2 id="summary">Summary</h2>

<p>So, what have we shown here? Well, in particular, we’ve shown that you can build as many versions of a binary as you want, where the definition of “version” takes into account any “versions” of upstream libraries you may also be building from source.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:technicallymodifying" role="doc-endnote">
      <p>Okay, technically I am modifying <code class="language-shell highlight highlighter-rouge">CFLAGS</code>, but only because that’s how you define preprocessor macros at compile time. What I mean is that I’m not passing arguments that change how the compiler behaves; e.g.: <code class="language-shell highlight highlighter-rouge"><span class="nt">-O3</span></code>. <a href="#fnref:technicallymodifying" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:usebeforedefining" role="doc-endnote">
      <p>I’ve already used some of these terms before defining them. I apologize for that, but it was hard to structure this document. <a href="#fnref:usebeforedefining" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:derivationreturningfunction" role="doc-endnote">
      <p>This Derivation-returning function is what is expected by the Nix Expression Language provided <code class="language-shell highlight highlighter-rouge">callPackage</code> function, which we will be using in just a bit to kick off the build process. <a href="#fnref:derivationreturningfunction" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:inputbased" role="doc-endnote">
      <p>This is known as “input addressing”. If you want to go down a rabbit hole, contrast this with “content addressing” (which is currently being worked on for NixOS). <a href="#fnref:inputbased" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:inputbased:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:gcroots" role="doc-endnote">
      <p>These symlinks are one instance of what is known as a Garbage Collection (GC) Root. There are different ways in which the Nix Package Manager creates GC Roots. Here, they are the output of the build process – a convenience. More interesting are Profiles and Generations… the tools NixOS uses to manage a bespoke execution environment for every user on the system. Any Output reachable via an existing GC Root’s graph will not be garbage collected when you run <code class="language-shell highlight highlighter-rouge">nix-collect-garbage</code>. I wanted to talk more about GC Roots, Profiles, and Generations… but this post is too long already! <a href="#fnref:gcroots" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><summary type="html"><![CDATA[DRAFT: Learning NixOS and its Nix Package Manager]]></summary></entry><entry><title type="html">CORS Lite</title><link href="/2025/12/19/cors.html" rel="alternate" type="text/html" title="CORS Lite" /><published>2025-12-19T00:00:00+00:00</published><updated>2025-12-19T00:00:00+00:00</updated><id>/2025/12/19/cors</id><content type="html" xml:base="/2025/12/19/cors.html"><![CDATA[<h1 id="cors-lite">CORS Lite</h1>

<p>Every time I see a CORS error, I have to rebuild my mental model of how CORS works. Maybe I don’t see CORS errors often enough, or maybe I’m just getting old. For whatever reason, I just can’t retain that model. But… every single time I try to rebuild it, I get it wrong. This blog post is for me – something to refer back to the next time I’m wondering what CORS is.</p>

<p>There are lots of docs you can read online if you want a reference. This is not a reference; this is the “Lite” version.</p>

<h2 id="what-is-cors">What is CORS?</h2>

<p>Actually, one of those <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS">online references</a> mentioned above has a perfectly fine definition:</p>

<p>“Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.”</p>

<h2 id="my-errors">My Error(s)</h2>

<p>My first problem is one of terminology. I always think of <strong>server</strong> as the URL I typed into my browser. In fact, that is the <strong>origin</strong>. The <strong>server</strong> is the resource server from which the page (loaded from the <strong>origin</strong>) requests resources.</p>

<p>With that clarified, we can state my true problem using the same language as the definition:</p>

<p>I gravitate towards the understanding that it is the <strong>origin</strong> that tells my browser which resource <strong>servers</strong> it trusts.</p>

<p>This seems natural to me. Shouldn’t it be the page I am visiting that determines which pages it trusts to load content from? Nope.</p>

<h2 id="why-im-wrong">Why I’m Wrong</h2>

<p>To understand why I’m wrong, it helps to use concrete examples – instead of the abstract “<strong>origin</strong> A loads resources from <strong>server</strong> B” types of examples.</p>

<p>Let’s say you do your banking with (<strong>origin</strong>) <code class="language-shell highlight highlighter-rouge">https://www.mybank.example.com</code>. They’ve got a modern website: a JavaScript frontend app that makes calls to a web service backend. The frontend authenticates you, stores your credentials in a cookie, and sends that cookie with every request it makes to the backend. One of those backend services is <code class="language-shell highlight highlighter-rouge">/transfer_to/&lt;routing_number&gt;/&lt;account_number&gt;/&lt;amount&gt;</code>.</p>

<p>Actually, that’s not quite accurate. Since your credentials are in a cookie, the frontend app doesn’t actively send them. It relies on the browser to send the cookie with every XMLHttpRequest it makes to the backend web services. That’s an important distinction: if your browser stored a cookie for <code class="language-shell highlight highlighter-rouge">www.mybank.example.com</code>, it will send that cookie for every request it makes to <code class="language-shell highlight highlighter-rouge">www.mybank.example.com</code>.</p>

<p>So let’s say you go to your bank, log in, and use their bill payment system to send a rent check to your landlord. Having taken care of that, it’s time to crack open a beer and watch a movie. So, after opening that beer, you go to your favorite source of online content, <code class="language-shell highlight highlighter-rouge">https://www.shadymovietorrenting.example.com</code>.</p>

<p>You never logged out of your bank’s website though. So the credentials in the cookie are still there, and they’re still valid…</p>

<p>And guess what? When you open <code class="language-shell highlight highlighter-rouge">https://www.shadymovietorrenting.example.com</code>, it makes this XMLHttpRequest:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://www.mybank.example.com/transfer_to/555/1234/10000
</code></pre></div></div>

<p>Your browser happily attaches the cookie to the request, your bank accepts the (valid) credentials, and you’re out $10,000.</p>

<h2 id="the-correct-model">The Correct Model</h2>

<p>The number of websites (<strong>servers</strong>) that you trust is much smaller than the number of websites (<strong>origins</strong>) that you navigate to in your web browser. For those <strong>servers</strong> that you do trust, CORS allows them to tell your browser which <strong>origins</strong> they allow to access their resources.</p>

<p>The good news is that your browser’s default policy is “same-origin only”. That’s why the example I gave above never happens in the wild.</p>

<p>Disclaimer:
I created the first few drafts of this post before asking an LLM to be my editor. There were em dashes and semicolons in the original – that’s just how I write. You can believe me; or not. I don’t care ;-)</p>]]></content><author><name></name></author><summary type="html"><![CDATA[CORS Lite]]></summary></entry><entry><title type="html">F#: There was always an Option</title><link href="/2025/11/28/fsharp.html" rel="alternate" type="text/html" title="F#: There was always an Option" /><published>2025-11-28T00:00:00+00:00</published><updated>2025-11-28T00:00:00+00:00</updated><id>/2025/11/28/fsharp</id><content type="html" xml:base="/2025/11/28/fsharp.html"><![CDATA[<h1 id="f-there-was-always-an-option">F#: There was always an Option</h1>

<p>I’ve been messing around with F# lately. I’ve glanced at ML/OCaml/F# code before, but this is my first experience really working in an ML descendant. So far, I’m really liking what I see. Today I encountered something that I found interesting enough to write a few paragraphs about.</p>

<h2 id="options">Options</h2>

<p>If you’re not familiar with what an <strong><em>Option</em></strong> type is, take a look at the <a href="https://en.wikipedia.org/wiki/Option_type">Wikipedia page</a>. I’ll attempt to describe it very briefly as:</p>

<p><em>Option: A type that wraps a value of another type, where that value may or may not be present.</em></p>

<p>Proponents would say that <strong><em>Options</em></strong> are a better alternative to <strong><em>null</em></strong> when you desire to express a value which may not exist, because they force you to deal with that fact at compile time.</p>

<p>There is a LOT more to say about Options, but this isn’t a blog post about why they exist. This is a blog post about an interesting design choice that appears in a language where library creators have always been able to assume they are present.</p>

<h2 id="filtering-transforming-and-choosing-with-options">Filtering, Transforming, and Choosing with Options</h2>

<p>The <strong><em>Option</em></strong> type isn’t unique to F#. Java, for example, has <strong><em>Optional</em></strong>. However, whereas Java’s <strong><em>Optional</em></strong> is a feature that was added to a language that had already been around for a long time (it was added in Java 1.8), F#’s <strong><em>option</em></strong> type has been in the language since its inception. In fact, my second edition of <em>ML for the Working Programmer</em>, published in 1996, lists an <strong><em>option</em></strong> type as part of ML’s standard library. In other words, F#’s ancestor had options since at least 1996 (and probably long before).</p>

<p>This means that all F# code in existence was written for a platform where <strong><em>option</em></strong> existed from day one. This has led to library functions that would never have occurred to someone who’s been writing Java for over two decades (me).</p>

<h3 id="java-example">Java Example</h3>

<p>All programming languages that I’ve used have had some sort of <strong><em>collection</em></strong> abstraction, and they’ve all had <em>at least</em> the two following operations defined for collections: <strong><em>filter</em></strong> and <strong><em>transform</em></strong>. Sure, these operations often go by different names (<strong><em>grep</em></strong>, <strong><em>remove-if-not</em></strong>, <strong><em>map</em></strong>, …) – but they are always there.</p>

<p>The <strong><em>filter</em></strong> function takes two arguments: a collection and a unary predicate. It returns a new collection containing only the elements of the original collection for which the predicate returns <strong><em>true</em></strong>.</p>

<p>The <strong><em>transform</em></strong> function takes two arguments: a collection and a unary function. It returns a new collection whose elements are the result of applying the function to each element in the original collection.</p>

<p>For example: let’s say that given a collection of integers, you wish to take only the even ones and divide them by three, resulting in a collection of floating point numbers. In Java, that could be accomplished as follows:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$&gt;</span> jshell

jshell&gt; var ints <span class="o">=</span> IntStream.rangeClosed<span class="o">(</span>1,10<span class="o">)</span>.mapToObj<span class="o">(</span>Integer::valueOf<span class="o">)</span>.collect<span class="o">(</span>Collectors.toList<span class="o">())</span>
ints <span class="o">==&gt;</span> <span class="o">[</span>1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

jshell&gt; ints.get<span class="o">(</span>0<span class="o">)</span>.getClass<span class="o">()</span>
<span class="nv">$27</span> <span class="o">==&gt;</span> class java.lang.Integer

jshell&gt; var floats <span class="o">=</span> ints.stream<span class="o">()</span>.filter<span class="o">(</span>n -&gt; n % 2 <span class="o">==</span> 0<span class="o">)</span>.map<span class="o">(</span>i-&gt;i/3.0<span class="o">)</span>.collect<span class="o">(</span>Collectors.toList<span class="o">())</span>
floats <span class="o">==&gt;</span> <span class="o">[</span>0.6666666666666666, 1.3333333333333333, 2.0, 2.6 ... 66665, 3.3333333333333335]

jshell&gt; floats.get<span class="o">(</span>0<span class="o">)</span>.getClass<span class="o">()</span>
<span class="nv">$29</span> <span class="o">==&gt;</span> class java.lang.Double
</code></pre></div></div>

<p>Most of that code is boilerplate that lets me show you the types of the expressions (to convince you that I started with <strong><em>ints</em></strong> and ended up with <strong><em>floats</em></strong>). The really important part is:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var floats <span class="o">=</span> ints.stream<span class="o">()</span>.filter<span class="o">(</span>n -&gt; n % 2 <span class="o">==</span> 0<span class="o">)</span>.map<span class="o">(</span>i-&gt;i/3.0<span class="o">)</span>.collect<span class="o">(</span>Collectors.toList<span class="o">())</span>
</code></pre></div></div>

<p>Note the successive calls to <strong><em>filter</em></strong> and <strong><em>map</em></strong> (a.k.a.: <strong><em>transform</em></strong>). This is the tried and true method of solving this type of problem that I’ve been using for over two decades.</p>

<h3 id="f-example">F# Example</h3>

<p>In F#, the same example uses <strong><em>options</em></strong> to merge the <strong><em>filter</em></strong> and <strong><em>transform</em></strong> operations into the same function! Perhaps to you this may seem like a little thing… but when I saw it, I was taken aback. It’s always interesting to see a new way of doing something you’ve been doing the same way for your entire career:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$&gt;</span> dotnet fsi

<span class="o">&gt;</span> List.choose<span class="p">;;</span>
val it: <span class="o">((</span><span class="s1">'a -&gt; '</span>b option<span class="o">)</span> -&gt; <span class="s1">'a list -&gt; '</span>b list<span class="o">)</span>

<span class="o">&gt;</span> <span class="nb">let </span>ints <span class="o">=</span> <span class="o">[</span>1..10]<span class="p">;;</span>
val ints: int list <span class="o">=</span> <span class="o">[</span>1<span class="p">;</span> 2<span class="p">;</span> 3<span class="p">;</span> 4<span class="p">;</span> 5<span class="p">;</span> 6<span class="p">;</span> 7<span class="p">;</span> 8<span class="p">;</span> 9<span class="p">;</span> 10]

<span class="o">&gt;</span> ints |&gt; List.choose<span class="o">(</span>fun i -&gt; <span class="k">if </span>i % 2 <span class="o">=</span> 0 <span class="k">then </span>Some<span class="o">(</span>float i / 3.0<span class="o">)</span> <span class="k">else </span>None<span class="o">)</span><span class="p">;;</span>
val it: float list <span class="o">=</span>
  <span class="o">[</span>0.6666666667<span class="p">;</span> 1.333333333<span class="p">;</span> 2.0<span class="p">;</span> 2.666666667<span class="p">;</span> 3.333333333]
</code></pre></div></div>

<p>Look at the signature of <strong><em>List.choose</em></strong>, the method that both “filters” and “transforms”:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>('a -&gt; 'b option) -&gt; 'a list -&gt; 'b list
</code></pre></div></div>

<p><strong><em>List.choose</em></strong>, as its only parameter, takes a function that maps a value of type <strong><em>‘a</em></strong> to an <strong><em>option</em></strong> of type <strong><em>‘b</em></strong>. That function can do two things:</p>
<ol>
  <li>Convert an instance of <strong><em>‘a</em></strong> to an instance of <strong><em>‘b</em></strong></li>
  <li>Indicate inclusion-in or exclusion-from the result via an <strong><em>option</em></strong></li>
</ol>

<p>Given this argument, <strong><em>List.choose</em></strong> then builds a function that can be applied to an input collection (<strong><em>ints</em></strong> in the example) to generate an output collection that has undergone both a “filter” and a “transform”!</p>

<p>Okay, in the spirit of full disclosure: sure, F# also has <strong><em>List.filter</em></strong> and <strong><em>List.map</em></strong> (a.k.a.: <strong><em>transform</em></strong>). <em>Still</em>, I still find it very interesting that the <strong><em>option</em></strong> type allowed them to include <strong><em>List.choose</em></strong> in the standard library. Perhaps it is even <em>more</em> interesting that they opted to do so.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[F#: There was always an Option]]></summary></entry><entry><title type="html">Spring @Cacheable</title><link href="/2024/06/25/spring-cacheable.html" rel="alternate" type="text/html" title="Spring @Cacheable" /><published>2024-06-25T00:00:00+00:00</published><updated>2024-06-25T00:00:00+00:00</updated><id>/2024/06/25/spring-cacheable</id><content type="html" xml:base="/2024/06/25/spring-cacheable.html"><![CDATA[<h1 id="spring-declarative-caching">Spring Declarative Caching</h1>

<p><em>This blog post was also published (with permission) <a href="https://www.solutionstreet.com/blog/2024/08/21/spring-declarative-caching/">on my employer’s website</a>.</em></p>

<p><em>Disclaimer: My views and opinions are my own and do not necessarily reflect those of my employer.</em></p>

<h2 id="why-this-blog-post">Why this blog post?</h2>

<p>Recently at work, I had occasion to consider using Spring’s <code class="language-java highlight highlighter-rouge"><span class="nd">@Cacheable</span></code> annotation. I searched the web for
some hints on how to use it, but wasn’t satisfied with any of the results. Even my favorite source<sup id="fnref:baeldung" role="doc-noteref"><a href="#fn:baeldung" class="footnote" rel="footnote">1</a></sup>
of bite-size Java code samples had examples that I felt
were <a href="https://www.baeldung.com/spring-cache-tutorial#2-cacheevict">too</a> <a href="https://www.baeldung.com/spring-cache-tutorial#3-cacheput">simple</a>.
Using “lookup” methods
as examples of places where you may want to put <code class="language-java highlight highlighter-rouge"><span class="nd">@CacheEvict</span></code> and <code class="language-java highlight highlighter-rouge"><span class="nd">@CachePut</span></code> annotations seemed misleading
to me.</p>

<p>So, at the very least, I wanted to provide more substantial examples. In particular, I wanted to show why Spring’s
default cache implementation requires careful thought in a distributed application environment.</p>

<p>In the process, I ended up going off the rails a bit. I spent way more time setting up an environment in which I could
run my examples than I did writing actual Java code.
But, in a way, that’s great! If you came here to read Java code, the good new is: there’s not a lot of it.</p>

<h2 id="code">Code</h2>

<p>For this blog post, I bootstrapped a Spring project using the <a href="https://start.spring.io/">spring initializr</a> and
then <a href="https://github.com/emacdona/blog-spring-cacheable">put it on Github</a>.</p>

<p>To run the examples with the least amount of fuss, you’ll need <code class="language-shell highlight highlighter-rouge">docker</code>, <code class="language-shell highlight highlighter-rouge">docker compose</code>, (gnu)
<code class="language-shell highlight highlighter-rouge">make</code>, <code class="language-shell highlight highlighter-rouge">curl</code>, and <code class="language-shell highlight highlighter-rouge">jq</code>. If you have those tools, things <em>should</em> go smoothly. However,
it <em>is</em> software… so, you know… good luck. If it breaks, you’ve got the source code!</p>

<p>For examples that show a command typed at a prompt, this character is my prompt: <code class="language-shell highlight highlighter-rouge">✗</code></p>

<h2 id="big-picture">Big Picture</h2>

<p>Broadly speaking, you’d like to cache return values of methods that are expensive to compute. You can measure 
“expensive” in different ways (eg: CPU or memory used); but often, when
we say “expensive”, we mean “it takes too much time”.</p>

<p>If we assume that all methods in question are “functions” in the mathematical sense – ie: given the same inputs (to
include the instance the method is operating on), they always give the same output – then caching is pretty simple. Any 
return value of such a method can be cached indefinitely, and the only decisions you need to make with respect to your 
cache are:</p>
<ol>
  <li>How big can it get?</li>
  <li>Which eviction policy do you choose to ensure the size constraint is maintained?</li>
</ol>

<p>If we do <strong><em>not</em></strong> assume that the method in question are functions<sup id="fnref:fibonacci" role="doc-noteref"><a href="#fn:fibonacci" class="footnote" rel="footnote">2</a></sup>, then we can consider much more interesting examples.</p>

<p>For instance: consider a service that, given an identifier, retrieves a record from a relational database. Assume that this
database has multiple clients, each of which can update records. Should you expect that, given the same identifier, the service
will return the same record now that it did six hours ago? Of course not: the record could have been updated in the 
intervening time.</p>

<h2 id="sample-application">Sample Application</h2>

<p>The sample application includes a very simple service for managing a database of books. It uses Spring declarative 
caching to minimize database lookups. It lets you:</p>
<ol>
  <li>Retrieve books</li>
  <li>Change books’ titles</li>
</ol>

<p>Following is a stripped down version of the RestController class that implements the API for our service (see the
source code for the complete class).</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/books"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">BookRestController</span> <span class="o">{</span>
  <span class="kd">private</span> <span class="kd">final</span> <span class="nc">BookRepository</span> <span class="n">bookRepository</span><span class="o">;</span>

  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/clear"</span><span class="o">)</span>
  <span class="nd">@CacheEvict</span><span class="o">(</span><span class="n">cacheNames</span> <span class="o">=</span> <span class="s">"books"</span><span class="o">,</span> <span class="n">allEntries</span> <span class="o">=</span> <span class="kc">true</span><span class="o">)</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">clearCache</span><span class="o">()</span> <span class="o">{</span>
  <span class="o">}</span>

  <span class="nd">@GetMapping</span>
  <span class="kd">public</span> <span class="nc">Collection</span><span class="o">&lt;</span><span class="nc">Book</span><span class="o">&gt;</span> <span class="nf">books</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">bookRepository</span><span class="o">.</span><span class="na">findAll</span><span class="o">();</span>
  <span class="o">}</span>

  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/{isbn}"</span><span class="o">)</span>
  <span class="nd">@Cacheable</span><span class="o">(</span><span class="n">cacheNames</span> <span class="o">=</span> <span class="s">"books"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">Book</span> <span class="nf">bookByIsbn</span><span class="o">(</span><span class="nd">@PathVariable</span><span class="o">(</span><span class="s">"isbn"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">isbn</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">bookRepository</span><span class="o">.</span><span class="na">findByIsbn</span><span class="o">(</span><span class="n">isbn</span><span class="o">);</span>
  <span class="o">}</span>

  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/{isbn}/badUpdateTitle/{title}"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">Book</span> <span class="nf">badUpdateTitle</span><span class="o">(</span><span class="nd">@PathVariable</span><span class="o">(</span><span class="s">"isbn"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">isbn</span><span class="o">,</span>
                             <span class="nd">@PathVariable</span><span class="o">(</span><span class="s">"title"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">title</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">bookRepository</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">bookRepository</span><span class="o">.</span><span class="na">findByIsbn</span><span class="o">(</span><span class="n">isbn</span><span class="o">).</span><span class="na">withTitle</span><span class="o">(</span><span class="n">title</span><span class="o">));</span>
  <span class="o">}</span>

  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/{isbn}/betterUpdateTitle/{title}"</span><span class="o">)</span>
  <span class="nd">@CacheEvict</span><span class="o">(</span><span class="n">cacheNames</span> <span class="o">=</span> <span class="s">"books"</span><span class="o">,</span> <span class="n">key</span> <span class="o">=</span> <span class="s">"#isbn"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">Book</span> <span class="nf">betterUpdateTitle</span><span class="o">(</span><span class="nd">@PathVariable</span><span class="o">(</span><span class="s">"isbn"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">isbn</span><span class="o">,</span>
                                <span class="nd">@PathVariable</span><span class="o">(</span><span class="s">"title"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">title</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">bookRepository</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">bookRepository</span><span class="o">.</span><span class="na">findByIsbn</span><span class="o">(</span><span class="n">isbn</span><span class="o">).</span><span class="na">withTitle</span><span class="o">(</span><span class="n">title</span><span class="o">));</span>
  <span class="o">}</span>

  <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/{isbn}/bestUpdateTitle/{title}"</span><span class="o">)</span>
  <span class="nd">@CachePut</span><span class="o">(</span><span class="n">cacheNames</span> <span class="o">=</span> <span class="s">"books"</span><span class="o">,</span> <span class="n">key</span> <span class="o">=</span> <span class="s">"#isbn"</span><span class="o">)</span>
  <span class="kd">public</span> <span class="nc">Book</span> <span class="nf">bestUpdateTitle</span><span class="o">(</span><span class="nd">@PathVariable</span><span class="o">(</span><span class="s">"isbn"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">isbn</span><span class="o">,</span>
                              <span class="nd">@PathVariable</span><span class="o">(</span><span class="s">"title"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">title</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">bookRepository</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">bookRepository</span><span class="o">.</span><span class="na">findByIsbn</span><span class="o">(</span><span class="n">isbn</span><span class="o">).</span><span class="na">withTitle</span><span class="o">(</span><span class="n">title</span><span class="o">));</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Some notes on the methods and their use of Spring’s declarative caching.</p>

<ul>
  <li><code class="language-java highlight nf highlighter-rouge"><span class="n">clearCache</span></code>: This method is for testing purposes only! It uses <code class="language-java highlight highlighter-rouge"><span class="nd">@CacheEvict</span></code> to clear <strong><em>ALL</em></strong> items from the cache. It allows us to start from a known state (empty cache) when we are testing.
  In a production application, I struggle to imagine a scenario in which you’d want to clear the entire cache.
  This is one of the reasons I didn’t like examples I found on the web: this seemed to be the most popular example use of this annotation.</li>
  <li><code class="language-java highlight highlighter-rouge"><span class="n">books</span></code>: This method returns a list of all Books. It does not cache results. It’s a convenience method that lets us see all Books.
  There are interesting questions here that I chose to completely ignore (but they are worth further research):
    <ul>
      <li>If we were to cache the result, would it cache the list as a unit, or the items in the list individually?</li>
      <li>If it does cache the list as a unit (which I think is the case), how could we make it cache the results individually?</li>
      <li>If the list were cached as a unit, how would we manage the cache when an individual Book was updated? Would we clear <strong><em>ALL</em></strong> cached lists of books (in case it appears in one of them)?</li>
    </ul>
  </li>
  <li><code class="language-java highlight highlighter-rouge"><span class="n">bookByIsbn</span></code>: Given an isbn, this method returns a single Book and caches the result (<code class="language-java highlight highlighter-rouge"><span class="nd">@Cacheable</span></code>).</li>
  <li><code class="language-java highlight highlighter-rouge"><span class="n">badUpdateTitle</span></code>: Given an isbn and a title, this method will update the title of the Book determined by the isbn. 
 This is “bad” because it allows for records in the database to be updated without correpsonding records in the cache being updated.</li>
  <li><code class="language-java highlight highlighter-rouge"><span class="n">betterUpdateTitle</span></code>: Given an isbn and a title, this method will update the the title of the Book determined by the isbn <em>and</em> <em>evict</em> any instance of the book from the cache (<code class="language-java highlight highlighter-rouge"><span class="nd">@CacheEvict</span></code>).
 This is “better” because when a database record is updated, any corresponding record in the cache is removed.</li>
  <li><code class="language-java highlight highlighter-rouge"><span class="n">bestUpdateTitle</span></code>: Given an isbn and a title, this method will update the title of the book determined by the isbn <em>and</em> <em>update</em> any instance of the book from the cache (<code class="language-java highlight highlighter-rouge"><span class="nd">@CachePut</span></code>).
 This is “best” because when a database record is updated, any corresponding record in the cache is also updated.</li>
</ul>

<p>A stripped down version of the Book entity follows (see the source for the complete class).</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Book</span> <span class="o">{</span>
  <span class="kd">private</span> <span class="nc">String</span> <span class="n">isbn</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">String</span> <span class="n">title</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">String</span> <span class="n">author</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">Boolean</span> <span class="n">cached</span><span class="o">;</span>
  <span class="kd">private</span> <span class="nc">String</span> <span class="n">host</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>This entity captures the <code class="language-java highlight highlighter-rouge"><span class="n">isbn</span></code>, <code class="language-java highlight highlighter-rouge"><span class="n">title</span></code>, and <code class="language-java highlight highlighter-rouge"><span class="n">author</span></code> of the book – no surprises there.</p>

<p>However, it also has two additional fields: <code class="language-java highlight highlighter-rouge"><span class="n">cached</span></code> and <code class="language-java highlight highlighter-rouge"><span class="n">host</span></code>. These two fields aren’t actually stored
in the database. They are managed by some clever <a href="https://eclipse.dev/aspectj/doc/latest/index.html">AspectJ</a> code. For a given instance of a book, they allow us to see:</p>
<ul>
  <li>Whether it came from a cache.</li>
  <li>Which host provided it in response to our request (which is interesting when we deploy multiple instances of our application).</li>
</ul>

<p>The same sample application can be deployed multiple ways, each having an impact on caching behavior.</p>

<h3 id="single-jvm">Single JVM</h3>

<p>The simplest of these architectures is a single instance of the application, using both an in-memory cache and an in-memory 
database (all in the same JVM)<sup id="fnref:mermaid" role="doc-noteref"><a href="#fn:mermaid" class="footnote" rel="footnote">3</a></sup>:</p>

<p><img class="mermaid" src="https://mermaid.ink/svg/eyJjb2RlIjoiYmxvY2stYmV0YVxuY29sdW1ucyA0XG5jbGllbnRbXCJjbGllbnRcIl1cbnNwYWNlXG5ibG9jazpncm91cDE6MlxuY29sdW1ucyA2XG5zcGFjZSBhcHAoW1wiYXBwXCJdKSBzcGFjZSBjYWNoZVsoXCJjYWNoZVxcbihpbiBtZW0pXCIpXSBzcGFjZSBkYlsoXCJkYlxcbihIMilcIildXG5hcHAgLS0-IGNhY2hlXG5jYWNoZSAtLT4gZGJcbmVuZFxuY2xpZW50IC0tPiBhcHAiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ" /></p>

<p>In this configuration, all requests are answered by the same application instance. That instance has a single backend
database. Its responses are saved in a single cache.</p>

<p>The following sequence diagram shows what happens when we attempt to retrieve a book. The Cache Interceptor intercepts the
request and first checks to see if the result is already in the cache. If it is, the interceptor returns the result.
If it’s not, the interceptor calls the Endpoint Method and adds the result to the cache before returning it to the Client.</p>

<p><img class="mermaid" src="https://mermaid.ink/svg/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5wYXJ0aWNpcGFudCBCIGFzIENsaWVudFxuYm94IHJnYmEoOTgsIDE3NSwgMTkyLCAwLjUpIFNpbmdsZSBKVk1cbnBhcnRpY2lwYW50IENJIGFzIENhY2hlIEludGVyY2VwdG9yXG5wYXJ0aWNpcGFudCBFTSBhcyBCb29rUmVzdENvbnRyb2xsZXJcbnBhcnRpY2lwYW50IEMgYXMgQ2FjaGVcbnBhcnRpY2lwYW50IERCIGFzIERhdGFiYXNlXG5lbmRcbkItPj5DSTogR0VUICgve2lzYm59KVxuQ0ktPj5DOiBHRVRcbmFsdCBjYWNoZSBtaXNzXG5DSS0-PkVNOiBib29rQnlJc2JuXG5FTS0-PkRCOlNFTEVDVFxuREItLT4-RU06IHJldHVyblxuRU0tLT4-Q0k6IHJldHVyblxuQ0ktPj5DOiBQVVRcbkNJLS0-PkI6IHJldHVyblxuZWxzZSBjYWNoZSBoaXRcbkMtLT4-Q0k6IHJldHVyblxuQ0ktLT4-QjogcmV0dXJuXG5lbmQiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ" /></p>

<p>To deploy the application in this configuration, run the following command (from the project’s root directory):</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make single-instance
</code></pre></div></div>

<p>Now let’s kick the tires! Open another shell (because the one in which you ran the previous command should now be occupied).</p>

<p>Note that if we clear the cache and then make 98 requests for the same book, 97 requests are served by the cache<sup id="fnref:make-automation" role="doc-noteref"><a href="#fn:make-automation" class="footnote" rel="footnote">4</a></sup>:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make clear-cache-for-all-replicas get-book
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..5<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/clear<span class="p">;</span>
<span class="k">done
for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     97 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
</code></pre></div></div>

<p>Then, if we (without clearing caches) “bad” update the title and then make 98 requests for the book… all 98 requests
are served by the cache, and all 98 have the <strong><em>wrong</em></strong> (old) title:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make bad-update-title get-book 
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/badUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BAD | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BAD"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
     98 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
</code></pre></div></div>

<p>The lesson to be learned here is that you are responsible for keeping the cache up to date with the “source of truth”. In our
example, the “source of truth” is our database.</p>

<p>Next, if we (again, without clearing caches) “better” update the title and then make 98 requests for the book… 97 requests
are served by the cache, and one is not. However all 98 have the <strong><em>correct</em></strong> (new) title:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make better-update-title get-book 
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/betterUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BETTER | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     97 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
</code></pre></div></div>

<p><strong><em>This</em></strong> is a much better example of how to use <code class="language-java highlight highlighter-rouge"><span class="nd">@CacheEvict</span></code> (in my opinion) than I was able to find online. Any time we update a record in the database, we evict
any instances of it in the cache. This is much better than evicting the entire cache.</p>

<p>Finally, if we (again, without clearing caches) “best” update the title and then make 98 requests for the book… all 98 requests
are served by the cache, and all 98 have the <strong><em>correct</em></strong> (new) title:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make best-update-title get-book 
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/bestUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BEST | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
     98 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"72fca0a378f9"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span><span class="o">}</span>
</code></pre></div></div>

<p>This example is arguably the best method for keeping a cache up to date. Any time a record is updated in the database, we add it to the cache (if it wasn’t there already) or
update it in the cache (if it was already there). This allows us to serve as many lookup requests from the cache as possible.</p>

<p>If you want to keep playing, you can use the following command to restore the state to what it was before we started. However,
if you plan to just move on to the examples in the next session, there is no need – because we are going to bring down the
entire application and deploy it in a new configuration.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make restore-title-for-all-replicas clear-cache-for-all-replicas
</code></pre></div></div>

<h3 id="replicas-with-individual-caches-shared-database">Replicas with Individual Caches, Shared Database</h3>

<p>A misguided next step in the evolution of this application’s architecture (especially if you think the way I do) would be
to create multiple replicas of the app that all store their data in a single database – <strong><em>without</em></strong> also centralizing
the cache.</p>

<p>For Spring novices, this is where a huge “gotcha” lies: you are always free to put a <code class="language-java highlight highlighter-rouge"><span class="nd">@Cacheable</span></code> annotation on any component
method. If you take no other action than that, you are using Spring’s default cache implementation… which is an in memory cache.
This was fine for our single replica example, however… it will cause trouble here.</p>

<p><img class="mermaid" src="https://mermaid.ink/svg/eyJjb2RlIjoiYmxvY2stYmV0YVxuJSUgY29sdW1ucyBhdXRvIChkZWZhdWx0KVxuJSUtXG5ibG9jazpjbGllbnRibG9jazoxXG5jb2x1bW5zIDFcbnNwYWNlXG5zcGFjZVxuY2xpZW50W1wiY2xpZW50XCJdXG5zcGFjZVxuc3BhY2VcbmVuZFxuJSUtXG5zdHlsZSBjbGllbnRibG9jayBmaWxsOiNmY2UxYzUsIHN0cm9rZTogI2ZjZTFjNVxuJSUtXG5ibG9jazpsYmJsb2NrOjFcbmNvbHVtbnMgMVxuc3BhY2VcbnNwYWNlXG5sYltcImxvYWRcXG5iYWxhbmNlclwiXToxXG5zcGFjZVxuc3BhY2VcbmVuZFxuJSUtXG5zdHlsZSBsYmJsb2NrICBmaWxsOiNmY2UxYzUsIHN0cm9rZTogI2ZjZTFjNVxuJSUtXG5ibG9jazpyZXBsaWNhczoxXG5jb2x1bW5zIDJcbiUlLVxuYmxvY2s6cmVwbGljYTE6MlxuYXBwMShbXCJhcHBcIl0pIGNhY2hlMVsoXCJjYWNoZVxcbihpbiBtZW0pXCIpXVxuYXBwMSAtLT4gY2FjaGUxXG5lbmRcbiUlLVxuYmxvY2s6cmVwbGljYTI6MlxuYXBwMihbXCJhcHBcIl0pIGNhY2hlMlsoXCJjYWNoZVxcbihpbiBtZW0pXCIpXVxuYXBwMiAtLT4gY2FjaGUyXG5lbmRcbiUlLVxuYmxvY2s6cmVwbGljYTM6MlxuYXBwMyhbXCJhcHBcIl0pIGNhY2hlM1soXCJjYWNoZVxcbihpbiBtZW0pXCIpXVxuYXBwMyAtLT4gY2FjaGUzXG5lbmRcbiUlLVxuYmxvY2s6cmVwbGljYTQ6MlxuYXBwNChbXCJhcHBcIl0pIGNhY2hlNFsoXCJjYWNoZVxcbihpbiBtZW0pXCIpXVxuYXBwNCAtLT4gY2FjaGU0XG5lbmRcbiUlLVxuYmxvY2s6cmVwbGljYTU6MlxuYXBwNShbXCJhcHBcIl0pIGNhY2hlNVsoXCJjYWNoZVxcbihpbiBtZW0pXCIpXVxuYXBwNSAtLT4gY2FjaGU1XG5lbmRcbiUlLVxuZW5kXG4lJS1cbmNsaWVudCAtLT4gbGJcbmxiIC0tPiBhcHAxXG5sYiAtLT4gYXBwMlxubGIgLS0-IGFwcDNcbmxiIC0tPiBhcHA0XG5sYiAtLT4gYXBwNVxuJSUtXG5kYlsoXCJkYlxcbihQb3N0Z3JlcylcIildOjFcbiUlLVxuY2FjaGUxIC0tPiBkYlxuY2FjaGUyIC0tPiBkYlxuY2FjaGUzIC0tPiBkYlxuY2FjaGU0IC0tPiBkYlxuY2FjaGU1IC0tPiBkYiIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In19" /></p>

<p>As you can see from the following sequence diagram, caches still belong to individual replicas, and are updated independently of one another.
If a replica answers a given retrieval request, only its cache is populated with the value. If a given replica services an update request,
only its cache is updated with the new value. Any other replica that has cached the value previously will now return stale data for lookup requests!</p>

<p><img class="mermaid" src="https://mermaid.ink/svg/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5wYXJ0aWNpcGFudCBCIGFzIENsaWVudFxuYm94IHJnYmEoOTgsIDE3NSwgMTkyLCAwLjUpIFJlcGxpY2EgMVxucGFydGljaXBhbnQgQ0kgYXMgQ2FjaGUgSW50ZXJjZXB0b3JcbnBhcnRpY2lwYW50IEVNIGFzIEJvb2tSZXN0Q29udHJvbGxlclxucGFydGljaXBhbnQgQyBhcyBDYWNoZVxuZW5kXG5ib3ggcmdiYSg5OCwgMTc1LCAxOTIsIDAuNSkgUmVwbGljYSAyXG5wYXJ0aWNpcGFudCBDSTIgYXMgQ2FjaGUgSW50ZXJjZXB0b3JcbnBhcnRpY2lwYW50IEVNMiBhcyBCb29rUmVzdENvbnRyb2xsZXJcbnBhcnRpY2lwYW50IEMyIGFzIENhY2hlXG5lbmRcbmJveCByZ2JhKDk4LCAxNzUsIDE5MiwgMC41KSBEYXRhYmFzZSBTZXJ2ZXJcbnBhcnRpY2lwYW50IERCIGFzIERhdGFiYXNlXG5lbmRcbiUlLVxucmVjdCByZ2JhKDk4LCAxNzUsIDE5MiwgMC41KVxubm90ZSByaWdodCBvZiBCOiBSZXBsaWNhIDIgc2VydmljZXMgbG9va3VwLiBDYWNoZSAyIHBvcHVsYXRlZC5cbkItPj5DSTI6IEdFVCAoL3tpc2JufSlcbkNJMi0-PkVNMjogYm9va0J5SXNiblxuRU0yLT4-REI6U0VMRUNUXG5EQi0tPj5FTTI6IHJldHVyblxuRU0yLS0-PkNJMjogcmV0dXJuXG5DSTItPj5DMjogUFVUXG5DSTItLT4-QjogcmV0dXJuXG5lbmRcbiUlLVxucmVjdCByZ2JhKDk4LCAxNzUsIDE5MiwgMC41KVxubm90ZSByaWdodCBvZiBCOiBSZXBsaWNhIDEgc2VydmljZXMgdXBkYXRlLiBDYWNoZSAxIHBvcHVsYXRlZC5cbkItPj5DSTogR0VUIChcIi97aXNibn0vYmVzdFVwZGF0ZVRpdGxlL3t0aXRsZX1cIilcbkNJLT4-RU06IGJlc3RVcGRhdGVUaXRsZVxuRU0tPj5EQjpVUERBVEVcbkRCLS0-PkVNOiByZXR1cm5cbkVNLS0-PkNJOiByZXR1cm5cbkNJLT4-QzogUFVUXG5DSS0tPj5COiByZXR1cm5cbmVuZFxuJSUtXG5yZWN0IHJnYmEoOTgsIDE3NSwgMTkyLCAwLjUpXG5ub3RlIHJpZ2h0IG9mIEI6IFJlcGxpY2EgMiBzZXJ2aWNlcyBsb29rdXAuIENhY2hlIDIgaGl0IChzdGFsZSBkYXRhISkuXG5CLT4-Q0kyOiBHRVQgKC97aXNibn0pXG5DSTItPj5DMjogR0VUXG5DMi0tPj5DSTI6IHJldHVyblxuQ0kyLS0-PkI6IHJldHVyblxuZW5kIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0" /></p>

<p>Okay, let’s give this new deployment scenario a spin. First things first… in a terminal where you have a prompt (ie: not the one currently
streaming docker logs from the previous scenario), run this:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make clean
</code></pre></div></div>

<p>Give it a little time, then check your shell that had the docker logs. Eventually, all containers should stop, and you should be presented
with a prompt again. At that prompt, type:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make replicas-individual-cache-shared-db
</code></pre></div></div>

<p>Now, if we clear the cache and then make 98 requests for the same book, we’ll see that each replica responds with a single un-cached
record, and then responds to successive requests from its own cache.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make clear-cache-for-all-replicas get-book
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..5<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/clear<span class="p">;</span>
<span class="k">done
for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"1de0e07a1854"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     18 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"1de0e07a1854"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"64434b3e44f2"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     18 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"64434b3e44f2"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"a7c9cadc9353"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"a7c9cadc9353"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e4a74ccf237b"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e4a74ccf237b"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e5910004e389"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e5910004e389"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
</code></pre></div></div>

<p>Keep in mind that all replicas now have the book we are querying for cached. If we “bad” update the title, successive
lookups will all be served from replicas’ caches. However, none of those caches will contain the proper, updated book.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make bad-update-title get-book
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/badUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BAD | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BAD"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"1de0e07a1854"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"1de0e07a1854"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"64434b3e44f2"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"a7c9cadc9353"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e4a74ccf237b"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e5910004e389"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
</code></pre></div></div>

<p>But, when we “better” update the title, only <strong><em>ONE</em></strong> stale cached value is removed (the one in the cache of the replica that serviced the update request). 
When we fetch books after that update, only the cache from which the stale value was removed bothers to repopulate its cache.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make better-update-title get-book
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/betterUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BETTER | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"a7c9cadc9353"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"1de0e07a1854"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"64434b3e44f2"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"a7c9cadc9353"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     18 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"a7c9cadc9353"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e4a74ccf237b"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e5910004e389"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
</code></pre></div></div>

<p>Finally, the only thing that our “best” update improves is that it prevents a cache-miss from a single replica. It has no effect
on data integrity. As you can see below, we now have <strong><em>TWO</em></strong> distinct stale values distributed across our replicas’ caches.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make best-update-title get-book
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/bestUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BEST | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"e4a74ccf237b"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"1de0e07a1854"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"64434b3e44f2"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"a7c9cadc9353"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e4a74ccf237b"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"e5910004e389"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
</code></pre></div></div>

<p>Okay, that was fun. Remember, if you want to keep messing around with this deployment scenario, you can run the following command 
to “reset”. Otherwise, let’s move on to the next deployment scenario.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make restore-title-for-all-replicas clear-cache-for-all-replicas
</code></pre></div></div>

<h3 id="replicas-with-shared-cache-shared-database">Replicas with Shared Cache, Shared Database</h3>

<p>Okay, if it wasn’t immediately obvious that the previous scenario was a bad idea, it should definitely be obvious in hindsight.
This scenario fixes the issues of the previous scenario by also using a centralized cache.</p>

<p><img class="mermaid" src="https://mermaid.ink/svg/eyJjb2RlIjoiYmxvY2stYmV0YVxuJSUgY29sdW1ucyBhdXRvIChkZWZhdWx0KVxuJSUtXG5ibG9jazpjbGllbnRibG9jazoxXG5jb2x1bW5zIDFcbnNwYWNlXG5zcGFjZVxuY2xpZW50W1wiY2xpZW50XCJdXG5zcGFjZVxuc3BhY2VcbmVuZFxuJSUtXG5zdHlsZSBjbGllbnRibG9jayBmaWxsOiNmY2UxYzUsIHN0cm9rZTogI2ZjZTFjNVxuJSUtXG5ibG9jazpsYmJsb2NrOjFcbmNvbHVtbnMgMVxuc3BhY2VcbnNwYWNlXG5sYltcImxvYWRcXG5iYWxhbmNlclwiXToxXG5zcGFjZVxuc3BhY2VcbmVuZFxuJSUtXG5zdHlsZSBsYmJsb2NrICBmaWxsOiNmY2UxYzUsIHN0cm9rZTogI2ZjZTFjNVxuJSUtXG5ibG9jazpyZXBsaWNhczoxXG5jb2x1bW5zIDFcbiUlLVxuYmxvY2s6cmVwbGljYTE6MVxuYXBwMShbXCJhcHBcIl0pXG5lbmRcbiUlLVxuYmxvY2s6cmVwbGljYTI6MVxuYXBwMihbXCJhcHBcIl0pXG5lbmRcbiUlLVxuYmxvY2s6cmVwbGljYTM6MVxuYXBwMyhbXCJhcHBcIl0pXG5lbmRcbiUlLVxuYmxvY2s6cmVwbGljYTQ6MVxuYXBwNChbXCJhcHBcIl0pXG5lbmRcbiUlLVxuYmxvY2s6cmVwbGljYTU6MVxuYXBwNShbXCJhcHBcIl0pXG5lbmRcbiUlLVxuZW5kXG4lJS1cbmNsaWVudCAtLT4gbGJcbmxiIC0tPiBhcHAxXG5sYiAtLT4gYXBwMlxubGIgLS0-IGFwcDNcbmxiIC0tPiBhcHA0XG5sYiAtLT4gYXBwNVxuJSUtXG5hcHAxIC0tPiBjYWNoZVxuYXBwMiAtLT4gY2FjaGVcbmFwcDMgLS0-IGNhY2hlXG5hcHA0IC0tPiBjYWNoZVxuYXBwNSAtLT4gY2FjaGVcbiUlLVxuY2FjaGVbKFwiY2FjaGVcXG4oUmVkaXMpXCIpXToxXG4lJS1cbmRiWyhcImRiXFxuKFBvc3RncmVzKVwiKV06MVxuJSUtXG5jYWNoZSAtLT4gZGIiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ" /></p>

<p>As you can see from the following sequence diagram, in this scenario: all replicas read from and write to the same cache.
Any update to the cache is seen by all replicas<sup id="fnref:threading" role="doc-noteref"><a href="#fn:threading" class="footnote" rel="footnote">5</a></sup>.</p>

<p><img class="mermaid" src="https://mermaid.ink/svg/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5wYXJ0aWNpcGFudCBCIGFzIENsaWVudFxuYm94IHJnYmEoOTgsIDE3NSwgMTkyLCAwLjUpIFJlcGxpY2EgMVxucGFydGljaXBhbnQgQ0kgYXMgQ2FjaGUgSW50ZXJjZXB0b3JcbnBhcnRpY2lwYW50IEVNIGFzIEJvb2tSZXN0Q29udHJvbGxlclxuZW5kXG5ib3ggcmdiYSg5OCwgMTc1LCAxOTIsIDAuNSkgUmVwbGljYSAyXG5wYXJ0aWNpcGFudCBDSTIgYXMgQ2FjaGUgSW50ZXJjZXB0b3JcbnBhcnRpY2lwYW50IEVNMiBhcyBCb29rUmVzdENvbnRyb2xsZXJcbmVuZFxuYm94IHJnYmEoOTgsIDE3NSwgMTkyLCAwLjUpIENhY2hlIFNlcnZlclxucGFydGljaXBhbnQgQyBhcyBDYWNoZVxuZW5kXG5ib3ggcmdiYSg5OCwgMTc1LCAxOTIsIDAuNSkgRGF0YWJhc2UgU2VydmVyXG5wYXJ0aWNpcGFudCBEQiBhcyBEYXRhYmFzZVxuZW5kXG4lJS1cbnJlY3QgcmdiYSg5OCwgMTc1LCAxOTIsIDAuNSlcbm5vdGUgcmlnaHQgb2YgQjogUmVwbGljYSAyIHNlcnZpY2VzIGxvb2t1cC4gQ2FjaGUgcG9wdWxhdGVkLlxuQi0-PkNJOiBHRVQgKC97aXNibn0pXG5DSS0-PkVNOiBib29rQnlJc2JuXG5FTS0-PkRCOlNFTEVDVFxuREItLT4-RU06IHJldHVyblxuRU0tLT4-Q0k6IHJldHVyblxuQ0ktPj5DOiBQVVRcbkNJLS0-PkI6IHJldHVyblxuZW5kXG4lJS1cbnJlY3QgcmdiYSg5OCwgMTc1LCAxOTIsIDAuNSlcbm5vdGUgcmlnaHQgb2YgQjogUmVwbGljYSAxIHNlcnZpY2VzIHVwZGF0ZS4gQ2FjaGUgdXBkYXRlZC5cbkItPj5DSTogR0VUIChcIi97aXNibn0vYmVzdFVwZGF0ZVRpdGxlL3t0aXRsZX1cIilcbkNJLT4-RU06IGJlc3RVcGRhdGVUaXRsZVxuRU0tPj5EQjpVUERBVEVcbkRCLS0-PkVNOiByZXR1cm5cbkVNLS0-PkNJOiByZXR1cm5cbkNJLT4-QzogUFVUXG5DSS0tPj5COiByZXR1cm5cbmVuZFxuJSUtXG5yZWN0IHJnYmEoOTgsIDE3NSwgMTkyLCAwLjUpXG5ub3RlIHJpZ2h0IG9mIEI6IFJlcGxpY2EgMiBzZXJ2aWNlcyBsb29rdXAuIENhY2hlIGhpdC5cbkItPj5DSTogR0VUICgve2lzYm59KVxuQ0ktPj5DOiBHRVRcbkMtLT4-Q0k6IHJldHVyblxuQ0ktLT4-QjogcmV0dXJuXG5lbmQiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ" /></p>

<p>Okay, time for our final deployment scenario. You know the drill…</p>

<p>In a shell with a prompt:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make clean
</code></pre></div></div>

<p>In the shell that had logs and now (after you wait a little bit) has a prompt again:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make replicas-shared-cache-shared-db
</code></pre></div></div>

<p>This time, when we fetch books, ONLY ONE request isn’t serviced from the cache… despite requests being distributed across five replicas.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make clear-cache-for-all-replicas get-book
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..5<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/clear<span class="p">;</span>
<span class="k">done
for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"2bb40d744e9c"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"380a19db4fcd"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"380a19db4fcd"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"4428dd122929"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"471359f51bd4"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"b7f5bbac15b7"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
</code></pre></div></div>

<p>“Bad” update is, of course, still broken: all requests are serviced from the cache, however no response contains the actual
book as it exists in the database.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make bad-update-title get-book
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/badUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BAD | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BAD"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"2bb40d744e9c"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"2bb40d744e9c"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"380a19db4fcd"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"4428dd122929"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"471359f51bd4"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"b7f5bbac15b7"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"On Lisp"</span><span class="o">}</span>
</code></pre></div></div>

<p>“Better” update now evicts the stale book from the <strong><em>single</em></strong> cache. The first request after this update requires a 
database lookup, but after that, <strong><em>all</em></strong> replicas are able to service successive requests using the cache.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make better-update-title get-book
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/betterUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BETTER | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"b7f5bbac15b7"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
      1 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"2bb40d744e9c"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"2bb40d744e9c"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"380a19db4fcd"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"4428dd122929"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"471359f51bd4"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"b7f5bbac15b7"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BETTER"</span><span class="o">}</span>
</code></pre></div></div>

<p>And finally, “best” update updates the book without requiring any successive lookups to query the database!</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make best-update-title get-book
curl <span class="nt">-s</span> http://localhost:8080/books/0130305529/bestUpdateTitle/<span class="s2">"HELLO%20WORLD"</span>%20BEST | jq <span class="nt">-c</span> <span class="s1">'.'</span>
<span class="o">{</span><span class="s2">"isbn"</span>:<span class="s2">"0130305529"</span>,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span>,<span class="s2">"author"</span>:<span class="s2">"Paul Graham"</span>,<span class="s2">"cached"</span>:false,<span class="s2">"host"</span>:<span class="s2">"4428dd122929"</span><span class="o">}</span>
<span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..98<span class="o">}</span><span class="p">;</span>
<span class="k">do
</span>curl <span class="nt">-s</span> http://localhost:8080/books/0130305529 | jq <span class="nt">-c</span> <span class="s1">'. | {host, cached,title}'</span><span class="p">;</span>
<span class="k">done</span> <span class="se">\</span>
| <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"2bb40d744e9c"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"380a19db4fcd"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span><span class="o">}</span>
     19 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"4428dd122929"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"471359f51bd4"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span><span class="o">}</span>
     20 <span class="o">{</span><span class="s2">"host"</span>:<span class="s2">"b7f5bbac15b7"</span>,<span class="s2">"cached"</span>:true,<span class="s2">"title"</span>:<span class="s2">"HELLO WORLD BEST"</span><span class="o">}</span>
</code></pre></div></div>

<p>Again, if you want to keep playing around, you can reset the application state with this:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ make restore-title-for-all-replicas clear-cache-for-all-replicas
</code></pre></div></div>

<h2 id="summary">Summary</h2>

<p>The big takeaway here is this: Spring make easy things easy. To that end, it has a default cache implementation. If you’re
not careful, you may be inclined to mark a component method as <code class="language-java highlight highlighter-rouge"><span class="nd">@Cacheable</span></code> – and then get on with your life. This
could have severe ramifications depending on how your app is deployed now or in the future.</p>

<p>Like I hinted at earlier, I had a lot of fun writing this sample app. The actual “book database web service” was the boring part.
Using AspectJ to decorate returned entities was really fun, and I think it made the examples much easier to read (you can
tell from the payload which host it came from and whether or not it was cached). It was also a lot of fun using docker compose
paired with Spring profiles to create wildly different deployment scenarios without having to change a single line of Java code.
Seriously, have a look at the source – there’s not a lot of it. The only bit that I would say is perhaps “less than readable” is the
AspectJ part – there’s not a lot to it, but it got complicated.</p>

<!---@formatter:off--->

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:baeldung" role="doc-endnote">
      <p>Seriously, I’m not picking on Baeldung. It’s one of my favorite web sites. Even though I didn’t love its examples in this instance, the article I referenced served as
one of the starting points for this very blog post. <a href="#fnref:baeldung" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:fibonacci" role="doc-endnote">
      <p>The examples in this blog post <em>only</em> consider caching return values of methods that are <em>not</em> mathematical functions. However, the sample application <em>does</em> have
examples of caching “mathematical” functions. See the endpoints for calculating fibonacci numbers… <a href="#fnref:fibonacci" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:mermaid" role="doc-endnote">
      <p>All diagrams in this post were created with <a href="https://mermaid.js.org/intro/">mermaid</a>. <a href="#fnref:mermaid" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:make-automation" role="doc-endnote">
      <p>The Makefile contains targets that allow me to run commands to exercise the application more succinctly.
<code class="language-shell highlight highlighter-rouge">make</code> also has the wonderful feature of echoing commands that it runs. This allows me to type a short command and
copy paste the output directly into this post – showing you both the commands that were actually run and the output that they
generated. <a href="#fnref:make-automation" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:threading" role="doc-endnote">
      <p>This raises very interesting questions like: “How does Spring’s Caching Interceptor handle cache updates from multiple threads?”. That’s outside of the scope of this
post, however – so I’m just going to “trust Spring” on this one.
<!---@formatter:on---> <a href="#fnref:threading" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>`author`{:.language-java .highlight}</name></author><summary type="html"><![CDATA[Spring Declarative Caching]]></summary></entry><entry><title type="html">Lisp Macros</title><link href="/2023/12/03/lisp-macros.html" rel="alternate" type="text/html" title="Lisp Macros" /><published>2023-12-03T00:00:00+00:00</published><updated>2023-12-03T00:00:00+00:00</updated><id>/2023/12/03/lisp-macros</id><content type="html" xml:base="/2023/12/03/lisp-macros.html"><![CDATA[<h1 id="lisp-macros-learning-by-example">Lisp Macros: Learning by Example</h1>

<h2 id="the-inspiration-for-this-post">The inspiration for this post</h2>

<p>Once a week, I meet with a group of like-minded nerds to discuss Lisp topics. This group started as a book club, and our
original goal was to read Paul Graham’s book “<a href="http://www.paulgraham.com/onlisp.html">On Lisp</a>”. Although we constantly
find
ourselves drifting from that goal, we keep working our way back toward it. We just can’t help ourselves from being
distracted by various Lisp related topics.</p>

<p class="callout">Lots of great books have been written about Lisp<sup id="fnref:books" role="doc-noteref"><a href="#fn:books" class="footnote" rel="footnote">1</a></sup>. To me at least, it seems that <strong>most</strong> books
written about Lisp are fantastic. Even if you care nothing about the language (you should), it’s worth your time to pick
up one of the more well known books about Lisp – so that you have an example of quality technical writing to study.</p>

<p><em>On Lisp</em> covers a lot of topics, but if one were to ask the Lisp community:</p>

<p>“Which <strong>one</strong> Lisp book should I read if I want to learn how to write Lisp Macros?”</p>

<p>I believe the community would answer:</p>

<p>“On Lisp.”</p>

<p>So it should surprise no one that when a group of nerds gets together to read <strong>“the”</strong> book about Lisp macros, at least
one of those nerds will feel the need to write a blog post about macros. This is one such post.</p>

<h2 id="searching-for-an-example">Searching for an example</h2>

<p>I’ve read a lot of articles and blog posts that try to explain the power of Lisp macros. They talk about transformation
of syntax, evaluation of arguments, <a href="https://en.wikipedia.org/wiki/Homoiconicity">homoiconicity</a>, etc. These topics are
all important, of course – but when I want to learn something, it really helps me to see an example.</p>

<p>Coming up with a good example isn’t easy. In my opinion, a good example should:</p>

<ul>
  <li>Exhibit the topic being studied in a non-trivial way.</li>
  <li>Have an implementation that’s small enough to fit on half a page.</li>
</ul>

<p>I’ll admit that I don’t have a rigorous definition for “non-trivial”. The best I can do is give some examples of what
I don’t like about examples I consider to be “trivial”:</p>

<ul>
  <li>On their own, they don’t convince me that the topic under study has any useful applications.</li>
  <li>They show me something that already seemed obvious.</li>
</ul>

<p>What follows is my attempt at a “non-trivial” example whose implementation fits on half a page.</p>

<h2 id="a-non-trivial-example">A non-trivial example</h2>

<p>One of the things that makes Lisp macros so powerful is that they grant application developers the ability to extend the
language
(Lisp). Contrast this with, say, C. Only compiler developers (not application developers) have the ability to extend C.</p>

<p>This suggests a possible avenue to explore when searching for a non-trivial example: find a feature in another language
and add it to Lisp!</p>

<p>To that end, I went shopping for language features that Lisp lacks. I settled on the syntax in Scala that allows you to
use the identifier “<code class="language-scala highlight highlighter-rouge"><span class="k">_</span></code>” when defining new functions
via <a href="https://en.wikipedia.org/wiki/Partial_application">partial application</a>. This syntax allows you to specify which
arguments of a given function you wish to remain as formal parameters of the new function you are defining. We’ll get
to an example in Scala in a minute, but first…</p>

<h3 id="slope-intercept-form-of-a-line">Slope-intercept form of a line</h3>

<p>Consider
the <a href="https://en.wikipedia.org/wiki/Linear_equation#Slope%E2%80%93intercept_form">slope-intercept form of a line</a>:
\(y = mx+b\)</p>

<p>We think of lines as a function of one independent variable, ie: \(y = f(x)\) – however the function above appears to
have three independent variables: \(m, x, b\)!</p>

<p>So, what gives? Well, mathematicians just call \(m\) and \(b\) “parameters” <sup id="fnref:param" role="doc-noteref"><a href="#fn:param" class="footnote" rel="footnote">2</a></sup> <sup id="fnref:paramdef" role="doc-noteref"><a href="#fn:paramdef" class="footnote" rel="footnote">3</a></sup> – which, once chosen, determine the single
function (one of <em>many</em>) which defines whatever line it is we happen to care about.</p>

<p>We’re programmers, not mathematicians, however – and to a programmer, that answer may seem unsatisfying…</p>

<h3 id="definining-functions-using-partial-application-in-scala">Definining functions using partial application in Scala</h3>

<p>This mathematicians’ process of specifying two “parameters” for a function of three variables – to obtain a new function of one
variable – is a <strong>perfect</strong> example of partial function application. In Scala, that looks like this:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">y</span><span class="o">(</span><span class="n">m</span><span class="k">:</span> <span class="kt">Float</span><span class="o">,</span> <span class="n">x</span><span class="k">:</span> <span class="kt">Float</span><span class="o">,</span> <span class="n">b</span><span class="k">:</span> <span class="kt">Float</span><span class="o">)</span> <span class="k">=</span> <span class="n">m</span> <span class="o">*</span> <span class="n">x</span> <span class="o">+</span> <span class="n">b</span>

<span class="c1">// Here, we are creating a function, "slopeInterceptLine", that in turn </span>
<span class="c1">// allows us to create new functions of a single variable by:</span>
<span class="c1">// 1) Fixing two of the parameters ("slope" and "intercept") of the </span>
<span class="c1">//    function "y".</span>
<span class="c1">// 2) Making the remaining parameter, "x", a parameter of the new </span>
<span class="c1">//    function being created.</span>
<span class="c1">// Note how we use "_" to specify the parameter(s) we wish to be </span>
<span class="c1">// parameter(s) in the new function being created.</span>
<span class="k">def</span> <span class="nf">slopeInterceptLine</span><span class="o">(</span><span class="n">slope</span><span class="k">:</span> <span class="kt">Float</span><span class="o">,</span> <span class="n">intercept</span><span class="k">:</span> <span class="kt">Float</span><span class="o">)</span> <span class="k">=</span> <span class="nf">y</span><span class="o">(</span><span class="n">slope</span><span class="o">,</span> <span class="k">_</span><span class="o">,</span> <span class="n">intercept</span><span class="o">)</span>

<span class="c1">// Use "slopeInterceptLine" to create a new function of a single variable.</span>
<span class="c1">// In this case, a function that pairs integral inputs with even integers</span>
<span class="k">def</span> <span class="nf">y1</span> <span class="k">=</span> <span class="nf">slopeInterceptLine</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="mi">0</span><span class="o">)</span>

<span class="c1">// Use "slopeInterceptLine" to create a new function of a single variable.</span>
<span class="c1">// In this case, a function that pairs integral inputs with odd integers</span>
<span class="k">def</span> <span class="nf">y2</span> <span class="k">=</span> <span class="nf">slopeInterceptLine</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">)</span>
</code></pre></div></div>

<p>Notice how when defining “slopeInterceptLine”, you can pass its formal parameters – along with a special “<code class="language-scala highlight highlighter-rouge"><span class="k">_</span></code>”
identifier – to what looks like an invocation of “y”. It is not, of course, an invocation; it’s special Scala
syntax that allows you to concisely define functions via partial function application. “<code class="language-scala highlight highlighter-rouge"><span class="k">_</span></code>” is part of that special
syntax.</p>

<p>Once defined, we can then call our new functions on some values:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">indexes</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Float</span><span class="o">]</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">3</span><span class="o">,</span> <span class="mi">4</span><span class="o">,</span> <span class="mi">5</span><span class="o">,</span> <span class="mi">6</span><span class="o">,</span> <span class="mi">7</span><span class="o">,</span> <span class="mi">8</span><span class="o">,</span> <span class="mi">9</span><span class="o">,</span> <span class="mi">10</span><span class="o">)</span>

<span class="nf">println</span><span class="o">(</span><span class="nc">List</span><span class="o">(</span><span class="nv">indexes</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">y1</span><span class="o">),</span> <span class="s">"\n"</span><span class="o">,</span> <span class="nv">indexes</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">y2</span><span class="o">)))</span>
</code></pre></div></div>

<p>Which yields:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">List</span><span class="o">(</span><span class="nc">List</span><span class="o">(</span><span class="mf">2.0</span><span class="o">,</span> <span class="mf">4.0</span><span class="o">,</span> <span class="mf">6.0</span><span class="o">,</span> <span class="mf">8.0</span><span class="o">,</span> <span class="mf">10.0</span><span class="o">,</span> <span class="mf">12.0</span><span class="o">,</span> <span class="mf">14.0</span><span class="o">,</span> <span class="mf">16.0</span><span class="o">,</span> <span class="mf">18.0</span><span class="o">,</span> <span class="mf">20.0</span><span class="o">),</span>
  <span class="o">,</span> <span class="nc">List</span><span class="o">(</span><span class="mf">1.0</span><span class="o">,</span> <span class="mf">3.0</span><span class="o">,</span> <span class="mf">5.0</span><span class="o">,</span> <span class="mf">7.0</span><span class="o">,</span> <span class="mf">9.0</span><span class="o">,</span> <span class="mf">11.0</span><span class="o">,</span> <span class="mf">13.0</span><span class="o">,</span> <span class="mf">15.0</span><span class="o">,</span> <span class="mf">17.0</span><span class="o">,</span> <span class="mf">19.0</span><span class="o">))</span>
</code></pre></div></div>

<h3 id="adding-this-feature-to-lisp-using-a-macro">Adding this feature to Lisp using a macro</h3>

<p>Now that we’ve found a feature we’d like to add to Lisp, let’s get to it.
I find that when I set about writing a Lisp macro, it helps to first determine the signature I want the macro to
have and then determine the code I want it to generate. <em>I save the actual implementation for last</em>. So, to that end:</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Don't copy/paste -- this isn't ready to run yet</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">y</span> <span class="p">(</span><span class="nv">m</span> <span class="nv">x</span> <span class="nv">b</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">+</span> <span class="p">(</span><span class="nb">*</span> <span class="nv">m</span> <span class="nv">x</span><span class="p">)</span> <span class="nv">b</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">slope-intercept-line</span> <span class="p">(</span><span class="nv">slope</span> <span class="nv">intercept</span><span class="p">)</span>

  <span class="c1">;; "partial" is the macro we will write</span>
  <span class="c1">;; we would like it to generate code something like the following:</span>
  <span class="c1">;; (lambda (x) (y slope x intercept))</span>
  
  <span class="p">(</span><span class="nv">partial</span> <span class="nv">y</span> <span class="nv">slope</span> <span class="nv">_</span> <span class="nv">intercept</span><span class="p">))</span>
</code></pre></div></div>

<p>So, let’s do this in steps. First, we know that our macro will take as arguments:</p>

<ol>
  <li>A function whose partial application we wish to use to build a new function</li>
  <li>An optional list of arguments. In this list, we expect to be able to use “<code class="language-scala highlight highlighter-rouge"><span class="k">_</span></code>” for parameters we wish not to fix in the
partial application.</li>
</ol>

<p>As shown in the comment in code above, we’d like it to return a lambda whose formal parameters correspond to those in the arg list
specified as “<code class="language-scala highlight highlighter-rouge"><span class="k">_</span></code>”. We would like that lambda to fix the other arguments by creating a lexical closure over them.</p>

<p>Now, wouldn’t it be nice if we had a variable called “new-function-arguments” that was a list of all the formal
parameters to our new function, and a variable called “all-function-arguments” that was a list of all arguments used to
invoke the function “f”, which we are partially applying? For now, let’s assume they exist.</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Don't copy/paste -- this isn't ready to run yet</span>

<span class="p">(</span><span class="nb">defmacro</span> <span class="nv">partial</span> <span class="p">(</span><span class="nv">f</span> <span class="k">&amp;rest</span> <span class="nv">args</span><span class="p">)</span>
<span class="c1">;;</span>
<span class="c1">;; missing code here</span>
<span class="c1">;;</span>
      <span class="o">`</span><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="o">,@</span><span class="nv">new-function-parameters</span><span class="p">)</span> <span class="p">(</span><span class="o">,</span><span class="nv">f</span> <span class="o">,@</span><span class="nv">all-function-arguments</span><span class="p">)))</span>
</code></pre></div></div>

<p>Okay… so, how do we get the values of those variables? Well… let’s assume we have a function called “process-args”
that can, given the list of arguments passed to the macro, retrieve them for us. Note that <em>this</em> is the function that
will define the semantics of the “<code class="language-scala highlight highlighter-rouge"><span class="k">_</span></code>” identifier. We’ve cleverly separated it out from the rest of the macro.</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Don't copy/paste -- this isn't ready to run yet</span>

<span class="p">(</span><span class="nb">defmacro</span> <span class="nv">partial</span> <span class="p">(</span><span class="nv">f</span> <span class="k">&amp;rest</span> <span class="nv">args</span><span class="p">)</span>
<span class="c1">;;</span>
<span class="c1">;; missing code here</span>
<span class="c1">;;</span>
    <span class="p">(</span><span class="nb">multiple-value-bind</span> <span class="p">(</span><span class="nv">new-function-parameters</span> <span class="nv">all-function-arguments</span><span class="p">)</span>
        <span class="p">(</span><span class="nv">process-args</span> <span class="nv">args</span><span class="p">)</span>
      <span class="o">`</span><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="o">,@</span><span class="nv">new-function-parameters</span><span class="p">)</span> <span class="p">(</span><span class="o">,</span><span class="nv">f</span> <span class="o">,@</span><span class="nv">all-function-arguments</span><span class="p">))))</span>
</code></pre></div></div>

<p>So, what does this function need to do? Well, it needs to iterate over the “args” passed to the macro. For each symbol
in “args”:</p>

<ol>
  <li>If it <em>is not</em> “<code class="language-scala highlight highlighter-rouge"><span class="k">_</span></code>”, it adds it to the “all-function-arguments” list that it’s building.</li>
  <li>If it <em>is</em> “<code class="language-scala highlight highlighter-rouge"><span class="k">_</span></code>”, it replaces it with a new symbol, and adds that symbol to both the “new-function-parameters” and
the “all-function-arguments” lists that it’s building.</li>
</ol>

<p>The symbols added to “all-function-arguments” in step one are those we are holding fixed. The lambda that our macro creates
passes them in to the function we are partially applying. These symbols are expected to have meaning in the context in
which this macro was expanded. The lambda that the macro results in will capture the bindings for these symbols, and –
if returned as the result of a function call – create a lexical closure for these bindings. Anywhere the lambda is
used, these symbols will evaluate to the same values captured in the closure.</p>

<p>The symbols created in step two are those needed for the formal parameters when we define the lambda – so they are
added to the “new-function-parameters” list. They are <em>also</em> added to the “all-function-arguments” list – because they must
be passed to the function we are partially applying.</p>

<p>Let’s have a look.</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; This and the following snippets are ready to run.</span>

<span class="p">(</span><span class="nb">defmacro</span> <span class="nv">partial</span> <span class="p">(</span><span class="nv">f</span> <span class="k">&amp;rest</span> <span class="nv">args</span><span class="p">)</span>
  <span class="p">(</span><span class="k">labels</span> <span class="p">((</span><span class="nv">process-args</span> <span class="p">(</span><span class="nv">args</span><span class="p">)</span>
             <span class="p">(</span><span class="k">if</span> <span class="nv">args</span>
                 <span class="c1">;; if args isn't empty</span>
                       <span class="c1">;; Store the first element of "args" in a variable</span>
                 <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nb">first</span> <span class="p">(</span><span class="nb">car</span> <span class="nv">args</span><span class="p">))</span>
                       <span class="c1">;; Generate a new symbol, and store it in a variable.</span>
                       <span class="c1">;; We'll use this later, *if* "first" is "_"</span>
                       <span class="p">(</span><span class="nv">parameter</span> <span class="p">(</span><span class="nb">gensym</span><span class="p">)))</span>
                   <span class="p">(</span><span class="nb">multiple-value-bind</span>
                         <span class="p">(</span><span class="nv">rest-parameters</span> <span class="nv">rest-arguments</span><span class="p">)</span>
                       <span class="c1">;; Recur over the remaining args. Note that we expect </span>
                       <span class="c1">;; this function to return two values</span>
                       <span class="p">(</span><span class="nv">process-args</span> <span class="p">(</span><span class="nb">cdr</span> <span class="nv">args</span><span class="p">))</span>
                     <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eq</span> <span class="nb">first</span> <span class="ss">'_</span><span class="p">)</span>
                         <span class="c1">;; If the first arg is "_", then cons the new symbol </span>
                         <span class="c1">;; we created onto the front of both lists</span>
                         <span class="p">(</span><span class="nb">values</span> <span class="p">(</span><span class="nb">cons</span> <span class="nv">parameter</span> <span class="nv">rest-parameters</span><span class="p">)</span>
                                 <span class="p">(</span><span class="nb">cons</span> <span class="nv">parameter</span> <span class="nv">rest-arguments</span><span class="p">))</span>
                         <span class="c1">;; If the first arg is not "_", then cons it only onto </span>
                         <span class="c1">;; the list of arguments our lambda will pass to the </span>
                         <span class="c1">;; function we are partially applying. Do not add it </span>
                         <span class="c1">;; to the list of formal parameters for the lambda </span>
                         <span class="c1">;; we are creating.</span>
                         <span class="p">(</span><span class="nb">values</span> <span class="nv">rest-parameters</span>
                                 <span class="p">(</span><span class="nb">cons</span> <span class="nb">first</span> <span class="nv">rest-arguments</span><span class="p">)))))</span>
                 <span class="c1">;; else, just return empty args</span>
                 <span class="nv">args</span><span class="p">)))</span>
    <span class="p">(</span><span class="nb">multiple-value-bind</span> <span class="p">(</span><span class="nv">new-function-parameters</span> <span class="nv">all-function-arguments</span><span class="p">)</span>
        <span class="p">(</span><span class="nv">process-args</span> <span class="nv">args</span><span class="p">)</span>
      <span class="o">`</span><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="o">,@</span><span class="nv">new-function-parameters</span><span class="p">)</span> <span class="p">(</span><span class="o">,</span><span class="nv">f</span> <span class="o">,@</span><span class="nv">all-function-arguments</span><span class="p">)))))</span>
</code></pre></div></div>

<p>We can test our macro<sup id="fnref:out-of-order" role="doc-noteref"><a href="#fn:out-of-order" class="footnote" rel="footnote">4</a></sup>:</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">macroexpand-1</span> <span class="o">'</span><span class="p">(</span><span class="nv">partial</span> <span class="nv">f</span> <span class="mi">2</span> <span class="nv">_</span> <span class="mi">0</span><span class="p">))</span>
</code></pre></div></div>

<p>Which yields:</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nv">LAMBDA</span> <span class="p">(</span><span class="ss">#:G609</span><span class="p">)</span> <span class="p">(</span><span class="nv">F</span> <span class="mi">2</span> <span class="ss">#:G609</span> <span class="mi">0</span><span class="p">))</span>
</code></pre></div></div>

<p>Once that macro is defined, we can write the following code<sup id="fnref:setf" role="doc-noteref"><a href="#fn:setf" class="footnote" rel="footnote">5</a></sup>:</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">y</span> <span class="p">(</span><span class="nv">m</span> <span class="nv">x</span> <span class="nv">b</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">+</span> <span class="p">(</span><span class="nb">*</span> <span class="nv">m</span> <span class="nv">x</span><span class="p">)</span> <span class="nv">b</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">slope-intercept-line</span> <span class="p">(</span><span class="nv">slope</span> <span class="nv">intercept</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">partial</span> <span class="nv">y</span> <span class="nv">slope</span> <span class="nv">_</span> <span class="nv">intercept</span><span class="p">))</span>

<span class="p">(</span><span class="nb">setf</span> <span class="p">(</span><span class="nb">symbol-function</span> <span class="ss">'y1</span><span class="p">)</span> <span class="p">(</span><span class="nv">slope-intercept-line</span> <span class="mi">2</span> <span class="mi">0</span><span class="p">))</span>
<span class="p">(</span><span class="nb">setf</span> <span class="p">(</span><span class="nb">symbol-function</span> <span class="ss">'y2</span><span class="p">)</span> <span class="p">(</span><span class="nv">slope-intercept-line</span> <span class="mi">2</span> <span class="mi">-1</span><span class="p">))</span>

<span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">indexes</span> <span class="o">'</span><span class="p">(</span><span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span> <span class="mi">5</span> <span class="mi">6</span> <span class="mi">7</span> <span class="mi">8</span> <span class="mi">9</span> <span class="mi">10</span><span class="p">)))</span>
  <span class="p">(</span><span class="nb">list</span>
   <span class="p">(</span><span class="nb">mapcar</span> <span class="nf">#'</span><span class="nv">y1</span> <span class="nv">indexes</span><span class="p">)</span>
   <span class="p">(</span><span class="nb">mapcar</span> <span class="nf">#'</span><span class="nv">y2</span> <span class="nv">indexes</span><span class="p">)))</span>
</code></pre></div></div>

<p>Which yields:</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">((</span><span class="mi">2</span> <span class="mi">4</span> <span class="mi">6</span> <span class="mi">8</span> <span class="mi">10</span> <span class="mi">12</span> <span class="mi">14</span> <span class="mi">16</span> <span class="mi">18</span> <span class="mi">20</span><span class="p">)</span> <span class="p">(</span><span class="mi">1</span> <span class="mi">3</span> <span class="mi">5</span> <span class="mi">7</span> <span class="mi">9</span> <span class="mi">11</span> <span class="mi">13</span> <span class="mi">15</span> <span class="mi">17</span> <span class="mi">19</span><span class="p">))</span>
</code></pre></div></div>

<p>The same as the Scala code. We’ve added a feature to Lisp! Is this feature worthwhile? That’s debatable. For one, the
macro invocation expression is barely shorter than lambda expression. But “worthwhile” wasn’t the intent. I contend that 
this example is, at least, non-trivial ;-)</p>

<!---@formatter:off--->

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:books" role="doc-endnote">
      <p>Some available free online:</p>
      <ul>
        <li><a href="https://gigamonkeys.com/book/">Practical Common Lisp</a></li>
        <li><a href="https://cse.buffalo.edu/~shapiro/Commonlisp/">Common Lisp: An Interactive Approach</a></li>
        <li><a href="https://www.cs.cmu.edu/~dst/LispBook/">Common Lisp: A Gentle Introduction to Symbolic Computation</a></li>
        <li><a href="http://www.paulgraham.com/onlisp.html">On Lisp</a></li>
        <li><a href="https://github.com/norvig/paip-lisp">Paradigms of Artificial Intelligence Programming</a></li>
      </ul>

      <p>Others available for purchase:</p>
      <ul>
        <li><a href="http://weitz.de/cl-recipes/">Common Lisp Recipes</a></li>
        <li><a href="http://www.paulgraham.com/acl.html">ANSI Common Lisp</a></li>
        <li><a href="https://www.cambridge.org/core/books/lisp-in-small-pieces/66FD2BE3EDDDC68CA87D652C82CF849E">Lisp in Small Pieces</a>
<!---@formatter:on---></li>
      </ul>
      <p><a href="#fnref:books" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:param" role="doc-endnote">
      <p>Not to be confused with the “formal parameters” of a function definition in a programming language – which I
also happily refer to as “parameters” in this very same blog post. I count on context (and the reader’s keen intellect)
to distinguish between the two uses. These are the dangers of mixing domains (here: math and programming) in the same
article. <a href="#fnref:param" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:paramdef" role="doc-endnote">
      <p>Mathematicans would possibly notate this as such: \(y = f_{m,b}(x)\) <a href="#fnref:paramdef" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:out-of-order" role="doc-endnote">
      <p>Hold on. Can we evaluate this expression? “f” doesn’t have a value! The answer is “yes”, we can 
evaluate it. This macro expansion doesn’t attempt to call “f” – it just generates code that <em>would</em> call it. <a href="#fnref:out-of-order" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:setf" role="doc-endnote">
      <p>Why the do we <code class="language-lisp highlight highlighter-rouge"><span class="nb">setf</span></code> the <code class="language-lisp highlight highlighter-rouge"><span class="nb">symbol-function</span></code> of the symbol we chose as the name of our function – instead of
just using <code class="language-lisp highlight highlighter-rouge"><span class="nb">defun</span></code>? Well, in short: because we aren’t <em>defining</em> a function – we aren’t specifying its arguments and we
aren’t providing a set of expressions which make up the function body. Instead, we already <em>have</em> a function (the one
returned by <code class="language-lisp highlight highlighter-rouge"><span class="nv">slope-intercept-line</span></code>) and we just want to give it a name. <a href="#fnref:setf" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><summary type="html"><![CDATA[Lisp Macros: Learning by Example]]></summary></entry><entry><title type="html">Happy New Year</title><link href="/2022/12/31/happy-new-year.html" rel="alternate" type="text/html" title="Happy New Year" /><published>2022-12-31T00:00:00+00:00</published><updated>2022-12-31T00:00:00+00:00</updated><id>/2022/12/31/happy-new-year</id><content type="html" xml:base="/2022/12/31/happy-new-year.html"><![CDATA[<h2 id="happy-new-year">Happy New Year!</h2>

<p>I hate publicizing New Year’s resolutions – mostly because I love making them, but hate committing to them. Alas, here 
we are… I’m publishing a blog and using it to declare a New Year’s resolution:</p>

<p>In 2023, I want to try to write more.</p>

<p>2022 was a pretty good year in a lot of ways. For one: I learned a lot. For another: it really felt like we were almost 
kinda-sorta entering a post-pandemic existence.</p>

<p>I’m still trying to figure out what I’ll write about, but I suspect a significant portion will be small, digestible bits 
about things I’ve learned. Since I’m a software engineer, I’d expect “things I’ve learned” to have a heavy bias towards 
Information Technology.</p>

<p>That being said, however, I do have hobbies that aren’t tech related. Maybe they’ll make an appearance here. For instance:
I have a strange obsession with pedestrian overpasses. Maybe you’ll see a post or two about those!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Happy New Year!]]></summary></entry></feed>