<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>

    <title>Computer Things</title>
    <description>Computer Things by Erik Hanson</description>
    <link>https://eahanson.com/</link>
    <lastBuildDate>Thu, 12 Jun 2025 10:00:00 GMT</lastBuildDate>
    <pubDate>Thu, 12 Jun 2025 10:00:00 GMT</pubDate>
    <ttl>1800</ttl>
    <atom:link href="https://eahanson.com/rss" rel="self" type="application/rss+xml"/>

    
      <item>
        <title>Make Elixir Tests Faster</title>
        <description><![CDATA[ Tips on making your Elixir tests run faster.
 ]]></description>
        <link>https://eahanson.com/articles/faster-tests</link>
        <guid>https://eahanson.com/articles/faster-tests</guid>
        <pubDate>Thu, 12 Jun 2025 10:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Make Elixir Tests Faster</h4>
    
    <p>
      Everybody wants faster tests, and nobody wants to spend more time than necessary writing them.
      In this article, I will show a few ways to make Elixir tests faster.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Run Tests In Parallel</h4>
    
    <p>
      The most obvious way to make tests faster is to run them in parallel. ExUnit of course makes this easy
      with <code>async: true</code>:
    </p>

    <p>
      
<pre><code class="c-text--code language-elixir">defmodule MyTest do
  use ExUnit.Case, async: true

  # ...
</code></pre>
    </p>

    <p>
      But you have to <i>remember</i>
      to add <code>async: true</code>
      to every test, and remembering is hard,
      especially when there are multiple people working on the codebase. Luckily,
      <a href="https://hexdocs.pm/credo/overview.html">Credo</a>
      has a check called <a href="https://hexdocs.pm/credo/Credo.Check.Refactor.PassAsyncInTestCases.html#module-explanation">
      PassAsyncInTestCases
      </a>. Just add the following to your
      <code>.credo.exs</code>
      in the <code>Refactoring Opportunities</code>
      section:
    </p>

    <p>
      
<pre><code class="c-text--code language-elixir">{Credo.Check.Refactor.PassAsyncInTestCases, []},
</code></pre>
    </p>

    <p>
      Credo will now fail if you don&rsquo;t explicity add an <code>async</code>
      value (either <code>true</code>
      or <code>false</code>).
    </p>

    <p>
      If you aren&rsquo;t already using Credo, I&rsquo;d recommend adding it. You can disable the checks you don&rsquo;t care about
      or that would be too time-consuming to fix right now. I&rsquo;d recommend running it in CI at the very least, but
      you might also want to run it before checking code in (via a commit hook or perhaps in <a href="https://github.com/synchronal/medic-rs">your shipit script</a>),
      or even directly in your editor.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Run Fewer Tests</h4>
    
    <p>
      <code>mix test</code> has a <code>--stale</code> option that only runs tests that reference files which have
      changed since the last time you ran tests with this option. If you get in the habit of running <code>mix test --stale</code>,
      you will end up saving time by running fewer tests. It&rsquo;s probably a good idea
      to run the full suite before pushing code.
    </p>

    <p>
      When running <code>mix test --stale</code>, you might be surprised at the number of tests that run. If your
      project has a big web of module dependencies, then changing one module might cause a lot of other modules to change,
      causing <code>mix test --stale</code> to run a lot of tests.
    </p>

    <p>
      This is where the <a href="/articles/boundary" data-phx-link="redirect" data-phx-link-state="push">Boundary</a>
      library comes in handy. It will help you enforce
      boundaries between different sections of your codebase, which will reduce the number of modules that get
      compiled when you make a change, which will cause fewer tests to run via <code>mix test --stale</code>,
      which will result in a faster test suite.
    </p>

    <p>
      <i>Installing</i> Boundary is not hard. <i>Fixing</i> boundary violations can take time though. I&rsquo;d recommend
      installing it as soon as possible, and then allowing existing boundary violations so that you can at least get
      alerted to new boundary violations. Over time, you can clean up the existing violations to further decrease
      compilation times and increase stale-test speed.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Sleep Less</h4>
    
    <p>
      When testing some asynchronous code, your test sometimes has to wait for the async action to complete before
      it can successfully assert on the state. The easy way to do this is just drop in <code>:timer.sleep(1_000)</code>
      and hope that the async action has finished. Unfortunately, this has the dual downsides of making the test suite
      slower and more flaky.
    </p>

    <p>
      A better way is to retry your assertion repeatedly until it passes. The <code>Moar</code>
      library (of which
      I am an author) has a <a href="https://hexdocs.pm/moar/Moar.Retry.html">Retry</a>
      module with <code>retry_for</code>
      and <code>rescue_for!</code>
      functions:
    </p>

    <p>
      
<pre><code class="c-text--code language-elixir"># repeatedly retry up to 5 seconds for the element with ID &quot;status&quot; to be &quot;finished&quot;
Moar.Retry.rescue_for!(5000, fn -&gt;
  assert view |&gt; element(&quot;#status&quot;) |&gt; render() == &quot;finished&quot;
end)
</code></pre>
    </p>

    <p>
      
<pre><code class="c-text--code language-elixir"># repeatedly retry up to 5 seconds for the element with ID &quot;status&quot; to be &quot;finished&quot;,
# and then make a different assertion
Moar.Retry.retry_for(5000, fn -&gt;
  view |&gt; element(&quot;#status&quot;) |&gt; render() == &quot;finished&quot;
end)

assert view |&gt; element(&quot;#total&quot;) |&gt; render() == &quot;8,675,309&quot;
</code></pre>
    </p>

    <p>
      There is a downside to all that retrying and waiting: you are doing unnecessary work which may slow down the
      test suite (but probably not as much as sleeping for a long time does). Another approach is to
      send a message to your test when the thing you are waiting for has finished. Look for a future
      article about how to do that.
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>Ranked Placement has launched!</title>
        <description><![CDATA[ Ranked Placement facilitates the placement of students and other prospective interns at internship and practica sites using the same matching algorithm as medical student residency matching.
 ]]></description>
        <link>https://eahanson.com/articles/ranked-placement</link>
        <guid>https://eahanson.com/articles/ranked-placement</guid>
        <pubDate>Mon, 26 May 2025 10:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Internships</h4>
    
    <p>
      Perhaps the most impactful part of my college career was being placed at a two-semester, full-time, paid
      internship (extending my time at school from 4 years to 5 years). I learned a lot, got good work experience,
      and made new friends. I even stayed on as an employee for a while after graduating from college, which made
      getting my next job eaiser.
    </p>

    <p>
      The internship program at my university was optional, but many educational programs have made internships
      a required part of their training. The most well-known example is medical residency, where new medical degree
      recipients work under the supervision of senior clinicians to work towards obtaining a license
      to practice medicine.
    </p>

    <p>
      My internship placement was straightforward: I looked through a binder of possible internships, applied to
      one, and luckily they accepted me.
    </p>

    <p>
      For programs that require internships as part of their training, a better system is obviously needed.
      The system commonly used for medical residencies and many other internship types allows the prospective
      interns and the internship sites to rank each other after going through an interview period. Once all the
      interns and sites have finished ranking each other, an algorithm is used to instantly place interns at sites,
      weighing the prospective interns&rsquo; preferences higher than the sites&rsquo; preferences.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Ranked Placement</h4>
    
    <p>
      I&rsquo;m excited to announce that my Reflective Software co-founder Eric Saxby and I built and launched such a system
      in late 2024. We call it <a href="https://rankedplacement.com">Ranked Placement</a>.
      Since its launch, it has matched hundreds of students in internships for our pilot customer,
      the Bay Area Practicum Information Collaborative.
    </p>

    <p>
      Ranked Placement is an easy-to-use application and placement system that can be used for various types of
      ranked-choice internship and practica matching.
      We are now ready to onboard additional customers. Please contact us at
      <a href="mailto:contact@rankedplacement.com" data-phx-link="redirect" data-phx-link-state="push">contact@rankedplacement.com</a>
      to learn more.
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>Why Boundary?</title>
        <description><![CDATA[ About the Boundary library, and why I highly recommend adding it to every Phoenix project from the very beginning.
 ]]></description>
        <link>https://eahanson.com/articles/boundary</link>
        <guid>https://eahanson.com/articles/boundary</guid>
        <pubDate>Fri, 29 Nov 2024 10:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Why Boundary?</h4>
    
    <p>
      <a href="https://hex.pm/packages/boundary">Boundary</a>
      by Sa&scaron;a Juri&cacute;:
      <blockquote>
        <p>
          Boundary is a library which helps managing and restraining cross-module dependencies in Elixir projects.
          A few examples of the things you can do with boundary include:
        </p>

        <p>
          <ul>
            <li>Prevent invocations from the context layer to the web layer</li>
            <li>Prevent invocations from the web layer to internal context modules</li>
            <li>Prevent usage of Phoenix and Plug in the context layer</li>
            <li>Limit usage of Ecto in the web layer to only Ecto.Changeset</li>
            <li>Allow :mix modules to be used only at compile time</li>
          </ul>
        </p>
      </blockquote>
    </p>
    <p>
      Restricting certain layers of your application from calling each other can make your application easier
      to change, but it can also help reduce incremental compile time. Have you ever changed a couple lines in
      a LiveView and had to wait for 43 files to compile? Boundary can save you from that pain.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">When Boundary?</h4>
    
    <p>
      You can add Boundary to your application at any time, but it is <i>far</i> easier to add it from the
      very beginning. Just do it. If it doesn&rsquo;t work out for you, it&rsquo;s very easy to remove. <a href="https://hexdocs.pm/boundary/readme.html">Installation instructions</a>.
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>Phoenix Project Layout</title>
        <description><![CDATA[ A nonstandard way to lay out your Phoenix project.
 ]]></description>
        <link>https://eahanson.com/articles/phoenix-project-layout</link>
        <guid>https://eahanson.com/articles/phoenix-project-layout</guid>
        <pubDate>Tue, 25 Jun 2024 10:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    
    
    <p>
      A newly-generated Phoenix project has a standard module layout. My
      <a href="https://reflective.dev">Reflective Software</a>
      co-founder and I have experimented
      with different module layouts over the years and this is what our projects currently look like:
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <div class="c-text--code--title">module structure</div>
<pre><code class="c-text--code language-elixir">Core                      # instead of something like &quot;MyApp&quot;
  Core.People             # a context module
    Core.People.Profile   # contains changeset function(s) and an embedded Query module
    ...
Etc                       # its sub-modules could be external libraries but are too small for that
  Etc.S3Uploader          # has functions for uploading to S3
  ...
Extra                     # its sub-modules &quot;extend&quot; library functions
  Extra.URI               # has extra URI-related functions like `Extra.URI.path/1`
  ...
Schema                    # contains schemas and structs
  Schema.Profile          # just the database schema for Profiles; no functions
  ...
Web                       # instead of something like &quot;MyAppWeb&quot;
  Web.Components          # Phoenix components
    Web.Components.Nav    # a component
    ...
  Web.Controllers         # Phoenix controllers
    Web.Controllers.Home  # a controller
    ...
  Web.Live                # Phoenix LiveViews
    Web.Live.Profile      # a LiveView
    ...
  Web.Plugs               # Plugs
  endpoint.ex
  router.ex
  ...
</code></pre>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      Along with this layout, we use the <a href="https://hexdocs.pm/boundary/Boundary.html">Boundary</a>
      library to define and enforce boundary separation. (Tip: it&rsquo;s a lot easier to enforce boundaries
      if you set them up at the beginning of a project.)
      A project&rsquo;s boundaries might look like this:
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <div class="c-text--code--title">boundary dependencies in each top-level module</div>
<pre><code class="c-text--code language-elixir"># Core
deps: [Etc, Extra, Schema]

# Etc
deps: []

# Extra
deps: []

# Schema
deps: []

# Web
deps: [Core, Etc, Extra, Schema]
</code></pre>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      One obvious difference between this layout and the generated code is that instead of <code>MyApp</code>
      and <code>MyAppWeb</code>, we use <code>Core</code>
      and <code>Web</code>. It&rsquo;s just as descriptive, a lot shorter, and easier to copy from other projects.
    </p>

    <p>
      Another difference is that we split &ldquo;models&rdquo; into changeset modules and schema modules. A schema module
      just defines a schema struct, and is accessible from modules such as <code>Web</code>.
      A changeset module defines changesets and has an internal <code>Query</code> module containing composable
      query parts; it is not accessible from modules like <code>Web</code>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      <div class="c-text--code--title">lib/schema/profile.ex</div>
<pre><code class="c-text--code language-elixir">defmodule Schema.Profile do
  use Schema

  @type t() :: %__MODULE__{}

  schema &quot;profiles&quot; do
    field :name, :string
    field :slug, :string
    field :totp_secret, :binary, read_after_writes: true

    belongs_to :org, Schema.Org

    timestamps()
  end
end
</code></pre>
    </p>
    <p>
      <div class="c-text--code--title">lib/core/people/profile.ex</div>
<pre><code class="c-text--code language-elixir">defmodule Core.People.Profile do
  import Ecto.Changeset

  @type t() :: Schema.Profile.t()

  @required_attrs ~w[name]a
  @optional_attrs ~w[org_id]a

  def changeset(data \\ %Schema.Profile{}, attrs) do
    data
    |&gt; cast(Map.new(attrs), @required_attrs ++ @optional_attrs)
    |&gt; put_slug()
    |&gt; validate_required(@required_attrs)
    |&gt; unique_constraint(:slug)
  end

  defp put_slug(changeset) do
    case fetch_field!(changeset, :name) do
      nil -&gt; changeset
      name -&gt; changeset |&gt; put_change(:slug, Extra.String.to_slug(name, random: 4))
    end
  end

  defmodule Query do
    import Ecto.Query
    alias Core.People
    alias Schema.Profile

    def base,
      do: from(_ in Profile, as: :profiles) |&gt; default_order()

    def default_order(query \\ base()),
      do: query |&gt; order_by([profiles: profiles], asc: profiles.name, asc: profiles.seq)

    def join_emails(query \\ base()),
      do: query |&gt; join(:left, [profiles: profiles], email in assoc(profiles, :emails), as: :emails)

    def where_email_address(query \\ base(), email_address),
      do: query |&gt; join_emails() |&gt; People.Email.Query.where_address(email_address)
  end
end
</code></pre>
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    Sometimes our schema modules are just plain structs:
  
  </div><div class="c-layout--vertical--item">
    
    
    <div class="c-text--code--title">lib/schema/message.ex</div>
<pre><code class="c-text--code language-elixir">defmodule Schema.Message do
  @type t() :: %__MODULE__{}
  defstruct ~w[body subject]a
end
</code></pre>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      <i>Look for a future blog post about changesets and composable queries.</i>
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>Web.Paths</title>
        <description><![CDATA[ A "Web.Paths" module in your Elixir Phoenix app can be a helpful indirection.
 ]]></description>
        <link>https://eahanson.com/articles/web-paths</link>
        <guid>https://eahanson.com/articles/web-paths</guid>
        <pubDate>Tue, 25 Jun 2024 09:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    
    
    <p>
      A relatively new feature of Phoenix is <a href="https://hexdocs.pm/phoenix/Phoenix.VerifiedRoutes.html">verified routes</a>,
      which lets you create routes with the <code>~p</code> sigil that result in compiler warnings when the route
      is invalid. For example, <code>~p"/users/new"</code> will fail if there is no such path defined.
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      You can sprinkle your code with <code>~p</code> sigils, but I&rsquo;ve found that there are advantages to having
      a module that contains functions for each path in your project, like this:
    </p>

    <p>
      <div class="c-text--code--title">web/paths.ex</div>
<pre><code class="c-text--code language-elixir">defmodule Web.Paths do
  use Web, :verified_routes

  @customer_id &quot;58-gkjScjj8&quot;

  def home, do: ~p&quot;/&quot;
  def invitation(%Schema.User{type: admin} = user), do: ~p&quot;/admin/invitation/#{user.id}&quot;
  def invitation(user), do: ~p&quot;/invitation/#{user.id}&quot;
  def login, do: ~p&quot;/auth/login&quot;
  def logo, do: static(&quot;images/logo.png&quot;)
  def remote_auth, do: &quot;https://auth29-g.example.net/customer/#{@customer_id}/auth&quot;
  def styleguide(module, function), do: ~p&quot;/styleguide/#{module}/#{function}&quot;
end
</code></pre>
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      Note that in this example, the module is <code>Web.Paths</code>, not <code>MyAppWeb.Paths</code>.
      See <a href="https://eahanson.com/articles/phoenix-project-layout">Phoenix Project Layout</a> for more info.
    </p>

    <p>
      More things to note:
      <ul>
        <li>As a plain module with functions, your editor can autocomplete your routes.</li>
        <li>The functions usually fit on a single line, so you can see a lot more routes at a time.</li>
        <li>
          A different invitation path is returned by pattern matching on the user type which reduces the need for
          duplicated code that chooses the correct route.
        </li>
        <li>The logo isn&rsquo;t a <code>~p</code> sigil but using the generated route works the same as other routes.</li>
        <li>Function parameters are listed so it&rsquo;s easy to tell what&rsquo;s required.</li>
        <li>You can name your functions something that&rsquo;s more meaningful than the path or URL.</li>
      </ul>
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>Jumping To Related Files In Your Editor</title>
        <description><![CDATA[ Reliably jump from one file to any of its related files in your editor.
 ]]></description>
        <link>https://eahanson.com/articles/related-files</link>
        <guid>https://eahanson.com/articles/related-files</guid>
        <pubDate>Thu, 23 May 2024 00:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <section>
  <p>
    It&rsquo;s common for code editors to have a built-in or extension-provided feature to switch between a code file
    and its test, using some heuristics that work <i>most of the time</i>. Some editors and extensions will also try
    to jump to other kinds of related files, such as CSS files. In my experience, these tools find the related files
    often enough to sound promising, but are frustrating in practice because they don&rsquo;t work 100% of the time,
    or don&rsquo;t work on entire types of files.
  </p>
</section>

<section>
  <p>
    I came up with a solution: manually add annotations in each file that point to its related files.
    For example, a module that renders some HTML might have annotations linking to a SASS file as well as
    the unit test for that module:
  </p>

  <p>
    
<pre><code class="c-text--code language-elixir"># @related [test](test/web/components/nav_test.exs)
# @related [sass](assets/css/components/_nav.sass)
</code></pre>
  </p>
  <p>
    The format is: &ldquo;<code>@related</code>&rdquo;, followed by a Markdown-style link with the name and the path to the file.
    I place them at the top of the file, and put them in a comment so as not to create a syntax error.
  </p>
</section>

<section>
  <p>I created a <a href="https://nova.app">Nova</a> editor extension to pop up a list of related files:</p>

  <div class="c-content--image">
  
  <img src="/images/related-files.png" style="">
</div>

  <p>
    There are also extensions for <a href="https://github.com/sstoltze/related-files">Emacs</a>
    and <a href="https://github.com/synchronal/related-files.nvim">Neovim</a>.
    I also created a script to validate that the file paths are valid but it&rsquo;s not quite ready for release.
  </p>
</section> ]]></content:encoded>
      </item>
    
      <item>
        <title>Version 1.0 of Test Reflector!</title>
        <description><![CDATA[ Test Reflector is a MacOS app that shows your GitHub Actions status in your menubar.
 ]]></description>
        <link>https://eahanson.com/articles/test-reflector</link>
        <guid>https://eahanson.com/articles/test-reflector</guid>
        <pubDate>Fri, 26 Apr 2024 00:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <section>
  <div class="c-content--image">
  <a href="https://testreflector.app">
    <img src="/images/testreflector.png" style="" width="300" height="300">
  </a>
  
</div>

  <p>
    My business partner Eric Saxby wrote a MacOS app called Test Reflector that adds GitHub Actions status
    to your menubar. Our company (<a href="https://reflective.dev">Reflective Software</a>)
    just released version 1.0 in the App Store.
  </p>

  <blockquote>
    Effortlessly monitor your GitHub Actions workflows directly from your Mac&rsquo;s menubar. Test Reflector provides a convenient overview of your workflows&rsquo; statuses and recent results, eliminating the need to constantly switch tabs or watch your email for failure notices.
  </blockquote>

  <p>
    <a href="https://testreflector.app">Read more about it.</a>
  </p>

  <div class="c-content--image">
  <a href="https://apps.apple.com/us/app/test-reflector/id6483935981?mt=12">
    <img src="/images/Download_on_the_Mac_App_Store_Badge_US-UK_RGB_blk_092917.svg" style="" height="50">
  </a>
  
</div>

  <div class="c-content--image">
  <a href="https://testreflector.app">
    <img src="/images/test-reflector-menubar@768w.png" style="">
  </a>
  
</div>
  <div class="c-content--image">
  <a href="https://testreflector.app">
    <img src="/images/test-reflector-settings.png" style="">
  </a>
  
</div>
</section> ]]></content:encoded>
      </item>
    
      <item>
        <title>Extensions for Panic's Nova Editor</title>
        <description><![CDATA[ I wrote some extensions for Nova that you might find handy.
 ]]></description>
        <link>https://eahanson.com/articles/nova-extensions</link>
        <guid>https://eahanson.com/articles/nova-extensions</guid>
        <pubDate>Thu, 21 Mar 2024 00:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    
    
    <p>
      <a href="https://nova.app">Nova</a>
      is a code editor written by <a href="https://panic.com">Panic</a>,
      the makers of your favorite <a href="https://panic.com/transmit">FTP app</a>.
      I&rsquo;ve written several extensions for Nova. A few of them have also been ported to other editors by me
      or by other people.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Copy Path</h4>
    
    <p>This extension copies the absolute or relative path of the current file,
optionally including the line number and column number.
</p>

    <p>
      Read more in the <a href="https://github.com/eahanson/copy-path.novaextension">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.copy-path&amp;name=Copy+Path">directly in Nova itself</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Document Sections</h4>
    
    <p>Sometimes, despite your best efforts, a document gets very large and hard to navigate, and for whatever reason,
the language server can&#39;t help you navigate. This extension provides commands to let you go to a specific
section of a document, or to go to the previous or next section. A section is defined by a line of text that
starts with a section indicator, optionally followed by some text terminated by a newline.
</p>

    <p>
      Read more in the <a href="https://github.com/eahanson/document-sections.novaextension">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.document-sections&amp;name=Document+Sections">directly in Nova itself</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Elixir Manual Formatter</h4>
    
    <p>Sometimes the ElixirLS extension fails to automatically format one or all files. This extension provides a
command to format the current file, and a command to format all files. It intentionally doesn&rsquo;t try to format
on save because the ElixirLS extension normally does that correctly.
</p>

    <p>
      Read more in the <a href="https://github.com/eahanson/elixir-manual-formatter.novaextension">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.elixir-manual-formatter&amp;name=Elixir+Manual+Formatter">directly in Nova itself</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Go To Tab</h4>
    
    <p>This extension shows a list of open editors and lets you choose one to go to.
</p>

    <p>
      Read more in the <a href="https://github.com/eahanson/go-to-tab.novaextension">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.go-to-tab&amp;name=Go+To+Tab">directly in Nova itself</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Open File at Path</h4>
    
    <p>This extension opens a palette into which you can type a file path and optionally line number and column
number. The palette will default to the first line of text from the clipboard. This is especially useful when
you have a file path in some stack trace or test failure but you can&#39;t click on it because it&rsquo;s in a Report,
or Nova doesn&rsquo;t recognize it because it has a line number and maybe a column number appended.
</p>

    <p>
      Read more in the <a href="https://github.com/eahanson/open-file-at-path.novaextension">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.open-file-at-path&amp;name=Open+File+at+Path">directly in Nova itself</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Open Recent</h4>
    
    <p>Open Recent shows a list of recently-used editors and lets you choose one to open.
</p>

    <p>
      Read more in the <a href="https://github.com/eahanson/open-recent.novaextension">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.open-recent&amp;name=Open+Recent">directly in Nova itself</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Open Related File</h4>
    
    <p>This extension opens a file related to the current file.
It&rsquo;s common for code editors to have a built-in or extension-provided feature to switch between a code file
and its test, using some heuristics that work most of the time. Some editors and extensions will also try to
jump to other kinds of related files, such as CSS files. In my experience, these tools find the related files
often enough to sound promising, but are frustrating in practice because they don&#39;t work 100% of the time,
or don&rsquo;t work on entire types of files.
</p><p>This extension allows authors to specify each related file using a
simple syntax. The upside is that the extension works perfectly all the time. The downside is that the author
has to list each related file and has to update them when files move. To specify a related file, add an
annotation somewhere in the file (perhaps in a comment).
</p><p>The annotation must start with &ldquo;@related&rdquo; and contain
one or more Markdown-style links in the form &ldquo;[name](file-path)&rdquo;, where &ldquo;name&rdquo; is any string and &ldquo;file-path&rdquo;
is a path to the file, relative to the project root.
</p>

    <p>
      Read more in the <a href="https://github.com/synchronal/related-files.novaextension">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.related-files&amp;name=Open+Related+File">directly in Nova itself</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Smart Sort Lines</h4>
    
    <p>This extension sorts lines of code with a little bit of intelligence when sorting a multi-line, comma-separated
list. If all but the last line of text end with a comma, then after sorting, all but the last line of text will
still end with a comma.
</p>

    <p>
      Read more in the <a href="https://github.com/eahanson/smart-sort-lines/blob/main/smart-sort-lines.novaextension/README.md">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.smart-sort-lines&amp;name=Smart+Sort+Lines">directly in Nova itself</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Trail</h4>
    
    <p>This extension lets you create a trail of editor positions as you navigate code so that you can easily get
back to where you came from. As you navigate your code, push waypoints onto Trail&rsquo;s stack with the
&ldquo;Push Waypoint&rdquo; command. Then when you want to get back to where you came from, pop the last waypoint off of
Trail&rsquo;s stack with the &ldquo;Pop Waypoint&rdquo; command which will move the text cursor to the file, line, and column
that you previously pushed. If you want to pop multiple waypoints at once, use &ldquo;Pop To Waypoint&rdquo; which will
show you the entire stack to of waypoints to choose from.
</p>

    <p>
      Read more in the <a href="https://github.com/eahanson/trail.novaextension">readme</a>,
      or open it <a href="nova://extension/?id=eahanson.trail&amp;name=Trail">directly in Nova itself</a>.
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>Querying HTML and XML in Elixir with HtmlQuery and XmlQuery</title>
        <description><![CDATA[ Find and extract information from HTML and XML using Elixir.
 ]]></description>
        <link>https://eahanson.com/articles/html-query-xml-query</link>
        <guid>https://eahanson.com/articles/html-query-xml-query</guid>
        <pubDate>Sun, 03 Mar 2024 00:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    
    
    <p>
      My colleague Eric Saxby and I created two Elixir libraries for finding and extracting information from
      HTML and XML. One is called <a href="https://github.com/synchronal/html_query">HtmlQuery</a>
      and the other is called <a href="https://github.com/synchronal/xml_query">XmlQuery</a>.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Quick overview</h4>
    
    <p>
      Before diving into the details, here is a quick overview.
    </p>

    <div class="c-layout--vertical c-layout--vertical--gap-m c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    
    <div class="c-text--code--title">HTML</div>
<pre><code class="c-text--code language-xml">&lt;h1&gt;Please update your profile&lt;/h1&gt;

&lt;form id=&quot;profile&quot; test-role=&quot;profile&quot;&gt;
  &lt;label&gt;Name &lt;input name=&quot;name&quot; type=&quot;text&quot; value=&quot;Fido&quot;&gt; &lt;/label&gt;
  &lt;label&gt;Age &lt;input name=&quot;age&quot; type=&quot;text&quot; value=&quot;10&quot;&gt; &lt;/label&gt;
  &lt;label&gt;Bio &lt;textarea name=&quot;bio&quot;&gt;Fido likes long walks and playing fetch.&lt;/textarea&gt; &lt;/label&gt;
&lt;/form&gt;
</code></pre>
  </div><div class="c-layout--vertical--item">
    
    <div class="c-text--code--title">XML</div>
<pre><code class="c-text--code language-xml">&lt;profile id=&quot;123&quot;&gt;
  &lt;name&gt;Fido&lt;/name&gt;
  &lt;age&gt;10&lt;/age&gt;
  &lt;bio&gt;Fido likes long walks and playing fetch.&lt;/bio&gt;
&lt;/profile&gt;
</code></pre>
  </div><div class="c-layout--vertical--item">
    
    <div class="c-text--code--title">Elixir</div>
<pre><code class="c-text--code language-elixir">HtmlQuery.find(
  html_contents,
  &quot;textarea[name=bio]&quot;
)
|&gt; HtmlQuery.text()

# returns &quot;Fido likes long walks and playing fetch.&quot;

XmlQuery.find(
  xml_contents,
  &quot;//bio&quot;
)
|&gt; XmlQuery.text()

# returns &quot;Fido likes long walks and playing fetch.&quot;
</code></pre>
  </div>
</div>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Motivation</h4>
    
    <p>
      In the 6 years or so that we have both been writing Elixir software, we have needed to
      search and extract a lot of HTML and XML. The HTML searching and extracting has been mostly in unit tests
      of web apps. The XML searching and extracting has mostly been in healthcare data processing
      apps.
    </p>

    <p>
      We started writing various helpers in each project we worked on and eventually extracted HtmlQuery, and
      more recently, XmlQuery. The API has changed over time, starting off relatively simple, then getting more
      complicated, and then eventually back to simple but easily composable.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">The API</h4>
    
    <p>
      The API has 3 main query functions: <code>all/2</code>, <code>find/2</code>, and <code>find!/2</code>.
      They each take a string of HTML or XML (depending on the library) and a CSS selector (for HtmlQuery) or an
      XPath (for XmlQuery). <code>all/2</code>
      returns every element that matches the selector, <code>find/2</code>
      returns the first element that matches the selector (or nil if none is found), and <code>find!/2</code>
      returns
      the single element that matches the selector, raising if no elements were found or if more than one element
      was found.
    </p>

    <p>
      Once an element is found, <code>text/1</code> returns its text, and <code>attr/2</code> returns the value
      of the given attribute.

      When finding multiple elements with <code>all/2</code>, we discovered that it&rsquo;s simpler to pipe the results
      into another function, rather than having various options built into <code>all/2</code>. So to get the text
      or value of each button in the following HTML:
    </p>

    <p>
      <div class="c-text--code--title">HTML</div>
<pre><code class="c-text--code language-xml">&lt;fieldset&gt;
  &lt;input type=&quot;radio&quot; name=&quot;animal&quot; value=&quot;1&quot;&gt;Ant&lt;/input&gt;
  &lt;input type=&quot;radio&quot; name=&quot;animal&quot; value=&quot;2&quot;&gt;Bat&lt;/input&gt;
  &lt;input type=&quot;radio&quot; name=&quot;animal&quot; value=&quot;3&quot;&gt;Cat&lt;/input&gt;
&lt;/fieldset&gt;
</code></pre>
    </p>

    <p>
      you would use the following code:
    </p>

    <p>
      <div class="c-text--code--title">Elixir</div>
<pre><code class="c-text--code language-elixir"># text
html
|&gt; HtmlQuery.all(&quot;input[type=radio]&quot;)
|&gt; Enum.map(&amp;HtmlQuery.text/1)

# value
html
|&gt; HtmlQuery.all(&quot;input[type=radio]&quot;)
|&gt; Enum.map(&amp;HtmlQuery.attr(&amp;1, :value))
</code></pre>
    </p>

    <p>
      That&rsquo;s the main API. Easy to remember, yet very powerful. For a more detailed description, documentation
      about some extra functions, and details on a shortcut for writing CSS selectors, check out the
      <a href="https://hexdocs.pm/html_query/readme.html">documentation for HtmlQuery</a>
      and the <a href="https://hexdocs.pm/xml_query/readme.html">documentation for XmlQuery</a>.
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>Creating an RSS feed in Elixir and Phoenix</title>
        <description><![CDATA[ It&apos;s easy to hand-roll an RSS feed using Elixir and Phoenix.
 ]]></description>
        <link>https://eahanson.com/articles/rss</link>
        <guid>https://eahanson.com/articles/rss</guid>
        <pubDate>Tue, 27 Feb 2024 00:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    
    
    <p>
      Hand-rolling an RSS feed with <a href="https://elixir-lang.org">Elixir</a>
      and <a href="https://www.phoenixframework.org">Phoenix</a>
      is pretty straightforward.
      You just need a list of feed items, a controller, a template, and a view. In this article,
      I&rsquo;ll assume the list of items is a list of blog articles.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Articles</h4>
    
    <p>
      A simple way to store your articles is in a list somewhere. A more complicated way is to
      store it in a database. I&rsquo;ll assume we&rsquo;re storing it in a list.
    </p>

    <p><div class="c-text--code--title">Elixir</div>
<pre><code class="c-text--code language-elixir">defmodule Core.Articles do
  @articles [
    %{title: &quot;Apples&quot;, description: &quot;Red or green fruit&quot;, published_at: ~U[2024-02-25 00:00:00Z], slug: &quot;apples&quot;},
    %{title: &quot;Bananas&quot;, description: &quot;Yellow fruit&quot;, published_at: ~U[2024-02-26 00:00:00Z], slug: &quot;bananas&quot;},
    %{title: &quot;Cherries&quot;, description: &quot;Red fruit&quot;, published_at: ~U[2024-02-27 00:00:00Z], slug: &quot;cherries&quot;}
  ]

  def articles, do: @articles
end
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Controller</h4>
    
    <p>
      All the controller needs to do is render an XML template:
    </p>

    <p><div class="c-text--code--title">Elixir</div>
<pre><code class="c-text--code language-elixir">defmodule Web.RssController do
  use Web, :controller

  def index(conn, _params) do
    render(conn, &quot;index.xml&quot;, articles: Core.Articles.all(), host: conn.host, port: conn.port)
  end
end
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Template</h4>
    
    <p>
      The template needs to include some header information, and then iterate over the articles:
    </p>

    <p><div class="c-text--code--title">XML</div>
<pre><code class="c-text--code language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;rss version=&quot;2.0&quot; xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot;&gt;
  &lt;channel&gt;
    &lt;title&gt;Favorite Fruit&lt;/title&gt;
    &lt;description&gt;A list of fruit&lt;/description&gt;
    &lt;link&gt;https://example.com/&lt;/link&gt;
    &lt;lastBuildDate&gt;&lt;%= pub_date(@articles) %&gt;&lt;/lastBuildDate&gt;
    &lt;pubDate&gt;&lt;%= pub_date(@articles) %&gt;&lt;/pubDate&gt;
    &lt;ttl&gt;1800&lt;/ttl&gt;
    &lt;atom:link href=&quot;https://example.com/rss&quot; rel=&quot;self&quot; type=&quot;application/rss+xml&quot;/&gt;

    &lt;%= for article &lt;- @articles do %&gt;
      &lt;item&gt;
        &lt;title&gt;&lt;%= article.title %&gt;&lt;/title&gt;
        &lt;description&gt;&lt;![CDATA[ &lt;%= article.description %&gt; ]]&gt;&lt;/description&gt;
        &lt;link&gt;&lt;%= &quot;https://example.com/#{article.slug}&quot; %&gt;&lt;/link&gt;
        &lt;guid isPermaLink=&quot;false&quot;&gt;&lt;%= article.slug %&gt;&lt;/guid&gt;
        &lt;pubDate&gt;&lt;%= pub_date(article) %&gt;&lt;/pubDate&gt;
      &lt;/item&gt;
    &lt;% end %&gt;
  &lt;/channel&gt;
&lt;/rss&gt;
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">View</h4>
    
    <p>
      The view needs to implement a couple helper functions for the template.
    </p>
    <p><div class="c-text--code--title">Elixir</div>
<pre><code class="c-text--code language-elixir">defmodule Web.RssView do
  use Web, :view

  def pub_date(nil), do: &quot;&quot;
  def pub_date(articles) when is_list(articles), do: List.first(articles) |&gt; pub_date()
  def pub_date(article), do: format_rfc822(article.published_at)

  def format_rfc822(date_time), do: Calendar.strftime(date_time, &quot;%a, %d %b %Y %H:%M:%S %Z&quot;)
end
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Wrap up</h4>
    
    <p>
      Add a route to your router:
    </p>
    <p><div class="c-text--code--title">Elixir</div>
<pre><code class="c-text--code language-elixir">get &quot;/rss&quot;, Web.RssController, :index</code></pre></p>
    <p>and add a link to the &ldquo;head&rdquo; section of your &ldquo;app.html.heex&rdquo; template:</p>
    <p><div class="c-text--code--title">HEEX</div>
<pre><code class="c-text--code language-xml">&lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; title=&quot;RSS feed for example.com&quot; href=&quot;/rss&quot; &gt;
</code></pre></p>
    <p>and you&rsquo;re all done. Easy to do without having to add an external dependency.</p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>A Doctor To Check Your Development Environment</title>
        <description><![CDATA[ A flexible tool for sharing project configuration and practices among members of a dev team.
 ]]></description>
        <link>https://eahanson.com/articles/doctor</link>
        <guid>https://eahanson.com/articles/doctor</guid>
        <pubDate>Sat, 02 Nov 2019 00:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    
    
    <p>
      Sharing project configuration and practices with a dev team can be tricky. Readme files are nice but
      become outdated quickly. Setup scripts, Docker, Chef, etc., are inflexible and add an extra
      layer of complexity.
    </p>
    <p>
      In between those two extremes is <i>doctor</i>, a script that checks your dev environment and <i>suggests</i>
      remedies to the problems it finds. If you don&rsquo;t like the suggested remedy, you can fix
      the problem some other way.
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      Setting up a project on a new computer is easy: clone the project from source control and then run <i>doctor</i>; it will tell you what your computer is missing (languages, databases, environment variables,
      etc.) and suggest a way to fix each problem.
    </p>
    <p>
      It&rsquo;s also easy to add new checks and commit them along with your code changes, so you can make code changes
      that require development environment changes without worrying about breaking other developers&rsquo;
      environments: <i>doctor</i> just runs the check when the developers update from source control, and then
      suggests a remedy if necessary.
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      <i>
        Most importantly, doctor is an alternative to people hesitating to make changes to code because they
        are worried about breaking other people's development environments.
      </i>
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      Here&rsquo;s a typical doctor session:
    </p>

    <p>
      <div class="c-text--code--title">shell</div>
<pre><code class="c-text--code language-shell">% bin/dev/doctor

[checking] homebrew: bundled?... OK
[checking] direnv: installed... OK
[checking] direnv: .envrc file exists... OK
[checking] asdf: installed... OK
[checking] asdf: erlang plugin installed... OK
[checking] asdf: elixir plugin installed... OK
[checking] asdf: nodejs plugin exists?... OK
[checking] asdf: tools are installed... OK
[checking] deps: elixir deps installed? (needed for yarn to compile)... OK
[checking] yarn: up to date... OK
[checking] phantomjs: installed... OK
[checking] postgres: launchctl script is linked... OK
[checking] postgres: running... OK
[checking] postgres: role exists... FAILED

Possible remedy: createuser -s postgres -U $USER
(it&#39;s in the clipboard)
</code></pre>
    </p>

    <p>
      In my projects, I typically check:
      <ul>
        <li>All the different programming languages are installed and at the right version.</li>
        <li>All the different databases are installed, configured, and running.</li>
        <li>All the necessary system tools are installed.</li>
        <li>All the necessary environment variables are set.</li>
      </ul>
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      I used to write doctor scripts in Bash because it&rsquo;s ubiquitous and typically doesn&rsquo;t require any
      configuration, but recently my business partner and I have built an implementation of doctor plus
      other workflow scripts in Elixir (<a href="https://github.com/synchronal/medic-ex">medic-ex</a>),
      and we are now re-writing it in Rust (<a href="https://github.com/synchronal/medic-rs">medic-rs</a>).
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>Using Scripts To Encode Your Development Process</title>
        <description><![CDATA[ Encode your dev team&apos;s process decisions in committed code.
 ]]></description>
        <link>https://eahanson.com/articles/scripts</link>
        <guid>https://eahanson.com/articles/scripts</guid>
        <pubDate>Fri, 01 Nov 2019 00:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    
    
    <p>
      For the past decade or so, I&rsquo;ve added a group of scripts to every project I&rsquo;ve worked on.
      These scripts started out relatively simple and automate some very common tasks.
      Scroll to the end for some updates.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Why Automate?</h4>
    
    <p>
      Automation encodes the team&rsquo;s decisions in committed code, reducing questions
      (such as &ldquo;do we like to do <code>git pull --rebase</code> or just <code>git pull</code>?&rdquo;)
      and reducing problems caused when people forget to perform a step (such as running tests before pushing code).
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">How To Automate</h4>
    
    <p>
      Because Bash is ubiquitous, I typically write the scripts in Bash.
      Sometimes I write them in a more powerful language if they are complex.
      I personally put them in the <code>bin/dev</code> directory
      (I&rsquo;ll often have a <code>bin/prod</code> directory for performing production actions,
      like <code>bin/prod/</code> or <code>bin/prod/logs</code>).
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Update</h4>
    
    <p>
      The <code>update</code> script is run when the developer wants to get the latest code onto their computer.
      It typically:
    </p>

    <p>
      <ul>
        <li>pulls code from the git remote</li>
        <li>updates dependencies</li>
        <li>runs migrations</li>
        <li>runs <a href="https://eahanson.com/articles/doctor" data-phx-link="redirect" data-phx-link-state="push">doctor</a></li>
      </ul>
    </p>

    <p><div class="c-text--code--title">Bash</div>
<pre><code class="c-text--code language-bash">#!/usr/bin/env bash

set -e

CYAN=&#39;\033[0;36m&#39;
YELLOW=&#39;\033[1;33m&#39;
NC=&#39;\033[0m&#39; # No Color

step() {
  description=$1
  command=$2

  echo -e &quot;\n${CYAN}${description}: ${YELLOW}${command}${NC}&quot;
  eval &quot;${command}&quot;
}

step &quot;Pulling&quot; &quot;git pull --rebase&quot;
step &quot;Updating deps&quot; &quot;MIX_QUIET=true mix deps.get&quot;
step &quot;Migrating&quot; &quot;mix ecto.migrate ecto.dump&quot;

bin/dev/doctor
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Test</h4>
    
    <p>
      The <code>test</code> script runs all the tests.
      A script is useful for this so that everyone runs tests the same way, and so changes to the way the
      team runs tests are automatically shared by everyone.
    </p>

    <p><div class="c-text--code--title">Bash</div>
<pre><code class="c-text--code language-bash">#!/usr/bin/env bash

set -e

CYAN=&#39;\033[0;36m&#39;
YELLOW=&#39;\033[1;33m&#39;
NC=&#39;\033[0m&#39; # No Color

step() {
  description=$1
  command=$2

  echo -e &quot;\n${CYAN}${description}: ${YELLOW}${command}${NC}&quot;
  eval &quot;${command}&quot;
}

step &quot;Running JS tests&quot; &quot;(cd assets &amp;&amp; yarn run mocha)&quot;
step &quot;Running Elixir tests&quot; &quot;mix test --color&quot;
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Shipit</h4>
    
    <p>
      The <code>shipit</code>
      script is run when the developer wants to push code to the git remote. It typically:
      <ul>
        <li>runs the <code>update</code> script</li>
        <li>re-compiles, ideally treating warnings as errors</li>
        <li>runs tests</li>
        <li>pushes to the git remote</li>
      </ul>
    </p>

    <p><div class="c-text--code--title">Bash</div>
<pre><code class="c-text--code language-bash">#!/usr/bin/env bash

set -e

CYAN=&#39;\033[0;36m&#39;
YELLOW=&#39;\033[1;33m&#39;
NC=&#39;\033[0m&#39; # No Color

step() {
  description=$1
  command=$2

  echo -e &quot;\n${CYAN}${description}: ${YELLOW}${command}${NC}&quot;
  eval &quot;${command}&quot;
}

bin/dev/update
step &quot;Recompiling&quot; &quot;mix compile --force --warnings-as-errors || (mix clean &amp;&amp; false)&quot;
bin/dev/test
step &quot;Pushing to git&quot; &quot;git push&quot;
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Start</h4>
    
    <p>
      The <code>start</code> script starts the server or app.
      It&rsquo;s usually not a complicated script but it makes it really easy to remember how to run the project.
    </p>

    <p><div class="c-text--code--title">Bash</div>
<pre><code class="c-text--code language-bash">#!/usr/bin/env bash
iex -S mix phx.server
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Other Scripts</h4>
    
    <p>
      Besides the above scripts which I have in nearly every project,
      I also have other scripts that show up in some of my projects:
    </p>

    <p>
<pre><code class="c-text--code language-shell">bin/
  dev/
    doctor    # ensures the development environment is set up correctly
    format    # formats code for consistent style
    outdated  # checks which dependencies are outdated
    psql      # opens psql with the right database
    shipit    # updates, runs tests, and pushes
    start     # starts the server or app
    test      # runs tests
    update    # updates from git remote, updates dependencies, runs migrations
  prod/
    deploy    # deploys to production, or prints instructions for how to do it
    log       # shows production logs
    restart   # restarts servers
    scale     # adds or removes servers
    shutdown  # stops servers
    ssh       # logs into servers
</code></pre></p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Related Reading</h4>
    
    <div class="c-container--article-list">
  <div class="c-container--article-list--article">
    
    <a href="https://github.blog/2015-06-30-scripts-to-rule-them-all" class="c-container--article-list--link">
  Scripts to Rule Them All
  <div class="c-content--icon c-content--icon--size-s c-content--icon--title-pos-bottom">
  <svg
  xmlns="http://www.w3.org/2000/svg"
  width="24"
  height="24"
  viewBox="0 0 24 24"
  fill="none"
  stroke="currentColor"
  stroke-width="2"
  stroke-linecap="round"
  stroke-linejoin="round"
>
  <path d="M12 6h-6a2 2 0 0 0 -2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-6" />
  <path d="M11 13l9 -9" />
  <path d="M15 4h5v5" />
</svg>
  
</div>
  
</a>
<div class="c-container--article-list--subtitle">
      from the GitHub blog
    </div>
  </div><div class="c-container--article-list--article">
    <a href="https://eahanson.com/articles/doctor" data-phx-link="redirect" data-phx-link-state="push" class="c-container--article-list--link">
  A Doctor To Check Your Development Environment
  
  
</a>
<div class="c-container--article-list--subtitle">
      A flexible tool for sharing project configuration and practices among members of a dev team.

    </div>
    
  </div>
</div>
  
  </div>
</div> ]]></content:encoded>
      </item>
    
      <item>
        <title>The Daily Diff</title>
        <description><![CDATA[ A quick way to regularly expose the entire team to code changes.
 ]]></description>
        <link>https://eahanson.com/articles/diff</link>
        <guid>https://eahanson.com/articles/diff</guid>
        <pubDate>Fri, 13 Sep 2019 00:00:00 GMT</pubDate>
        <content:encoded><![CDATA[ <div class="c-layout--vertical c-layout--vertical--gap-xxl c-layout--vertical--margin-m c-layout--vertical--justify-left">
  <div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Extreme Programming  Practices</h4>
    
    <p>
      I&rsquo;ve been practicing <i>Extreme Programming</i> (XP) for over twenty years.
      It&rsquo;s an agile software development methodology that promotes taking good software practices to the extreme
      in order to provide maximum benefit.
    </p>

    <p>
      For example, we know that writing tests is good; XP developers take testing to the extreme by writing
      tests for everything, and writing tests first. We know that code review is useful; XP developers take
      code review to the extreme by pair programming, which results in instant, continuous code review.
    </p>

    <p>
      Other practices include daily stand-up meetings, weekly planning meetings, continuous integration,
      small releases, collective code ownership, and sustainable pace.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">The Daily Diff</h4>
    
    <p>
      One practice that isn&rsquo;t part of XP but that fits in nicely is the <i>daily diff</i>.
      I was first introduced to it by my friend and former boss Greg Woodward.
      It&rsquo;s a 10-20 minute exercise that is performed daily and familiarizes the team with all the changes happening
      in the codebase. That familiarity is important when practicing collective code ownership. I can&rsquo;t count
      the number of times I&rsquo;ve said while programming, &ldquo;hey, didn&rsquo;t we see something in diff the other day&hellip;&rdquo;
    </p>

    <p>
      I&rsquo;ve practiced daily diff primarily with teams of 6-10 people. With much larger teams, it would presumably
      be very time consuming, and few people would have enough context to understand most of what they were seeing.
      Larger teams are often split into sub-teams; it&rsquo;s probably best for those sub-teams to have their own daily
      diffs.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Step 1: Gather Around A Computer</h4>
    
    <p>
      Each morning, the entire team gathers around a computer. I&rsquo;ve used a few different configurations over the
      years: a 27" iMac connected to a second 27" monitor mirroring the iMac&rsquo;s built-in screen, an iMac connected
      to an 80" 4K TV, and a laptop sharing its screen over Zoom with a bunch of remote developers.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Step 2: Choose A Driver</h4>
    
    <p>
      I&rsquo;ve found it useful to have a different person running diff each day. My favorite way to choose a person
      is to write each person&rsquo;s name on an index card and randomly pick one. The stack of index cards also comes in
      handy for quickly deciding who will kickoff the daily standup meeting, who will lead the weekly
      retrospective meeting, and for choosing pairs for the day by randomly choosing cards in groups of two.
    </p>
  
  </div><div class="c-layout--vertical--item">
    <h4 class="c-layout--vertical--item--title--h4">Step 3: Open The Diff</h4>
    
    <p>
      Daily diff is about looking at all the code that was changed since the last time diff was done
      (usually yesterday). Some diff tools and editors can show a side-by-side diff of multiple commits to see all
      the changes at once. GitHub&rsquo;s web diff can do this, but only shows the changes in each file rather than the
      entire file that was changed. I personally prefer the full-file diffs but GitHub&rsquo;s web diff is simple to use
      and is often good enough.
    </p>

    <p>
      When working on a team that is working on multiple projects at the same time, I diff each project separately.
    </p>
  
  </div><div class="c-layout--vertical--item">
    
    
    <p>
      I have found the daily diff to be a valuable part of my daily software development practice and I
      recommend that everyone try it. Like everything, it might not be a good fit or might need some
      adjustment for your particular situation.
    </p>
  
  </div>
</div> ]]></content:encoded>
      </item>
    

  </channel>
</rss>
