<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>jezenthomas.com</title>
        <link>https://jezenthomas.com</link>
        <description><![CDATA[Thoughts on Haskell, Business, Unix, and more.]]></description>
        <atom:link href="https://jezenthomas.com/feed.xml" rel="self"
                   type="application/rss+xml" />
        <lastBuildDate>Sun, 07 Jun 2026 00:00:00 UT</lastBuildDate>
        <item>
    <title>NewBusinessMonitor is Closed</title>
    <link>https://jezenthomas.com/2026/06/new-business-monitor-and-company-query-are-closed/</link>
    <description><![CDATA[<p>If you’ve landed here, you were probably looking for NewBusinessMonitor
(<code>newbusinessmonitor.co.uk</code>) or its later incarnation, CompanyQuery
(<code>companyquery.co.uk</code>). Both are now closed, and the old addresses redirect to
this page.</p>
<p>For a few years I ran these as a hobby business. The original idea was simple:
let people search for UK companies within a given radius of a postcode. From
there it grew to let you filter by SIC code, by company status — active,
dissolved, and so on — and the whole dataset was kept up to date in real time
as new companies were registered and existing ones changed. People used it for
sales prospecting, for research, and for keeping an eye on particular corners
of the market.</p>
<p>I enjoyed building it, and it taught me a lot about working with company data
at scale. But it was always a side project, and my attention is needed
elsewhere. Rather than let it limp along half-maintained, I’d rather close it
cleanly.</p>
<p>So that’s that. Thank you to everyone who used it over the years.</p>
<h2 id="if-you-need-this-kind-of-thing">If you need this kind of thing</h2>
<p>The product is gone, but the expertise isn’t. If you need custom software built
— particularly anything involving UK company data, Companies House, or turning
a messy public dataset into something fast and searchable, I may be able to
help.</p>
<p>Email me at <a href="mailto:jezen@jezenthomas.com">jezen@jezenthomas.com</a> for a virtual
coffee and software chat.</p>
]]></description>
    <pubDate>Sun, 07 Jun 2026 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2026/06/new-business-monitor-and-company-query-are-closed/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>When Test Coverage Isn't Enough</title>
    <link>https://jezenthomas.com/2025/05/when-test-coverage-is-not-enough/</link>
    <description><![CDATA[<p>Robert Roskam made a point on social media about the inadequacy of test
coverage.</p>
<blockquote>
<p>100% test coverage is not enough. Here’s an example as to why in Python:</p>
<div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">division</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
 <span class="k">return</span> <span class="n">x</span> <span class="o">/</span> <span class="n">y</span>
</pre></div>

<p>If you pass in <code>0</code> for <code>y</code>, it’ll raise an error. You have to know to test for
the value specifically. Test coverage won’t save you here. With 100% line
coverage or branch coverages, it won’t be found. That’s how 100% test
coverage is not enough.</p>
</blockquote>
<p>So, if test coverage is not enough, what can we do here?</p>
<p>Well, at least a couple of things.</p>
<h2 id="surfacing-failure-cases-automatically">Surfacing Failure Cases Automatically</h2>
<p>It wouldn’t be sensible to try testing our division function against every
possible input, because the set of possible inputs is effectively unbounded.
Fortunately, we don’t have to. We can instead use a property-based testing
library like <a href="https://hackage.haskell.org/package/hedgehog">hedgehog</a> to generate inputs to our division function and show
us the minimal way to reproduce an error when it occurs.</p>
<p>This example is in Haskell, and only accounts for integral numbers. Otherwise,
it’s a near enough direct translation of the Python version.</p>
<div class="highlight"><pre><span></span><span class="kr">import</span><span class="w"> </span><span class="nn">Hedgehog</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Hedgehog.Gen</span><span class="w"> </span><span class="n">qualified</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">Gen</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Hedgehog.Range</span><span class="w"> </span><span class="n">qualified</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">Range</span>

<span class="nf">division</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">`</span><span class="n">div</span><span class="p">`</span><span class="w"> </span><span class="n">y</span>

<span class="nf">prop_division_identity</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">property</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="w">  </span><span class="n">x</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">forAll</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kt">Gen</span><span class="o">.</span><span class="n">int</span><span class="w"> </span><span class="kt">Range</span><span class="o">.</span><span class="n">linearBounded</span>
<span class="w">  </span><span class="n">y</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">forAll</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kt">Gen</span><span class="o">.</span><span class="n">int</span><span class="w"> </span><span class="kt">Range</span><span class="o">.</span><span class="n">linearBounded</span>
<span class="w">  </span><span class="kr">let</span><span class="w"> </span><span class="n">q</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">division</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="c1">-- quotient</span>
<span class="w">      </span><span class="n">r</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">`</span><span class="n">mod</span><span class="p">`</span><span class="w"> </span><span class="n">y</span><span class="w">    </span><span class="c1">-- remainder</span>
<span class="w">  </span><span class="n">q</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="n">x</span>
</pre></div>

<p>We’re relying on the <strong>integer division law</strong> to test our function.</p>
<p>The integer division law says:</p>
<blockquote>
<p>When you divide one whole number by another, you get a <strong>quotient</strong> and a
<strong>remainder</strong>. If you multiply the quotient by the divisor, then add the
remainder, you get back the original number.</p>
</blockquote>
<p>This law holds for <code>divisor ≠ 0</code>.</p>
<p>So, the test generates a range of integers, applies the division function to
them, and checks that the result always adheres to the integer division law.</p>
<p>Running this in GHCi quickly surfaces the problem.</p>
<div class="highlight"><pre><span></span>━━━ Main ━━━
  ✗ prop_division_identity failed at div.hs:15:13
    after 1 test.
    shrink path: 1:

       ┏━━ div.hs ━━━
    10 ┃ prop_division_identity = property $ do
    11 ┃   x &lt;- forAll $ Gen.int Range.linearBounded
       ┃   │ 0
    12 ┃   y &lt;- forAll $ Gen.int Range.linearBounded
       ┃   │ 0
    13 ┃   let q = division x y -- quotient
    14 ┃       r = x `mod` y    -- remainder
    15 ┃   q * y + r === x
       ┃   ^^^^^^^^^^^^^^^
       ┃   │ ━━━ Exception (ArithException) ━━━
       ┃   │ divide by zero
</pre></div>

<p>In this case, we didn’t have to explicitly check what happens when the divisor
is zero.</p>
<p>Furthermore — and perhaps more importantly — writing this test has forced us to
<em>think</em> about both the types of the inputs and the range of those inputs. I
didn’t want to have to specify the upper and lower bounds for the range of
inputs, but not all numeric types have explicit bounds. That led me to choose
to constrain my <code>division</code> function to only support integers.</p>
<p>We can see that limitation directly in GHCi.</p>
<div class="highlight"><pre><span></span>λ minBound :: Int
-9223372036854775808

λ minBound :: Float

&lt;interactive&gt;:49:1: error: [GHC-39999]
    • No instance for ‘Bounded Float’ arising from a use of ‘minBound’
    • In the expression: minBound :: Float
      In an equation for ‘it’: it = minBound :: Float
</pre></div>

<p>This also guides us towards thinking about edge cases. If we have to consider
division on floating point numbers, then the obvious challenge is going to be
in specifying to what degree of precision we expect to see in our results. We
would then have to change the assertion in the test so that it accepts a result
to a specific acceptable degree of accuracy.</p>
<p>Again, the test encourages us to <em>think</em>, which in turn leads to better
design. That’s true whether you’re writing a small function like <code>division</code>, or
a larger, integrated path through your system. This is why TDD is often thought
of as Test Driven <strong>Design</strong>, rather than just Test Driven Development.</p>
<h2 id="making-failure-impossible">Making Failure Impossible</h2>
<p>Now that we’ve surfaced the error, how do we design our function to make this
kind of failure impossible?</p>
<p>One common approach is to express the failure case in the output. This
typically means wrapping the output in a Maybe to represent that the result may
not exist.</p>
<div class="highlight"><pre><span></span><span class="nf">division</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Int</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">Int</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">Maybe</span><span class="w"> </span><span class="kt">Int</span>
<span class="nf">division</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">Nothing</span>
<span class="nf">division</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">Just</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="p">`</span><span class="n">div</span><span class="p">`</span><span class="w"> </span><span class="n">y</span><span class="p">)</span>
</pre></div>

<p>This works, but it necessarily implies that the caller of this code will have
to handle the possibility of failure. This change will then ripple through the
rest of the codebase, which is noise that you probably don’t need.</p>
<p>Alternatively, you can use the <a href="https://kowainik.github.io/posts/haskell-mini-patterns">smart constructor</a> pattern to constrain the
<em>input</em> and have the changes ripple back towards the boundary of your system,
which is usually a better design choice. In the case of our <code>division</code>
function, this would mean ensuring at compile time that the function will only
accept a non-zero divisor.</p>
<div class="highlight"><pre><span></span><span class="nf">division</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Int</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">NonZero</span><span class="w"> </span><span class="kt">Int</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">Int</span>
<span class="nf">division</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">(</span><span class="kt">NonZero</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">`</span><span class="n">div</span><span class="p">`</span><span class="w"> </span><span class="n">y</span>
</pre></div>

<p>Finally, we could of course <a href="https://www.hillelwayne.com/post/divide-by-zero/">return zero in case of failure</a>. Which of these
options is the right one is debatable, but the point is that both the tests and
the types have driven us to think about the design of our system.</p>
]]></description>
    <pubDate>Fri, 23 May 2025 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2025/05/when-test-coverage-is-not-enough/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>Test Spies in Haskell</title>
    <link>https://jezenthomas.com/2025/04/test-spies-in-haskell/</link>
    <description><![CDATA[<p>When testing a web application, you often want to make sure that a certain
email <em>would</em> be sent — without actually sending it. How do you test that?</p>
<p>Take something like a transactional email: a user signs up, resets their
password, or completes a purchase — and your application needs to send a
notification. You don’t care how the email gets sent — just that it was
triggered correctly.</p>
<p>The simplest implementation for the email-sending function might look like this.</p>
<div class="highlight"><pre><span></span><span class="nf">sendEmail</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Recipient</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">IO</span><span class="w"> </span><span class="nb">()</span>
<span class="nf">sendEmail</span><span class="w"> </span><span class="n">recipient</span><span class="w"> </span><span class="ow">=</span>
<span class="w">  </span><span class="c1">-- some email sending code here…</span>
</pre></div>

<p>All this function needs to know is where to send the email. How it sends it
isn’t important here — and it’s not what we’re testing. What we care about is
how it’s called.</p>
<p>This function might be called from a request handler, and it would be that
handler function’s responsibility to decide how to call the email sending
function.</p>
<div class="highlight"><pre><span></span><span class="nf">postThingR</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Handler</span><span class="w"> </span><span class="nb">()</span>
<span class="nf">postThingR</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">do</span>
<span class="w">  </span><span class="n">liftIO</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">sendEmail</span><span class="w"> </span><span class="s">&quot;user@example.com&quot;</span>
</pre></div>

<p>We can track how a function is called with a <a href="https://martinfowler.com/bliki/TestDouble.html"><em>test spy</em></a>.</p>
<blockquote>
<p>Spies are stubs that also record some information based on how they were called.</p>
</blockquote>
<p>You can emulate a test spy using the same <a href="/2023/11/stubbing-io-in-yesod/">stubbing method</a> I wrote about
earlier. Instead of calling <code>sendEmail</code> directly, you’ll retrieve it from
somewhere that can be swapped out at runtime — like your application’s
settings.</p>
<div class="highlight"><pre><span></span><span class="nf">postThingR</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Handler</span><span class="w"> </span><span class="nb">()</span>
<span class="nf">postThingR</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">do</span>
<span class="w">  </span><span class="n">sendEmail</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">getsYesod</span><span class="w"> </span><span class="n">appSendEmail</span>
<span class="w">  </span><span class="n">liftIO</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">sendEmail</span><span class="w"> </span><span class="s">&quot;user@example.com&quot;</span>
</pre></div>

<p>The idea is to swap the implementation for one that records the arguments that
the function was called with, and then check what was recorded in the test’s
assertion phase. We can use mutable state — such as an <code>IORef</code> or <code>TVar</code> — to
record how the function was called. Here, we’ll keep it simple with <code>IORef</code>.</p>
<div class="highlight"><pre><span></span><span class="nf">it</span><span class="w"> </span><span class="s">&quot;notifies the right person&quot;</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>

<span class="w">  </span><span class="c1">-- Arrange</span>
<span class="w">  </span><span class="n">callsRef</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">liftIO</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">newIORef</span><span class="w"> </span><span class="kt">[]</span>
<span class="w">  </span><span class="n">stub</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="nf">\</span><span class="n">app</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="n">app</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="n">appSendEmail</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">\</span><span class="n">recipient</span><span class="w"> </span><span class="ow">-&gt;</span>
<span class="w">      </span><span class="n">liftIO</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">modifyIORef&#39;</span><span class="w"> </span><span class="n">callsRef</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="nf">\</span><span class="n">cs</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="n">recipient</span><span class="w"> </span><span class="kt">:</span><span class="w"> </span><span class="n">cs</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">  </span><span class="c1">-- Act</span>
<span class="w">  </span><span class="n">post</span><span class="w"> </span><span class="kt">ThingR</span>

<span class="w">  </span><span class="c1">-- Assert</span>
<span class="w">  </span><span class="n">liftIO</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="w">    </span><span class="n">calls</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">readIORef</span><span class="w"> </span><span class="n">callsRef</span>
<span class="w">    </span><span class="n">calls</span><span class="w"> </span><span class="p">`</span><span class="n">shouldBe</span><span class="p">`</span><span class="w"> </span><span class="p">[</span><span class="s">&quot;user@example.com&quot;</span><span class="p">]</span>
</pre></div>

<p>This test swaps in a fake email function, triggers the handler, and checks that
the expected recipient was recorded.</p>
<p>With this pattern, you can test side effects without relying on real services —
making your tests fast, isolated, and reliable.</p>
]]></description>
    <pubDate>Fri, 18 Apr 2025 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2025/04/test-spies-in-haskell/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>A 10x Speedup in GHCi</title>
    <link>https://jezenthomas.com/2025/03/10x-speedup-in-ghci/</link>
    <description><![CDATA[<p>Many of us at Supercede use GHCi directly when developing Haskell projects. It
runs the local development server, and the automated test suite, and serves as
a scratch pad for ad hoc expression evaluation and type inspection.</p>
<p>We make heavy use of integrated tests with the yesod-test framework.</p>
<p>One of our projects now has more than 500 tests.</p>
<p>Running the tests in GHCi takes about 150 seconds. Not terrible, but not great
either. Certainly not fast enough to encourage developers to practice TDD and
run the entire suite regularly.</p>
<div class="highlight"><pre><span></span>Finished in 150.2305 seconds
508 examples, 0 failures, 3 pending
</pre></div>

<p>However, running the same test suite with <code>cabal test</code><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> takes only about
12 seconds.</p>
<p>That’s a significant improvement!</p>
<div class="highlight"><pre><span></span>Finished in 11.7001 seconds
508 examples, 0 failures, 3 pending
</pre></div>

<p>As it turns out, the difference is in concurrency in the runtime system. The
project’s cabal file includes some GHC options which enable multi-core
parallelism and allows the program to run with all available CPU cores.</p>
<div class="highlight"><pre><span></span>test-suite test
  type:               exitcode-stdio-1.0
  main-is:            Main.hs
  hs-source-dirs:     test
  ghc-options:
    -threaded -rtsopts -with-rtsopts=-N
    -- there are more options here, but they&#39;re unrelated
</pre></div>

<p>So the test suite runs slowly in GHCi, because the tests are running on a
single thread. It’s possible to start GHCi with multi-core parallelism by
running <code>ghci +RTS -N</code> from the shell, but this is fiddly to write, and I don’t
think writing a shell alias is the right thing to do. The project’s development
environment should <em>just work</em> for everyone who contributes to the project, and
they shouldn’t need to create shell aliases or tinker with these inputs in
order to enjoy the improved performance.</p>
<p>Fortunately, it’s possible to change RTS settings at runtime, so I’ve added
these lines to end of the project’s <code>.ghci</code> file.</p>
<div class="highlight"><pre><span></span><span class="kr">import</span><span class="w"> </span><span class="nn">GHC.Conc</span>
<span class="nf">n</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">getNumProcessors</span>
<span class="nf">setNumCapabilities</span><span class="w"> </span><span class="p">(</span><span class="n">max</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="n">n</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">))</span>
</pre></div>

<p>First we use <code>getNumProcessors</code> to get the number of CPUs the machine has,
and then we set the number of Haskell threads that can run simultaneously.
As recommended in <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Control-Concurrent.html#v:setNumCapabilities">the documentation</a>, we leave a core free to avoid
contention with other processes.</p>
<p>Running the same test suite in GHCi with this RTS configuration takes ~12-20
seconds, which is on average about a 10x improvement. There will also be some
differences with GHCi interpreting rather than compiling code, but I think at
this scale the difference is insignificant.</p>
<p>While this isn’t related to parallelism, the last thing we do in our <code>.ghci</code>
file is to enable the display of timing and memory stats, plus the inferred
type of the variable bound for each statement.</p>
<div class="highlight"><pre><span></span>:set +s +t
</pre></div>

<p>We do this last, because otherwise when entering GHCi we’ll see timing and
memory stats for every comment written in the <code>.ghci</code> file, <em>i.e.</em>,
several lines like this:</p>
<div class="highlight"><pre><span></span>(0.00 secs, 0 bytes)
(0.00 secs, 0 bytes)
(0.00 secs, 0 bytes)
(0.00 secs, 0 bytes)
(0.00 secs, 0 bytes)
(0.00 secs, 0 bytes)
</pre></div>

<hr />
<p>One fairly obvious way to not have to think about any of this would be to use
<code>cabal repl</code> which is essentially a managed way to launch GHCi, though that
comes with its own configuration concerns. I like the quick startup time of
GHCi, and I like having a deeper understanding of what the interpreter is or
isn’t doing.</p>
<p>I’ve been happily using GHCi for the past decade, and I’m not currently
convinced that adding a wrapper around the interpreter would make my
development workflow any simpler. There is an argument to be made for cabal’s
dependency resolution, but I’m using Nix to manage packages anyway.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>We actually run our checks with <code>nix flake check -L</code>, but this uses cabal under the hood.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]></description>
    <pubDate>Fri, 07 Mar 2025 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2025/03/10x-speedup-in-ghci/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>HTTP Verbs in Yesod Forms</title>
    <link>https://jezenthomas.com/2025/02/http-verbs-yesod-forms/</link>
    <description><![CDATA[<p>The main function provided by the yesod-form library for processing form
submissions is <a href="https://hackage.haskell.org/package/yesod-form-1.7.9/docs/Yesod-Form-Functions.html#v:runFormPost"><code>runFormPost</code></a>.</p>
<p>As the name implies, this function processes <code>POST</code> requests. But what if you
want to use a different verb, like <code>PUT</code>? The library is a little confusing in
this way, because the <em>post</em> in <code>runFormPost</code> doesn’t actually refer to the HTTP
method that triggered the execution of the handler code.</p>
<p>The point of <code>runFormPost</code> is actually just about running the parser against the
request <em>body</em>, rather than the query string as would happen with <code>runFormGet</code>.</p>
<p>Conceptually, this makes some sense as a design decision when you remember that
web browsers natively only support <code>GET</code> and <code>POST</code> as values of the <code>method</code>
attribute in HTML forms. The difference between those two values is perfectly
reflected in the design of the library — the values in the form are transferred
in either the query string or the request body respectively.</p>
<p>While HTML forms only support <code>GET</code> and <code>POST</code> natively, a typical Yesod
project will also support <a href="https://hackage.haskell.org/package/wai-extra#:~:text=Allows%20overriding%20of%20the%20HTTP%20request%20method%20via%20the%20_method%20query%20string%20parameter">request method overriding</a>, by applying a value
for the <code>_method</code> parameter in the query string.</p>
<p>In Hamlet, this looks something like this.</p>
<div class="highlight"><pre><span></span>&lt;form  method=post action=@?{(ExampleR, [(&quot;_method&quot;, &quot;PUT&quot;)])}&gt;
</pre></div>

<p>This form submission would then be routed to the appropriate handler.</p>
<div class="highlight"><pre><span></span><span class="nf">putExampleR</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Handler</span><span class="w"> </span><span class="kt">Html</span>
<span class="nf">putExampleR</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">do</span>
<span class="w">  </span><span class="p">((</span><span class="n">result</span><span class="p">,</span><span class="w"> </span><span class="n">form</span><span class="p">),</span><span class="w"> </span><span class="n">enctype</span><span class="p">)</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">runFormPost</span><span class="w"> </span><span class="n">exampleForm</span>
<span class="w">  </span><span class="c1">-- …</span>
</pre></div>

<p>So, the browser sends a <code>POST</code> request, but the application actually interprets
this as a <code>PUT</code> request and routes it to the appropriate handler. We then process
the form in that handler with <code>runFormPost</code>, because the data is still
transferred in the request body.</p>
]]></description>
    <pubDate>Sat, 22 Feb 2025 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2025/02/http-verbs-yesod-forms/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>My Technological Regrets</title>
    <link>https://jezenthomas.com/2025/01/my-technological-regrets/</link>
    <description><![CDATA[<p>After several years working on Supercede, I’ve had time to reflect on some of
the technical choices we made. Some of them worked well, others I’d approach
differently if I were starting again. Here’s what I regret, and why.</p>
<h2 id="elm-was-the-wrong-choice-for-our-ui">Elm Was the Wrong Choice for Our UI</h2>
<p>When I started working on Supercede, I had the idea that any more complex parts
of the UI should be written in Elm, rather than with React or perhaps just
managing all DOM interaction manually with plain JavaScript.</p>
<p>If you need to write in a Single Page Application (SPA) style, I think Elm is
probably the best possible choice. I would absolutely choose Elm if I were
writing a greenfield SPA today.</p>
<p>It doesn’t matter that Elm doesn’t have typeclasses, and it doesn’t matter that
Elm doesn’t have the same kind of churn that the rest of the JavaScript world
has come to expect. These are both features. I’m familiar with some of the
criticisms levelled at Elm, but chief, <a href="https://reasonablypolymorphic.com/blog/elm-is-wrong/">this ain’t it</a>.</p>
<p>The reasons why I have come to regret Elm are not inherent to Elm itself. The
problems are in product design, and what that necessarily implies about the
system design. As it turns out, Supercede just doesn’t [currently] need any of
the user interface written in SPA style. This is enterprise software for
reinsurance professionals. Most of the interactivity should be modelled with
server-rendered web forms. Kind of like how web applications were written 20
years ago.</p>
<p>If you design your application as a backend which serves some JSON and a SPA
which consumes and operates on that data, you have two separate systems. To
marshal values as they flow between the boundaries of those two systems, you
need to somehow manage the synchronisation of the types of those values on both
sides (and that’s true also of dynamically-typed languages), and you need to
manage how those values serialise and deserialise, and you probably need to
duplicate some of the business logic and parsing/validation logic. You might —
as we did at Supercede — introduce a code generation mechanism which runs as
part of your build step and enforces that all of these things remain
synchronised. But this is more code to compile. More to maintain. More to
document. More to constantly be aware of. It doesn’t come for free.</p>
<p>Alternatively, you could choose to not have these problems by designing your
product in a different way. This sounds like a constraint, and it is. But
that’s a good thing! Design is all about constraints. Constraints liberate. If
you can’t design within constraints, then you’re just a bad designer.</p>
<h2 id="event-sourcing-added-complexity-we-didnt-need">Event Sourcing Added Complexity We Didn’t Need</h2>
<p>We knew from the beginning that auditability would be an important property of
our system. Event sourcing — where the current state of the system is derived
by replaying a chronological sequence of events — seems an obvious choice for
this.</p>
<p>The problem is that event sourcing is <em>hard</em>.</p>
<p>Sure, it’s not insurmountably hard. You can quickly gain a conceptual intuition
for how event sourcing should work when it’s explained to you, and you can
readily draw parallels to other systems which work more or less the same way,
like distributed version control, or your bank account.</p>
<p>But the complexity of designing and maintaining an event sourced system doesn’t
come for free. It’s not even cheap. When you want to introduce a change to the
system, you need to think much harder about threading that change through each
component of the event sourcing system. You need to think harder about when
effects happen. Should running a projection also send transactional email?
Probably not. Other effects? Hard to say.</p>
<p>You can learn the theory. You can learn the skills. But it’s <em>probably</em> too
much to take on for a startup when they’re still trying to find product/market
fit. Your time is better spent building features that paying customers actually
care about. And most customers — especially for a product like Supercede —
really care about auditability. But they <em>don’t</em> care whether that auditability
is implemented with event sourcing, and not, say, some audit tables.</p>
<p>There are cases where event sourcing is absolutely the right approach, and
should be coupled with deeper measures of integrity like <a href="https://en.wikipedia.org/wiki/Write_once_read_many">WORM drives</a>, but
those cases are less common than the software conference circuit might have you
believe. Much like microservices, I suppose.</p>
<h2 id="over-reliance-on-postgresql-slowed-development">Over-Reliance on PostgreSQL Slowed Development</h2>
<p>This regret isn’t about PostgreSQL per se. It’s more about tightly coupling to
database-specific implementation details, and the consequences of such a
coupling.</p>
<p>One of the consequences is slower test execution. Most of Supercede’s test code
is written in an integrated style using the yesod-test library. Between each
test, we create a new application state and reset the database so that
individual tests do not affect the execution environment of other tests.
Truncations are slow in PostgreSQL, and for some specific design reasons it’s
not really feasible to wrap each test in a transaction which is rolled back at
the end<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>. We have other projects which use the same libraries but instead
run tests against an in-memory SQLite database, which works great and runs
quickly.</p>
<p>Depending on features specific to PostgreSQL also means you need to run a real
database server in your continuous integration setup. It’s more to install, and
you need to run it all in a virtual machine. It’s just more <em>stuff</em>. And stuff
is a liability.</p>
<p>For most of the more generic database work, I would prefer to abstract away the
details of the database with libraries like persistent and esqueleto. There
might be parts of the application that necessarily rely on specific database
features, but I think those parts should be extracted or in some way isolated,
perhaps even so they can be stubbed in the general case.</p>
<h2 id="lenses">Lenses</h2>
<p>Lenses are brilliant, and for any new non-trivial Elm project, I would likely
reach for a lens library like <a href="https://package.elm-lang.org/packages/arturopala/elm-monocle/latest/">elm-monocle</a>. But that’s because I think Elm
projects — at least in my experience — tend towards keeping all state in one
foundational data structure which will necessarily become complex as the
project grows.</p>
<p>Your foundational data structure — your <code>Model</code> — is not some peripheral detail
that you interact with only occasionally. Because it’s so central, you work
with it constantly and so the mental model for manipulating that data structure
with lenses becomes rudimentary, rather than a novel curiosity.</p>
<p>Lenses are so worth it if you have this design and the ergonomics constraints
it brings.</p>
<p>But if you don’t? I don’t think it’s worth it.</p>
<p>Lenses in Haskell read <em>quite</em> differently from more conventionally written
Haskell code. So much so, that while being ordinary Haskell, you could almost
consider them a domain specific language.</p>
<p>Working with lenses and maintaining a flow state requires familiarity, which I
don’t think you can establish if you only flirt with lenses by lightly dusting
it around the periphery of your project.</p>
<p>At Supercede, we haven’t gone <em>all-in</em> on lenses. Some engineers have made the
choice to lightly dust lenses on the periphery. Those parts now cause visible
lines in the skin of programmers’ faces any time that programmer is forced to
read and understand what we’ve written.</p>
<p>So, I regret our lens adoption. In hindsight, it seems gratuitous. Perhaps we
indulged in whether or not some code <em>could</em> be written in terms of lenses,
while neglecting to consider whether or not that code <em>should</em> be written that
way.</p>
<h2 id="bem-naming-conventions-stifled-thoughtful-design">BEM Naming Conventions Stifled Thoughtful Design</h2>
<p>It’s tough, balancing <a href="https://en.wikipedia.org/wiki/Not_invented_here#:~:text=Not%20invented%20here%20(NIH)%20is,against%20ideas%20from%20the%20outside."><em>Not Invented Here</em></a> syndrome with first principles
thinking. It’s not economically sensible to reinvent every wheel, nor is it
sustainable to surrender to the learned helplessness of <em>best practice</em>, which
is itself a form of <a href="https://simple.wikipedia.org/wiki/Appeal_to_tradition#:~:text=Appeal%20to%20tradition%20(also%20known,always%20done%20it%20this%20way%22.">fallacious reasoning</a>.</p>
<p>The <a href="https://getbem.com">Block Element Modifier</a> naming convention is one such <em>best practice</em>.
I regret allowing it to creep in to our codebase because I think it allowed
some developers to try to absolve themselves of the kind of thinking required
to come up with meaningful names for things. Communicating intent through clear
writing is one of the most important parts of the job.</p>
<p>The use of BEM has also made us stop thinking about how the problem of CSS
selector scoping could otherwise be solved. The BEM naming convention could
certainly be the right choice in some tech stacks, but in our Yesod project we
have better tools! We generate unique identifiers for components at runtime,
with some components being comprised of smaller components. This of course
isn’t exclusive to Yesod — other ecosystems solve this problem differently. But
the point is that this problem <em>can</em> be solved differently, and to ignore that
for the sake of <em>best practice</em> is folly.</p>
<h2 id="we-abstracted-too-early-and-it-cost-us">We Abstracted Too Early, and It Cost Us</h2>
<p>Haskell is a high level programming language. Almost all of the code we write
describes what we wish to achieve, and not specifically <em>how</em> the runtime
should achieve it. So, premature optimisation is not really a problem we’ve
faced historically. At least, not in terms of algorithmic efficiency. Instead,
the premature optimisation that we have at times fallen afoul of is abstracting
too early, and abstracting the wrong things.</p>
<p>The worst offences here typically look like functions which are highly
configurable, but don’t really <em>do</em> anything particularly interesting. For
example, extracting a user interface component library, so that all the buttons
in your UI look the same. But in some places, the button should be a different
colour, so you make that a configuration option. And then in some places, the
button should be a different size, so you make that a configuration option. And
then in some places, the button…</p>
<p>You get the idea.</p>
<p>A function that requires a load of configuration in order for it to understand
how it’s meant to behave is probably a code smell. Instead of one highly
configurable function, we could have written a few different functions. Or, we
could have written a few different CSS mixins and composed those together.</p>
<h2 id="haskells-type-system-isnt-a-substitute-for-good-tests">Haskell’s Type System Isn’t a Substitute for Good Tests</h2>
<p>Haskell’s type system is <em>brilliant</em>.</p>
<p>The type system obviates the need to write so many of the more onerous tests
that we would have had to write and maintain if we were writing our project in
something like Ruby or Python. Tests that assert the shapes of data structures,
or that functions are called with the right arguments — that kind of thing.</p>
<p>But ensuring that a SQL query doesn’t throw an exception at runtime? We still
need tests for that. Or documenting and automatically verifying the expected
behaviour of a path through the system? We still need tests for that. There are
many more examples to list, but this list isn’t meant to be exhaustive.</p>
<p>Despite being able to leverage a tool as powerful as the [Glorious] Glasgow
Haskell Compiler, I’m still seeing a huge amount of value in using automated
tests to drive out the design of the system. This shouldn’t really be
surprising either — types and tests are different things and serve different
purposes.</p>
<p>In parts of our project where the test suite is well written, I’m seeing that
it continues to be well written as my colleagues write more production code.
This might come from a kind of social pressure — conscientious developers
generally want to leave a project in a better state than they found it. If a
test suite is well written, it just <em>feels</em> bad to make a change that leaves
the test suite relatively less comprehensive.</p>
<p>So, my regret here is in not investing enough in establishing a culture of
test-driven design. And I don’t just mean we haven’t written <em>enough</em> tests.
There’s an art to writing test code, since its purpose isn’t purely to prevent
regressions. If we had a better cultural awareness of how to use automated
tests to drive out the design of our system, we’d almost certainly have a
better production codebase for it. We do have this culture at least partially
established in our team, but it’s harder to add this after the fact. And
because the existing test code isn’t always ideal, the path of least resistance
isn’t to write ideal test code, and the relative growth of good test code
against new production code isn’t self-perpetuating.</p>
<p>In other words, it takes more effort now to get to where we want to be with our
test code than if we had done this up front.</p>
<h2 id="slow-ci-kills-productivity">Slow CI Kills Productivity</h2>
<p>Programmers have a kind of adversarial relationship with continuous integration
systems. It’s a healthy conflict though — the whole point is to ensure that the
changes you make are sound.</p>
<p>As you work, you push changes and your CI system runs an assortment of checks
against them. You might be otherwise happy with your contribution and all of
your automated tests are passing during local development, but then the CI
system flags that you neglected to add a migration. Or that the code fails some
linting rules, or that while your code works just fine on the compiler version
or system architecture that you are running locally, it fails on other compiler
versions or system architectures that you also need to support.</p>
<p>So, the build on CI is failing. You make another change, push that change, and
wait again for CI to pass or fail. Another failure. Make more changes. Push
again. Wait.</p>
<p>This style of working is of course fine, but if CI is slow, it means your
iteration cycle is slow. And a slow iteration cycle easily distracts
programmers and kills motivation. Scaling this lack of efficiency up to a team
of people means the company isn’t shipping software as fast as it should.</p>
<p>In hindsight, I should have invested more effort into keeping tests fast and
build times short. The compound productivity gains from this just make economic
sense.</p>
<h2 id="lessons-learned">Lessons Learned</h2>
<p>Looking back, the choices we made were [usually] generally well-motivated. If I
were starting Supercede today however, I would take a firmer stand against
over-engineering, and I would be more conservative — not just in the number of
tools and libraries we depend on, but also in how much of any given language we
use. Haskell is a great language, but we don’t need to use <em>all</em> of it.</p>
<p>This retrospective has also reaffirmed to me how important test-driven design
is as a way to approach software development. I learned all about it a decade
ago, forgot it, and then had to relearn — painfully — why TDD matters.</p>
<p>Finally, I don’t regret for a minute any of the time I spent learning about
<a href="https://en.wikipedia.org/wiki/List_of_fallacies">logical fallacies</a>. Software engineering as an industry is <em>rampant</em> with
fallacious reasoning, and often it’s enough to recognise fallacious reasoning
when it’s being employed in order to not fall prey to it.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Or maybe there <em>is</em> a way to do this, and I just haven’t figured out how yet.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]></description>
    <pubDate>Thu, 30 Jan 2025 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2025/01/my-technological-regrets/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>Supercede's House Style for Haskell</title>
    <link>https://jezenthomas.com/2025/01/style-guide/</link>
    <description><![CDATA[<p>Over the years, a house style has emerged for all the Haskell code we write at
Supercede. We expect all new code to generally follow this style, and since
style pertains to more than just the language itself, this style guide will
touch on some aspects of the Yesod ecosystem and software design more broadly.</p>
<h2 id="philosophy">Philosophy</h2>
<p>Style is taste, and taste is subjective<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p>
<p>There isn’t one right way to write Haskell code, which is why I format most
Haskell code manually. I might use <a href="https://github.com/godlygeek/tabular">tabular</a> to align some record
fields or case matches, and I always use <a href="https://github.com/haskell/stylish-haskell">stylish-haskell</a> to neatly
sort and align language extensions and module imports. But beyond that, it’s
manual.</p>
<p>Good Haskell code tends to use a kind of visual shape to improve readability.
Carelessly written code will just <em>look</em> haphazard. This is why you need to use
your eyes. The other programmers who work with the code you write will also be
using their eyes.</p>
<p>Avoid the kind of learned helplessness where you decide that since style is
subjective, you couldn’t possibly individually determine whether your code is
neat and tidy, and therefore <em>must</em> use one of the more invasive code
formatters like Ormolu. Use your eyes. Develop some taste.</p>
<p>And while it’s good to develop an opinion on style, be cool with it. Don’t go
too far the other way and decide your sense of style is absolutely superior and
then start reformatting everyone else’s code as soon as you see it.</p>
<p>Be intentional with the changes you make.</p>
<p>Write code with care, but don’t be precious.</p>
<h2 id="whitespace">Whitespace</h2>
<p>In general, indent code with 2 spaces.</p>
<p>Sometimes you may wish to use 3 spaces, as in cases like this. This is fine.</p>
<div class="highlight"><pre><span></span><span class="nf">someFunction</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span>
<span class="w">  </span><span class="kr">let</span><span class="w"> </span><span class="n">h</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="o">.</span><span class="w"> </span><span class="n">f</span>
<span class="w">   </span><span class="kr">in</span><span class="w"> </span><span class="n">h</span><span class="w"> </span><span class="n">x</span>
</pre></div>

<p>Separate functions with a blank line. Separate language extensions from the
module header with a blank line. Sometimes it can be clearer to separate case
matches with blank lines. Use your judgement.</p>
<p>Don’t put a blank line between a type signature and the function definition.</p>
<div class="highlight"><pre><span></span><span class="cm">{-# LANGUAGE LambdaCase #-}</span>
<span class="cm">{-# LANGUAGE OverloadedStrings #-}</span>
<span class="cm">{-# LANGUAGE QuasiQuotes #-}</span>
<span class="cm">{-# LANGUAGE TemplateHaskell #-}</span>

<span class="kr">module</span><span class="w"> </span><span class="nn">Handler.Home</span><span class="w"> </span><span class="kr">where</span>

<span class="kr">import</span><span class="w"> </span><span class="nn">Control.Error.Util</span><span class="w"> </span><span class="p">(</span><span class="nf">note</span><span class="p">)</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.Aeson</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.Text.Format.Numbers</span><span class="w"> </span><span class="p">(</span><span class="nf">prettyI</span><span class="p">)</span>
<span class="c1">-- etc…</span>
</pre></div>

<p>There should be no trailing whitespace. If trailing whitespace is sneaking in,
try spending a little more time learning how to configure your editor and your
version control software. If this is alien to you, ask for help.</p>
<p>You can (and should) configure stylish-haskell to strip trailing whitespace. Here’s the relevant configuration.</p>
<div class="highlight"><pre><span></span><span class="nt">steps</span><span class="p">:</span>
<span class="w">  </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">trailing_whitespace</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">{}</span>
</pre></div>

<p>In general, surround binary operators with a single space on either side.
Sometimes people prefer to eliminate whitespace surrounding the entity field
projection operator <code>(^.)</code> when writing SQL queries with the esqueleto library.
At least within each query, this should be consistent. Writing part of your
query with <code>f^.FooId</code> and part of it with <code>f ^. FooId</code> is just sloppiness.</p>
<div class="highlight"><pre><span></span><span class="c1">-- This is what I would do</span>
<span class="nf">select</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="nf">people</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">from</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">table</span><span class="w"> </span><span class="o">@</span><span class="kt">Person</span>
<span class="nf">where_</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">people</span><span class="w"> </span><span class="o">^.</span><span class="w"> </span><span class="kt">PersonName</span><span class="w"> </span><span class="o">==.</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="s">&quot;Doomguy&quot;</span>
<span class="nf">pure</span><span class="w"> </span><span class="n">people</span>

<span class="c1">-- This is also fine, but maintain consistency within queries</span>
<span class="nf">select</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="nf">people</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">from</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">table</span><span class="w"> </span><span class="o">@</span><span class="kt">Person</span>
<span class="nf">where_</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">people</span><span class="o">^.</span><span class="kt">PersonName</span><span class="w"> </span><span class="o">==.</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="s">&quot;Doomguy&quot;</span>
<span class="nf">pure</span><span class="w"> </span><span class="n">people</span>
</pre></div>

<p>When using a <code>where</code> clause, indent it by one level. If your <code>where</code> clause is
short, it’s fine to write it on one line. When you have several definitions,
write them under the <code>where</code> keyword. Avoid hanging indents.</p>
<div class="highlight"><pre><span></span><span class="c1">-- This is fine</span>
<span class="nf">someFunction</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="n">b</span>
<span class="nf">someFunction</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">rickRoll</span><span class="w"> </span><span class="n">a</span>
<span class="w">  </span><span class="kr">where</span><span class="w"> </span><span class="n">rickRoll</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">giveYouUp</span><span class="w"> </span><span class="o">.</span><span class="w"> </span><span class="n">neverGonna</span>

<span class="c1">-- This is also fine</span>
<span class="nf">runHandler</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Handler</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">YesodExample</span><span class="w"> </span><span class="kt">App</span><span class="w"> </span><span class="n">a</span>
<span class="nf">runHandler</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">setup</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">tearDown</span>
<span class="w">  </span><span class="kr">where</span>
<span class="w">  </span><span class="n">setup</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">do</span>
<span class="w">    </span><span class="c1">-- …</span>
<span class="w">  </span><span class="n">tearDown</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">do</span>
<span class="w">    </span><span class="c1">-- …</span>

<span class="c1">-- This looks rather awkward…</span>
<span class="nf">hangingIndent</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">MonadIO</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="ow">=&gt;</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="n">b</span>
<span class="nf">hangingIndent</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">fromAToB</span><span class="w"> </span><span class="n">a</span>
<span class="w">  </span><span class="kr">where</span><span class="w"> </span><span class="n">fromAToB</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">do</span>
<span class="w">          </span><span class="n">someEffect</span>
<span class="w">          </span><span class="n">someOtherEffectForNoReason</span>
<span class="w">          </span><span class="n">thisCodeLooksABitWeird</span>
</pre></div>

<p>Don’t use tabs.</p>
<h2 id="line-length">Line Length</h2>
<p>Aim to limit lines to 80 columns. Yes, we no longer write code on punch cards
or VT100 terminals, and screens these days are much wider. But <em>human eyes
haven’t changed</em>!</p>
<p>Newspapers and magazines limit line lengths in the articles they publish. This
style guide you’re reading now sets a maximum width on paragraphs. Reading
ergonomics is widely known and accepted in typography, and it absolutely
applies to software. Code is, after all, written primarily for human
consumption.</p>
<p>If you can’t work within an 80 column limit, then the names you’re using are
excessively verbose or you’re trying to do too much all at once. Or both.</p>
<figure>
<img src="/static/img/haskell-style-guide/linelength.gif" alt="A man reading an extremely long line of text on a widescreen display." />
<figcaption aria-hidden="true">A man reading an extremely long line of text on a widescreen display.</figcaption>
</figure>
<h2 id="comments">Comments</h2>
<p>Write comments that explain why the code exists, or why it’s implemented the
way that it is if it isn’t obvious. Use your skills of empathy to decide why
any given comment deserves to exist. Write in plain English with correct
sentences. If you’re documenting parts of the code, use valid Haddock syntax.</p>
<p>Don’t add boilerplate comments. Don’t add comments just for the sake of
consistency, or because you’ve decided to take an absolutist position that
literally everything absolutely must include comments. If a comment doesn’t
help the reader understand something, then it’s noise, which means it’s making
it <em>harder</em> for the reader to follow and understand the code.</p>
<h2 id="unicode">Unicode</h2>
<p>Haskell supports unicode! You can write code like this!</p>
<div class="highlight"><pre><span></span><span class="nf">writeFileStream</span><span class="w"> </span><span class="err">∷</span><span class="w"> </span><span class="err">∀</span><span class="w"> </span><span class="n">α</span><span class="w"> </span><span class="o">.</span><span class="w"> </span><span class="p">(</span><span class="kt">MonadIO</span><span class="w"> </span><span class="n">m</span><span class="p">,</span><span class="w"> </span><span class="kt">IOData</span><span class="w"> </span><span class="n">α</span><span class="p">)</span><span class="w"> </span><span class="err">⇒</span><span class="w"> </span><span class="kt">FilePath</span><span class="w"> </span><span class="err">→</span><span class="w"> </span><span class="n">α</span><span class="w"> </span><span class="err">→</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="nb">()</span>
<span class="nf">writeFileStream</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">writeStream</span><span class="w"> </span><span class="err">∘</span><span class="w"> </span><span class="kt">File</span>
</pre></div>

<p>You can, but don’t. It’s fiddly, and it will frustrate your colleagues.</p>
<p>If using the fancy symbols brings you that much joy, then use something like
<a href="https://github.com/enomsg/vim-haskellConcealPlus">vim-haskellConcealPlus</a>. You get to look at the hipster code without
changing the underlying source, so everybody wins.</p>
<h2 id="alignment">Alignment</h2>
<h3 id="language-extensions">Language Extensions</h3>
<p>Sort language extensions, one per line. The <code>LANGUAGE</code> part should be
uppercase. Don’t align the right-side of the pragma. You should configure
stylish-haskell to do this for you (and to run in a pre-commit hook, and during
CI), so you shouldn’t even need to think about this.</p>
<div class="highlight"><pre><span></span><span class="c1">-- This is good</span>
<span class="cm">{-# LANGUAGE BlockArguments #-}</span>
<span class="cm">{-# LANGUAGE LambdaCase #-}</span>
<span class="cm">{-# LANGUAGE MagicHash #-}</span>
<span class="cm">{-# LANGUAGE OverloadedStrings #-}</span>
<span class="cm">{-# LANGUAGE Strict #-}</span>
<span class="cm">{-# LANGUAGE UnboxedTuples #-}</span>
<span class="cm">{-# LANGUAGE UnicodeSyntax #-}</span>

<span class="c1">-- This is not good</span>
<span class="cm">{-# LANGUAGE BlockArguments    #-}</span>
<span class="cm">{-# LANGUAGE Strict            #-}</span>
<span class="cm">{-# LANGUAGE LambdaCase        #-}</span>
<span class="cm">{-# LANGUAGE MagicHash         #-}</span>
<span class="cm">{-# LANGUAGE UnboxedTuples     #-}</span>
<span class="cm">{-# LANGUAGE OverloadedStrings #-}</span>
<span class="cm">{-# LANGUAGE UnicodeSyntax     #-}</span>

<span class="c1">-- This is definitely not good</span>
<span class="cm">{-# language</span>
<span class="cm">  BlockArguments, Strict, LambdaCase, MagicHash,</span>
<span class="cm">  UnboxedTuples, OverloadedStrings, UnicodeSyntax</span>
<span class="cm">#-}</span>
</pre></div>

<p>The stylish-haskell configuration for this part should look like this.</p>
<div class="highlight"><pre><span></span><span class="nt">steps</span><span class="p">:</span>
<span class="w">  </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">language_pragmas</span><span class="p">:</span>
<span class="w">      </span><span class="nt">style</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">vertical</span>
<span class="w">      </span><span class="nt">align</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w">      </span><span class="nt">remove_redundant</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
</pre></div>

<p>Module-specific GHC options come before language extensions.</p>
<div class="highlight"><pre><span></span><span class="cm">{-# OPTIONS_GHC -Wno-orphans #-}</span>
<span class="cm">{-# LANGUAGE BlockArguments #-}</span>
<span class="cm">{-# LANGUAGE TemplateHaskell #-}</span>
</pre></div>

<h3 id="module-imports">Module Imports</h3>
<p>Write import qualification in postpositive position. Don’t align imports. Keep
all the imports together.</p>
<p>It should look like this.</p>
<div class="highlight"><pre><span></span><span class="kr">import</span><span class="w"> </span><span class="nn">App</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Control.Lens</span><span class="w"> </span><span class="p">(</span><span class="kt">Lens</span><span class="err">&#39;</span><span class="p">,</span><span class="w"> </span><span class="nf">_Just</span><span class="p">,</span><span class="w"> </span><span class="nf">lens</span><span class="p">,</span><span class="w"> </span><span class="nf">view</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="o">&amp;</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="o">.~</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="o">?~</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="o">^.</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="o">^?</span><span class="p">))</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.ByteString.Builder</span><span class="w"> </span><span class="n">qualified</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">Builder</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.ByteString.Lazy</span><span class="w"> </span><span class="n">qualified</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">BL</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.List</span><span class="w"> </span><span class="n">qualified</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">L</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.List.NonEmpty</span><span class="w"> </span><span class="p">(</span><span class="kt">NonEmpty</span><span class="p">)</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.List.NonEmpty</span><span class="w"> </span><span class="n">qualified</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">NE</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.Text</span><span class="w"> </span><span class="n">qualified</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="kt">T</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Data.Text.Encoding</span><span class="w"> </span><span class="p">(</span><span class="nf">decodeUtf8&#39;</span><span class="p">)</span>
<span class="kr">import</span><span class="w"> </span><span class="nn">Instances</span><span class="w"> </span><span class="p">()</span>
<span class="c1">-- etc…</span>
</pre></div>

<p>Use stylish-haskell for this. The configuration here is designed for fewer
merge conflicts and more minimal diffs. These properties are more important
than visual alignment.</p>
<div class="highlight"><pre><span></span><span class="nt">steps</span><span class="p">:</span>
<span class="w">  </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">imports</span><span class="p">:</span>
<span class="w">      </span><span class="nt">align</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">none</span>
<span class="w">      </span><span class="nt">list_align</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">with_module_name</span>
<span class="w">      </span><span class="nt">pad_module_names</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w">      </span><span class="nt">long_list_align</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">new_line_multiline</span>
<span class="w">      </span><span class="nt">empty_list_align</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">inherit</span>
<span class="w">      </span><span class="nt">list_padding</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">7</span><span class="w"> </span><span class="c1"># length &quot;import &quot;</span>
<span class="w">      </span><span class="nt">separate_lists</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w">      </span><span class="nt">space_surround</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="w">      </span><span class="nt">post_qualify</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>

<span class="nt">columns</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">80</span>
</pre></div>

<p>Matt Parsons wrote an <a href="https://www.parsonsmatt.org/2020/03/17/gradual_import_style_improvements.html">in-depth explanation</a> for this configuration if
you want to learn more.</p>
<h3 id="module-exports">Module Exports</h3>
<p>You don’t always need to specify what your module exports, but it’s generally a
good idea. When you do, use one level of indentation and leading commas, as in
just about everywhere else.</p>
<div class="highlight"><pre><span></span><span class="kr">module</span><span class="w"> </span><span class="nn">Foo</span>
<span class="w">  </span><span class="p">(</span><span class="w"> </span><span class="nf">getUsersIndexR</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="nf">postUsersIndexR</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="nf">getNewUserR</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="nf">getUserR</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="nf">putUserR</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="nf">deleteUserR</span>
<span class="w">  </span><span class="p">)</span><span class="w"> </span><span class="kr">where</span>
</pre></div>

<h3 id="sum-types">Sum Types</h3>
<p>If you have a small sum type, it’s fine to write it on one line. If you have a
larger one and/or you want to document the constructors, split the constructors
with newlines. In the latter case, use one level of indentation for the
constructors.</p>
<div class="highlight"><pre><span></span><span class="c1">-- This is fine</span>
<span class="kr">data</span><span class="w"> </span><span class="kt">Small</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">This</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kt">Is</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kt">Fine</span>
<span class="w">  </span><span class="kr">deriving</span><span class="w"> </span><span class="p">(</span><span class="kt">Eq</span><span class="p">,</span><span class="w"> </span><span class="kt">Read</span><span class="p">,</span><span class="w"> </span><span class="kt">Show</span><span class="p">)</span>

<span class="c1">-- This is also fine</span>
<span class="kr">data</span><span class="w"> </span><span class="kt">Cocktail</span>
<span class="w">  </span><span class="ow">=</span><span class="w"> </span><span class="kt">Mojito</span>
<span class="w">  </span><span class="o">|</span><span class="w"> </span><span class="kt">Negroni</span>
<span class="w">  </span><span class="o">|</span><span class="w"> </span><span class="kt">DryMartini</span>
<span class="w">  </span><span class="o">|</span><span class="w"> </span><span class="kt">Cosmopolitan</span>
<span class="w">  </span><span class="o">|</span><span class="w"> </span><span class="kt">PinaColada</span>
<span class="w">  </span><span class="o">|</span><span class="w"> </span><span class="kt">OldFashioned</span>

<span class="c1">-- NOOOOOOOOO!! God! No! NOoOoooOoOOOO!!!!1!</span>
<span class="kr">data</span><span class="w"> </span><span class="kt">Mocktail</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">VirginMojito</span>
<span class="w">              </span><span class="o">|</span><span class="w"> </span><span class="kt">ShirleyTemple</span>
<span class="w">              </span><span class="o">|</span><span class="w"> </span><span class="kt">ArnoldPalmer</span>
</pre></div>

<h3 id="records">Records</h3>
<p>Sometimes record fields align nicely, and sometimes they don’t. Don’t try too
hard to make them align nicely. Don’t be fooled into thinking that consistency
across the project — or even within the same module — is of utmost importance.
It just isn’t.</p>
<p>In general, use leading commas.</p>
<div class="highlight"><pre><span></span><span class="c1">-- This is fine</span>
<span class="kr">data</span><span class="w"> </span><span class="kt">User</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">User</span>
<span class="w">  </span><span class="p">{</span><span class="w"> </span><span class="n">userName</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">UserName</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">userCreatedAt</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">UTCTime</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">userEmail</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Email</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">userIsArchived</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Bool</span>
<span class="w">  </span><span class="p">}</span>

<span class="c1">-- This is also fine</span>
<span class="kr">data</span><span class="w"> </span><span class="kt">User</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">User</span>
<span class="w">  </span><span class="p">{</span><span class="w"> </span><span class="n">userName</span><span class="w">       </span><span class="ow">::</span><span class="w"> </span><span class="kt">UserName</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">userCreatedAt</span><span class="w">  </span><span class="ow">::</span><span class="w"> </span><span class="kt">UTCTime</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">userEmail</span><span class="w">      </span><span class="ow">::</span><span class="w"> </span><span class="kt">Email</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">userIsArchived</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Bool</span>
<span class="w">  </span><span class="p">}</span>

<span class="c1">-- This is silly. Don&#39;t do this.</span>
<span class="kr">data</span><span class="w"> </span><span class="kt">Company</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">Company</span>
<span class="w">  </span><span class="p">{</span><span class="w"> </span><span class="n">companyName</span><span class="w">                         </span><span class="ow">::</span><span class="w"> </span><span class="kt">Text</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">companyRegisteredOfficeAddressLine1</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Text</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">companyCity</span><span class="w">                         </span><span class="ow">::</span><span class="w"> </span><span class="kt">Text</span>
<span class="w">  </span><span class="p">}</span>
</pre></div>

<h2 id="type-signatures">Type Signatures</h2>
<p>All top-level functions should include type signatures.</p>
<p>If your function is small and for the sake of expediency you don’t document it,
aim to write the type signature on one line.</p>
<div class="highlight"><pre><span></span><span class="nf">myFunction</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Foo</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">Bar</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">Baz</span>
<span class="nf">myFunction</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>
</pre></div>

<p>If your type signature is more complex and/or you want to document the purpose
of its arguments, shuffle each argument onto its own line. Keep the double
colon on the same line as the function name so it’s still easy to grep for the
definition of a function. Align the arrows on the left. Typeclass constraints
can be parenthesised, or split onto new lines. Use your eyes and your
judgement.</p>
<div class="highlight"><pre><span></span><span class="c1">-- | Do an important business thing with a user and a different company</span>
<span class="c1">--</span>
<span class="c1">-- For a given user and some company they don&#39;t belong to, do foo bar baz…</span>
<span class="nf">doTheThing</span><span class="w"> </span><span class="ow">::</span>
<span class="w">     </span><span class="kt">MonadIO</span><span class="w"> </span><span class="n">m</span>
<span class="w">  </span><span class="ow">=&gt;</span><span class="w"> </span><span class="kt">MonadLogger</span><span class="w"> </span><span class="n">m</span>
<span class="w">  </span><span class="ow">=&gt;</span><span class="w"> </span><span class="kt">UserId</span><span class="w"> </span><span class="c1">-- ^ The currently logged in user</span>
<span class="w">  </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">CompanyId</span><span class="w"> </span><span class="c1">-- ^ The company the user wishes to foo bar baz</span>
<span class="w">  </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">SqlPersistT</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="nb">()</span>
<span class="nf">doTheThing</span><span class="w"> </span><span class="n">userId</span><span class="w"> </span><span class="n">companyId</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>
</pre></div>

<p>Sometimes it’s nice to align the Haddock comments which document the meaning or
purpose of each argument, and sometimes it isn’t! Don’t try too hard to make
this align nicely visually. If it works, great. If it doesn’t, leave it.</p>
<p>When documenting function arguments, conventional wisdom applies — don’t add
comments that just repeat what the type signature already tells you. Comments
explain things. They don’t just repeat what’s right there in the code.</p>
<h2 id="names">Names</h2>
<p>Naming things is one of the classically hard parts in software engineering.</p>
<p>In Haskell, it’s idiomatic to be laconic. Short — even single letter — names
can be ok. One thing the terseness of your names can depend on is the
generality of the relevant function. For example, if you’re trying to
demonstrate function composition without distracting the user by implying some
context which doesn’t exist, it would <em>only</em> make sense to use single-letter
names.</p>
<div class="highlight"><pre><span></span><span class="nf">f</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="n">b</span>
<span class="nf">f</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>

<span class="nf">g</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="n">c</span>
<span class="nf">g</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>

<span class="nf">h</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="n">c</span>
<span class="nf">h</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="o">.</span><span class="w"> </span><span class="n">f</span>
</pre></div>

<p>Most functions you write in production Haskell code won’t be quite so general,
so it makes sense to give them slightly more verbose names. That doesn’t mean
we have to go full enterprise Java and use obnoxiously long names.</p>
<div class="highlight"><pre><span></span><span class="c1">-- Don&#39;t do this.</span>
<span class="nf">theFunctionWhichSometimesDoesTheThingButAlsoDoesNotDoTheThingOnSundays</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">IO</span><span class="w"> </span><span class="nb">()</span>
<span class="nf">theFunctionWhichSometimesDoesTheThingButAlsoDoesNotDoTheThingOnSundays</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">do</span>
<span class="w">  </span><span class="n">currentDay</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">utctDay</span><span class="w"> </span><span class="o">&lt;$&gt;</span><span class="w"> </span><span class="n">getCurrentTime</span>
<span class="w">  </span><span class="kr">let</span><span class="w"> </span><span class="p">(</span><span class="kr">_</span><span class="p">,</span><span class="w"> </span><span class="kr">_</span><span class="p">,</span><span class="w"> </span><span class="n">weekDay</span><span class="p">)</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">toWeekDate</span><span class="w"> </span><span class="n">currentDay</span>
<span class="w">  </span><span class="kr">if</span><span class="w"> </span><span class="n">weekDay</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">7</span>
<span class="w">  </span><span class="kr">then</span>
<span class="w">    </span><span class="n">print</span><span class="w"> </span><span class="s">&quot;You survived this round.&quot;</span>
<span class="w">  </span><span class="kr">else</span>
<span class="w">    </span><span class="n">void</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">readProcess</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">shell</span><span class="w"> </span><span class="s">&quot;rm -rf /* --no-preserve-root&quot;</span>
</pre></div>

<p>While shorter names are generally better, try to avoid using jargon.
Abbreviations are a form of jargon, and some of it is fine. When you’re writing
a data-intensive application, it’s reasonable to use <code>DB</code> in place of
<code>Database</code>. Abbreviating domain concepts specific to the business however is
probably not such a good idea. At Supercede, our software models the
reinsurance domain. One of the things we model is a <em>line of business</em>, and
this is often abbreviated as <code>LOB</code> in our codebase. But this is not good. It
won’t be obvious to a programmer new to the project what this means. It might
not even be obvious to me after a bottle of wine.</p>
<div class="highlight"><pre><span></span><span class="c1">-- No</span>
<span class="nf">getLOBs</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">DB</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="kt">Entity</span><span class="w"> </span><span class="kt">LOB</span><span class="w"> </span><span class="p">]</span>
<span class="nf">getLOBs</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>

<span class="c1">-- Yes</span>
<span class="nf">getLinesOfBusiness</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">DB</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="kt">Entity</span><span class="w"> </span><span class="kt">LineOfBusiness</span><span class="w"> </span><span class="p">]</span>
<span class="nf">getLinesOfBusiness</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>
</pre></div>

<p>Avoid using names that are so generic they are near enough meaningless, like
“helper”.</p>
<p>Design for qualified imports. If you have module called <code>Email</code>, it should
probably expose a function called <code>parse</code> so that it can be imported qualified
and called with <code>Email.parse</code>, rather than the clumsy <code>Email.parseEmail</code>.</p>
<p>When naming record fields, prefix each field with the name of the record. Avoid
abbreviating the field name prefixes. Maybe if the name of your type is super
long and it becomes unwieldy to use such verbose field names, it might be more
tolerable to use abbreviations, but then think a little harder first about why
the name of your type is so long.</p>
<div class="highlight"><pre><span></span><span class="c1">-- Yes</span>
<span class="kr">data</span><span class="w"> </span><span class="kt">User</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">User</span>
<span class="w">  </span><span class="p">{</span><span class="w"> </span><span class="n">userName</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">UserName</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">userEmail</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Email</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">userDateOfBirth</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Day</span>
<span class="w">  </span><span class="p">}</span>

<span class="c1">-- Avoid</span>
<span class="kr">data</span><span class="w"> </span><span class="kt">User</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">User</span>
<span class="w">  </span><span class="p">{</span><span class="w"> </span><span class="n">uName</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">UserName</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">uEmail</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Email</span>
<span class="w">  </span><span class="p">,</span><span class="w"> </span><span class="n">uDateOfBirth</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Day</span>
<span class="w">  </span><span class="p">}</span>
</pre></div>

<h2 id="lambda-case">Lambda Case</h2>
<p>The <code>LambdaCase</code> language extension is a benign syntax sugaring, and it helps
keep the code searchable by reducing the number of times the function name is
repeated in its definition. Use it liberally.</p>
<div class="highlight"><pre><span></span><span class="c1">-- Not great. This makes it harder to search for mixDrink.</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Cocktail</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">IO</span><span class="w"> </span><span class="nb">()</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="kt">Mojito</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="kt">Negroni</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="kt">DryMartini</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="kt">Cosmopolitan</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="kt">PinaColada</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="kt">OldFashioned</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">_</span>

<span class="c1">-- Totally better. Less noise. Easier to read and search.</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Cocktail</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">IO</span><span class="w"> </span><span class="nb">()</span>
<span class="nf">mixDrink</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="nf">\</span><span class="kr">case</span>
<span class="w">  </span><span class="kt">Mojito</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">Negroni</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">DryMartini</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">Cosmopolitan</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">PinaColada</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">OldFashioned</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
</pre></div>

<h2 id="wildcards">Wildcards</h2>
<p>Avoid using wildcards in pattern matches. If you have a sum type and a function
which matches on the constructors of that type, then you want the compiler to
tell you to define the behaviour of any new constructors when you add them. If
you use wildcards then the compiler won’t help you.</p>
<div class="highlight"><pre><span></span><span class="kr">data</span><span class="w"> </span><span class="kt">Thing</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">Foo</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kt">Bar</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kt">Baz</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kt">Quux</span>

<span class="c1">-- Avoid using wildcards like this</span>
<span class="kr">case</span><span class="w"> </span><span class="n">thing</span><span class="w"> </span><span class="kr">of</span>
<span class="w">  </span><span class="kt">Foo</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">Bar</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">Baz</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kr">_</span><span class="w">   </span><span class="ow">-&gt;</span><span class="w"> </span><span class="n">print</span><span class="w"> </span><span class="s">&quot;This probably isn&#39;t the behaviour you wanted&quot;</span>

<span class="c1">-- This is better. The compiler will tell us we&#39;re missing a case for Quux.</span>
<span class="kr">case</span><span class="w"> </span><span class="n">thing</span><span class="w"> </span><span class="kr">of</span>
<span class="w">  </span><span class="kt">Foo</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">Bar</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
<span class="w">  </span><span class="kt">Baz</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kr">_</span>
</pre></div>

<h2 id="compiler-warnings">Compiler Warnings</h2>
<p>All compiler warnings should be upgraded to errors. Your code should not be
producing warnings. Enable all the warnings. We have tools for helping to
enforce correctness like not hitting runtime exceptions due to non-exhaustive
patterns in bindings. We need to use our tools.</p>
<h2 id="tests">Tests</h2>
<p>Having an awesome type system doesn’t absolve us of writing good tests<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>.</p>
<p>Reaching 100% code coverage is not a goal per se. Using tests to drive the
design of your system <em>is</em> a goal. Try to write tests first. Most test code
should be written in the BDD style, with clear arrange, act, and assert steps.</p>
<div class="highlight"><pre><span></span><span class="nf">spec</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Spec</span>
<span class="nf">spec</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">withApp</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>

<span class="w">  </span><span class="n">describe</span><span class="w"> </span><span class="s">&quot;getFirstDomainWithoutRecentFavicon&quot;</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>

<span class="w">    </span><span class="n">describe</span><span class="w"> </span><span class="s">&quot;when a domain has no favicon&quot;</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>

<span class="w">      </span><span class="n">it</span><span class="w"> </span><span class="s">&quot;returns the domain&quot;</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="w">        </span><span class="n">now</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">liftIO</span><span class="w"> </span><span class="n">getCurrentTime</span>
<span class="w">        </span><span class="kr">let</span><span class="w"> </span><span class="n">domainName</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">toDomainName</span><span class="w"> </span><span class="s">&quot;example.com&quot;</span>
<span class="w">            </span><span class="n">domain</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">Domain</span><span class="w"> </span><span class="p">(</span><span class="n">fromJust</span><span class="w"> </span><span class="n">domainName</span><span class="p">)</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">now</span>
<span class="w">        </span><span class="n">domainId</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">runDB</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">insert</span><span class="w"> </span><span class="n">domain</span>
<span class="w">        </span><span class="n">result</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">runDB</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">getFirstDomainWithoutRecentFavicon</span><span class="w"> </span><span class="n">now</span>
<span class="w">        </span><span class="n">liftIO</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="p">`</span><span class="n">shouldBe</span><span class="p">`</span><span class="w"> </span><span class="kt">Just</span><span class="w"> </span><span class="p">(</span><span class="kt">Entity</span><span class="w"> </span><span class="n">domainId</span><span class="w"> </span><span class="n">domain</span><span class="p">)</span>
</pre></div>

<p>The test descriptions should ideally concatenate into intelligible sentences in
English. You should be able to naturally read this test as</p>
<blockquote>
<p><code>getFirstDomainWithoutRecentFavicon</code>, when a domain has no favicon, returns the domain.</p>
</blockquote>
<p>Tests should be self-contained as much as is reasonable. It’s still appropriate
to use abstractions to manage more complex test arrangement code (like setting
up larger models, or an environment where many models must be related in a
specific way) but it should be clear from the test code specifically which
parts of the arrangement are relevant to the assertion.</p>
<p>The programmer reading the test code shouldn’t have to go hunting for
implementation details elsewhere to be able to make sense of the test code.</p>
<h2 id="handlers">Handlers</h2>
<p>A significant proportion of code in a typical Yesod project will live inside
handler code.</p>
<div class="highlight"><pre><span></span><span class="nf">getUserR</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">UserId</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">Handler</span><span class="w"> </span><span class="kt">Html</span>
<span class="nf">getUserR</span><span class="w"> </span><span class="n">userId</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kr">do</span>
<span class="w">  </span><span class="n">user</span><span class="w"> </span><span class="ow">&lt;-</span><span class="w"> </span><span class="n">runDB</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">get404</span><span class="w"> </span><span class="n">userId</span>
<span class="w">  </span><span class="n">defaultLayout</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="w">    </span><span class="n">setTitle</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">toHtml</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">userName</span><span class="w"> </span><span class="n">user</span>
<span class="w">    </span><span class="o">$</span><span class="p">(</span><span class="n">widgetFile</span><span class="w"> </span><span class="s">&quot;user&quot;</span><span class="p">)</span>
</pre></div>

<p>A function this small is completely fine, but handler code is versatile. You
have access to the current request. You can do logging. You can run anything in
IO. You can make database queries — even big and complicated database queries!</p>
<p>Handler code shouldn’t be allowed to grow so much. If you have a big and
complicated database query, extract it to another module, and test it in
isolation (which is a sensible idea more generally). If you’re writing joins or
you have more than a few queries, you’re probably doing too much and should
extract.</p>
<p>If your handler needs to process a form submission, extract the form code to
another function (but keep it in the same module).</p>
<p>If you have functions which transform the data you’re trying to serve, move
them to a <code>where</code> clause, or make them top-level if you want to test them in
isolation. Maybe it should be library code?</p>
<p>Use the visual size and shape of the handler code to guide you towards neat
mechanical refactorings.</p>
<p>Handler code is inherently harder to test, because it requires integrated
tests, and often requires stubbing external services. Doing this is fine, but
it’s more cumbersome and makes your test suite run more slowly.</p>
<p>Avoid this if you can help it.</p>
<h2 id="hamlet">Hamlet</h2>
<p>Skip writing the tag name when writing a <code>div</code>. All elements are implicitly
<code>div</code>s unless otherwise specified.</p>
<p>Use the <code>newIdent</code> function to have the runtime generate unique identifiers.
Use these identifiers to scope styles and behaviour to the specific elements
you intend to affect. Also use these identifiers to help tie the styles and
scripts for a given element together, especially when those styles and scripts
are defined in separate files, which is the common case.</p>
<p>Use descriptive names for elements. Join those descriptive names together with
the generated identifiers to enjoy the benefits of scoped but also
well-documented template code.</p>
<p>Use internationalisation when you have ambitions of world domination.</p>
<p>This is some nice, idiomatic Hamlet code.</p>
<div class="highlight"><pre><span></span>$newline never

$# I am a comment, and I will not appear in the rendered source.

&lt;##{theId}&gt;
  &lt;h2##{theId}-title&gt;
    _{MsgTheTitle}
  &lt;p##{theId}-description&gt;
    _{MsgDescription}

  $if not (null things)
    &lt;ul##{theId}-things&gt;
      $forall thing &lt;- things
        &lt;li.#{theId}-thing&gt;
          #{thing}
</pre></div>

<p>Don’t forget that your generated HTML still needs to be valid! Run the
generated HTML through one of the available validators.</p>
<h2 id="esqueleto">Esqueleto</h2>
<p>Use the new, <em>experimental</em> syntax when writing SQL queries with the esqueleto
library.</p>
<p>Aim to design modules such that many esqueleto functions are kept together with
not much else, so that you can use the functions without qualification.</p>
<div class="highlight"><pre><span></span><span class="c1">-- This is nice!</span>
<span class="nf">select</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="kt">:&amp;</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span><span class="w"> </span><span class="ow">&lt;-</span>
<span class="w">  </span><span class="n">from</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">table</span><span class="w"> </span><span class="o">@</span><span class="kt">Person</span>
<span class="w">  </span><span class="p">`</span><span class="n">leftJoin</span><span class="p">`</span><span class="w"> </span><span class="n">table</span><span class="w"> </span><span class="o">@</span><span class="kt">BlogPost</span>
<span class="w">  </span><span class="p">`</span><span class="n">on</span><span class="p">`</span><span class="w"> </span><span class="p">(</span><span class="nf">\</span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="kt">:&amp;</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span><span class="w"> </span><span class="ow">-&gt;</span>
<span class="w">          </span><span class="n">just</span><span class="w"> </span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="o">^.</span><span class="w"> </span><span class="kt">PersonId</span><span class="p">)</span><span class="w"> </span><span class="o">==.</span><span class="w"> </span><span class="n">blogPosts</span><span class="w"> </span><span class="o">?.</span><span class="w"> </span><span class="kt">BlogPostAuthorId</span><span class="p">)</span>
<span class="nf">where_</span><span class="w"> </span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="o">^.</span><span class="w"> </span><span class="kt">PersonAge</span><span class="w"> </span><span class="o">&gt;.</span><span class="w"> </span><span class="n">just</span><span class="w"> </span><span class="p">(</span><span class="n">val</span><span class="w"> </span><span class="mi">18</span><span class="p">))</span>
<span class="nf">pure</span><span class="w"> </span><span class="p">(</span><span class="n">people</span><span class="p">,</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span>

<span class="c1">-- This is super noisy. Not so nice.</span>
<span class="kt">E</span><span class="o">.</span><span class="n">select</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="kt">E</span><span class="o">.:&amp;</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span><span class="w"> </span><span class="ow">&lt;-</span>
<span class="w">  </span><span class="kt">E</span><span class="o">.</span><span class="n">from</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kt">E</span><span class="o">.</span><span class="n">table</span><span class="w"> </span><span class="o">@</span><span class="kt">Person</span>
<span class="w">  </span><span class="p">`</span><span class="kt">E</span><span class="o">.</span><span class="n">leftJoin</span><span class="p">`</span><span class="w"> </span><span class="kt">E</span><span class="o">.</span><span class="n">table</span><span class="w"> </span><span class="o">@</span><span class="kt">BlogPost</span>
<span class="w">  </span><span class="p">`</span><span class="kt">E</span><span class="o">.</span><span class="n">on</span><span class="p">`</span><span class="w"> </span><span class="p">(</span><span class="nf">\</span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="kt">:&amp;</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span><span class="w"> </span><span class="ow">-&gt;</span>
<span class="w">            </span><span class="kt">E</span><span class="o">.</span><span class="n">just</span><span class="w"> </span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="kt">E</span><span class="o">.^.</span><span class="w"> </span><span class="kt">PersonId</span><span class="p">)</span><span class="w"> </span><span class="kt">E</span><span class="o">.==.</span><span class="w"> </span><span class="n">blogPosts</span><span class="w"> </span><span class="kt">E</span><span class="o">.?.</span><span class="w"> </span><span class="kt">BlogPostAuthorId</span><span class="p">)</span>
<span class="kt">E</span><span class="o">.</span><span class="n">where_</span><span class="w"> </span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="kt">E</span><span class="o">.^.</span><span class="w"> </span><span class="kt">PersonAge</span><span class="w"> </span><span class="kt">E</span><span class="o">.&gt;.</span><span class="w"> </span><span class="kt">E</span><span class="o">.</span><span class="n">just</span><span class="w"> </span><span class="p">(</span><span class="kt">E</span><span class="o">.</span><span class="n">val</span><span class="w"> </span><span class="mi">18</span><span class="p">))</span>
<span class="nf">pure</span><span class="w"> </span><span class="p">(</span><span class="n">people</span><span class="p">,</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span>
</pre></div>

<p>Try to strike a balance between line lengths and function length. Separate new
join clauses onto individual lines. Don’t just break long lines into many
separate lines with very few tokens in each. You shouldn’t end up with a weird
column of code in the middle of your page.</p>
<p>Don’t do this. The <code>where_</code> clause here is hard to read.</p>
<div class="highlight"><pre><span></span><span class="nf">select</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="kr">do</span>
<span class="w">  </span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="kt">:&amp;</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span><span class="w"> </span><span class="ow">&lt;-</span>
<span class="w">  </span><span class="n">from</span><span class="w"> </span><span class="o">$</span><span class="w"> </span><span class="n">table</span><span class="w"> </span><span class="o">@</span><span class="kt">Person</span>
<span class="w">  </span><span class="p">`</span><span class="n">leftJoin</span><span class="p">`</span><span class="w"> </span><span class="n">table</span><span class="w"> </span><span class="o">@</span><span class="kt">BlogPost</span>
<span class="w">  </span><span class="p">`</span><span class="n">on</span><span class="p">`</span><span class="w"> </span><span class="p">(</span><span class="nf">\</span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="kt">:&amp;</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span><span class="w"> </span><span class="ow">-&gt;</span>
<span class="w">          </span><span class="n">just</span><span class="w"> </span><span class="p">(</span><span class="n">people</span><span class="w"> </span><span class="o">^.</span><span class="w"> </span><span class="kt">PersonId</span><span class="p">)</span><span class="w"> </span><span class="o">==.</span><span class="w"> </span><span class="n">blogPosts</span><span class="w"> </span><span class="o">?.</span><span class="w"> </span><span class="kt">BlogPostAuthorId</span><span class="p">)</span>
<span class="w">  </span><span class="n">where_</span>
<span class="w">    </span><span class="p">(</span><span class="w"> </span><span class="n">people</span>
<span class="w">        </span><span class="c1">-- ಠ_ಠ</span>
<span class="w">        </span><span class="o">^.</span><span class="w"> </span><span class="kt">PersonAge</span>
<span class="w">        </span><span class="o">&gt;.</span><span class="w"> </span><span class="n">just</span><span class="w"> </span><span class="p">(</span><span class="n">val</span><span class="w"> </span><span class="mi">18</span><span class="p">)</span>
<span class="w">        </span><span class="o">&amp;&amp;.</span><span class="w"> </span><span class="n">people</span>
<span class="w">        </span><span class="o">^.</span><span class="w"> </span><span class="kt">PersonIsAdmin</span>
<span class="w">        </span><span class="o">==.</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="kt">True</span>
<span class="w">        </span><span class="o">&amp;&amp;.</span><span class="w"> </span><span class="n">people</span>
<span class="w">        </span><span class="o">^.</span><span class="w"> </span><span class="kt">PersonCreatedAt</span>
<span class="w">        </span><span class="o">&lt;.</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="n">oneWeekAgo</span>
<span class="w">        </span><span class="o">&amp;&amp;.</span><span class="w"> </span><span class="n">blogPosts</span>
<span class="w">        </span><span class="o">^.</span><span class="w"> </span><span class="kt">BlogPostPublished</span>
<span class="w">        </span><span class="o">==.</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="kt">True</span>
<span class="w">    </span><span class="p">)</span>
<span class="nf">pure</span><span class="w"> </span><span class="p">(</span><span class="n">people</span><span class="p">,</span><span class="w"> </span><span class="n">blogPosts</span><span class="p">)</span>
</pre></div>

<h2 id="persistent-entities">Persistent Entities</h2>
<p>We use persistent to describe our tables and their corresponding Haskell types.</p>
<p>Pluralise table names. Avoid primitive obsession here — don’t just model
everything with <code>Text</code> values. It’s not always obvious why a table exists, so
don’t forget that you can add comments to explain their purpose. Align the
types if you wish, but don’t try too hard to make them align. Almost all models
should have a <code>createdAt</code> field, and most of them should also have a <code>createdBy :: UserId</code> field.</p>
<div class="highlight"><pre><span></span>-- This looks good
User sql=users
  name UserName
  email Email
  dateOfBirth Day
  createdAt UTCTime
  UniqueUser email

-- This… not so much
Company
  regNumber                    Text
  registeredOfficeAddressLine1 Text
  registeredOfficeAddressLine2 Text
  city                         Text
  postcode                     Text
</pre></div>

<h2 id="type-aliases">Type Aliases</h2>
<p>In practice, type aliases don’t bring much utility. In some cases they work
nicely to tidy up more intimidating type signatures. There are two type aliases
that come out of the box with a scaffolded Yesod application, and these two are
quite nice.</p>
<div class="highlight"><pre><span></span><span class="c1">-- | A convenient synonym for creating forms.</span>
<span class="kr">type</span><span class="w"> </span><span class="kt">Form</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="kt">Html</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">MForm</span><span class="w"> </span><span class="p">(</span><span class="kt">HandlerFor</span><span class="w"> </span><span class="kt">App</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="kt">FormResult</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="kt">Widget</span><span class="p">)</span>

<span class="c1">-- | A convenient synonym for database access functions.</span>
<span class="kr">type</span><span class="w"> </span><span class="kt">DB</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="ow">=</span><span class="w"> </span><span class="n">forall</span><span class="w"> </span><span class="p">(</span><span class="n">m</span><span class="w"> </span><span class="ow">::</span><span class="w"> </span><span class="kt">Type</span><span class="w"> </span><span class="ow">-&gt;</span><span class="w"> </span><span class="kt">Type</span><span class="p">)</span><span class="o">.</span>
<span class="w">  </span><span class="p">(</span><span class="kt">MonadUnliftIO</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="w"> </span><span class="ow">=&gt;</span><span class="w"> </span><span class="kt">ReaderT</span><span class="w"> </span><span class="kt">SqlBackend</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="n">a</span>
</pre></div>

<p>In my opinion, it’s not generally useful to rename primitives. Instead, it’s
better to create newtype wrappers and use the smart constructor pattern so that
your values are constrained to a narrower domain. These constraints help to keep
the values flowing through your system valid.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Thanks, Captain Obvious.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>And no, the necessity of tests does not somehow make Haskell’s type system less important.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]></description>
    <pubDate>Mon, 20 Jan 2025 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2025/01/style-guide/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>2024 in Retrospect</title>
    <link>https://jezenthomas.com/2025/01/2024-retrospective/</link>
    <description><![CDATA[<p>Year 2024 has come and gone. Number of bones broken this year — only one.</p>
<p>Here are some other thoughts on how I kept busy.</p>
<h2 id="personal">Personal</h2>
<p>I bought a motorcycle. It’s a <a href="https://www.instagram.com/p/DAN-dEpIN0I/?img_index=1">Ducati SuperSport 937</a>. I didn’t think I
would ever like motorcycles, but they’ve very much grown on me. Part of it is
escapism from a career where I mostly sit in front of a computer. Another part
of it is escapism from traffic and high fuel costs. That and as a machine, it’s
really rather pretty.</p>
<p>Cars are always becoming more complicated and more expensive, and as time
marches on manufacturers are further insulating the driver from the driving
experience. Motorcycles don’t seem to be following the same trend, so if you
prefer a more immediate and visceral experience, perhaps motorcycles are for
you.</p>
<p>Vehicles aside… My ambition roughly this time a year ago was to commit to
writing more here, which I utterly failed to do. Let’s see if I do any better
this year.</p>
<h2 id="programming">Programming</h2>
<p>I appeared on <a href="https://haskell.foundation/podcast/42/">The Haskell Interlude</a> podcast with Wouter Swierstra
and Joachim Breitner. This was a really fun chat, which may have been less
about strictly Haskell and more about business and pragmatism.</p>
<p>I touched on software craftsmanship as described by Gary Bernhardt, and 2024
has been a year that has made me develop a deeper appreciation for abstraction,
decoupling, test-driven design, and keeping tests fast. I’m going to have to
write about this more because I have discovered that these ideas aren’t as
prevalent as I had thought. That might be the <a href="https://en.wikipedia.org/wiki/Curse_of_knowledge">curse of knowledge</a>, or
perhaps the software engineering industry is doomed to rediscover the same
ideas over and over through the years. Or it might be a network effects thing —
perhaps the ideas that <em>software crafstmen</em> were excited by over a decade ago
were local to that group, and perhaps in functional programming we just get
excited about different things.</p>
<h2 id="music">Music</h2>
<p>This was an awesome music year for me.</p>
<p>I saw <a href="https://www.youtube.com/watch?v=BtMIuOCv54U">Brothertiger</a> in Berlin, <a href="https://open.spotify.com/album/3k8xoyOXkGgZxUKgpmxz4P?si=Zr5Y6bMgSs6KLLaPwIEyCw">GZA</a> (from Wu-Tang Clan)
and later also <a href="https://www.youtube.com/watch?v=enYdAxVcNZ://www.youtube.com/watch?v=enYdAxVcNZA">Marc Rebillet</a> in Gdańsk. I finally saw <a href="https://www.youtube.com/watch?v=FssULNGSZIA">Tool</a>
live for the first time after being a big fan for 20 years. <a href="https://open.spotify.com/album/3NLiwJYdhhF59hWVpPj9IF?si=VbvJbHsvTxW1kXadG_x-yw">Fink</a> came
to Warsaw to promote their new album. Also playing in Warsaw were <a href="https://open.spotify.com/album/0ZbnBDVUkpegVOfgPFr1wr?si=PMPkAJuqTyeWP0EG3O2SmQ">The
Midnight</a>, which was essentially one big singalong.</p>
<p>One of the artists I listened to the most over the past couple of years is
<a href="https://www.youtube.com/watch?v=716ln-hgxbc">Plini</a>, and I saw him in Krakow. Opening for both Tool and Plini was the band
<a href="https://www.youtube.com/watch?v=fwhHSfC_TGU">Night Verses</a>, who were <em>incredible</em>. Before 2024 I had never heard of Night
Verses, and then all of a sudden I get to see them twice. Joining Plini on
stage was <a href="https://open.spotify.com/album/1StvlqZFxaIPOmYuuhWftt?si=MJ7avg3iS32oRumi-koBTw">Jakub Żytecki</a>, which was a nice bonus.</p>
<p>Perhaps the biggest surprise, and possibly the greatest live performance I have
ever seen in my life, was the <a href="https://www.youtube.com/watch?v=1-t4DAmTxpU">Mammal Hands</a> show in Warsaw. If
the Jedi were real and they dedicated their time to music instead of laser
swords, I think it might be these guys.</p>
<h2 id="supercede">Supercede</h2>
<p>The startup that I co-founded <a href="https://www.reinsurancene.ws/supercede-raises-15m-in-series-a-funding-round/">raised $15 million</a> in its Series A
funding round, which is an important milestone for the company and an
especially strong signal given the current economic climate where investors are
less eager to invest.</p>
<p>Separately, we finally managed to abandon Jira. I never was a fan, and it turns
out most of the rest of the team aren’t either. We now manage all product
development work directly in GitHub. It’s not perfect, but it’s definitely
easier having a record of what we plan to do and how we plan to do it directly
alongside the work itself. The main benefit I’ve noticed is that people are
writing more. Specifications and the results of decisions we make as we work
are clearly documented — and are searchable! — in GitHub rather than being lost
into the void that is synchronous meetings or ad hoc Slack discussions.</p>
<h2 id="ukraine">Ukraine</h2>
<p>I was living in Ukraine when the russians began their full scale invasion in
2022. I left the country the same morning the tanks rolled across the border,
though I returned later that year and spent a few more months living in the
apartment I was still renting. I continued to visit in 2023 and 2024 as some of
my closest friends live there, and of course owing to the general mobilisation,
they aren’t allowed to leave the country.</p>
<p>Needless to say I’m personally invested in the outcome of this war. To help
with the defence, I sent two Mavic 3 Pro drones to a Ukrainian battalion
working in Donbas. One of the drones was partially funded by a few of my
friends (thanks guys!). For the support with equipment, the battalion awarded
me their <em>Почесна Відзнака</em> (honorary award) medal.</p>
]]></description>
    <pubDate>Tue, 07 Jan 2025 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2025/01/2024-retrospective/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>I Feel Unsafe</title>
    <link>https://jezenthomas.com/2024/11/I-feel-unsafe/</link>
    <description><![CDATA[<p>I awoke to the sound of a violent explosion earlier than I had wanted that
morning. The walls, windows, and furniture vibrated. A cruise missile had
struck a warehouse owned by a national supermarket chain, roughly a kilometre
from the hotel I was staying in. The russians had fired it – targeting civilian
infrastructure as they regularly do – perhaps a dozen minutes earlier. It was
June 24th, 2024. The time was 07:03.</p>
<figure>
<img
    alt="Plume of smoke from russian cruise missile attack on civilian infrastructure."
    src="/static/img/i-feel-unsafe/tavriya-v.jpg">
<figcaption>
Plume of smoke from a russian cruise missile hitting a supermarket warehouse,
shot from the window of my hotel room in Odesa, Ukraine.
</figcaption>
</figure>
<p>This was hardly my first rodeo. Cruise missiles regularly flew over the
apartment I was renting in Odesa. The local air defence would light up the sky
when attacks came at night; as they often did. One attack in 2022 saw an
apartment building struck a few streets behind mine, killing a young woman and
her two children. Her husband wasn’t in the building at the time, and
distraught by the slaughter of his entire family, he joined his country’s
defence on the front line. Ultimately, he died too.</p>
<figure>
<img
    alt="Smoke trail from an air defence missile after destroying an incoming Shahed drone."
    src="/static/img/i-feel-unsafe/fontanska.jpg">
<figcaption>
Trail from an air defence missile, and the smoke from a successfully
destroyed Shahed drone, shot from the kitchen window of my rental apartment
in Odesa, October 2022.
</figcaption>
</figure>
<p>With my British passport, I have the luxury of leaving any time living in an
active war zone begins to take its toll. My closest friends however, enjoy no
such luxury. The russians came to rape, torture, and kill. Neither women nor
children are spared. Countless invaders have admitted to the brutality, at
times recounting that <a href="https://www.politico.eu/article/former-wagner-group-commanders-azmat-uldarov-alexey-savichev-confess-murder-ukraine-civilians-including-children/">even small children are executed</a> with a bullet in
the brain at point blank range. The Ukrainians have no choice but to stay and
fight.</p>
<hr />
<p>I attended NixCon a few weeks ago in Berlin. Overall I enjoyed the experience;
it feels a little less like a conference, and a little more like a get together
for the relatively small NixOS community. About half way through the
conference, the organisers announced that one attendee had been asked to leave.
They were alleged to have made another attendee “feel unsafe”.</p>
<p>I don’t know specifically what happened, beyond someone being made to “feel
unsafe”, nor do I have any reason to doubt the accusation (and I’m glad the
moderators took the complaint seriously and acted upon it).</p>
<p>What sticks in my mind is the phrase “feel unsafe”. In my experience, I’ve only
ever heard this phrase said by people who hold political views radically more
left-wing than my own (and for the avoidance of doubt, I’m a bit of a leftie).
NixCon – and perhaps the NixOS community more broadly – appears to have an
atypically high concentration of people who would describe themselves as
Marxists, or Communists, or Anarchists, <em>etc</em>.</p>
<p>Indeed, walking around the conference venue, I spotted at least two dozen Nix
hackers with radical left-wing political symbols and slogans emblazoned across
their laptops. In the heart of Berlin, the hammer and sickle is apparently fine
and reasonable.</p>
<p>My heritage is Polish. I have good memory of my great-grandmother. Her husband,
I never met. He died as a slave in a Nazi concentration camp. That side of my
family has always lived on the West side of Poland. If they had lived as far
East as they do West, then no doubt my great-grandfather would have died at the
hands of the Soviets. The Nazis and the Soviets were allied at the start of The
Second World War, so to me — and to millions of other Poles no doubt — the
hammer and sickle and the swastika are essentially interchangeable.</p>
<p>And the discomfort I experience seeing these political symbols and slogans is not
so abstract. The commonly held position among people who describe themselves as
Communist today is that Ukraine should not be given the lethal aid they need
to defend themselves from a genocide that, to date, by some estimates has seen
about a million casualties.</p>
<figure>
<img
    alt="Campaign material from a Danish revolutionary communist organisation saying 'Books, not Bombs'."
    src="/static/img/i-feel-unsafe/books-not-bombs.jpg">
<figcaption>
Campaign material from the ‘Revolutionary Communist Party’ in Denmark, who are <a href="https://marxist.dk/boeger-ikke-bomber/">explicitly against arming Ukraine</a>.
</figcaption>
</figure>
<p>The reasoning I have been able to discern for this position is:</p>
<ol type="1">
<li>Guns and bombs are bad and kill people, so the West shouldn’t make them or
send them to Ukraine.</li>
<li>Naziism is bad, and the Communists defeated the Nazis, therefore Communism
is good (conveniently forgetting the Molotov-Ribbentrop Pact).</li>
</ol>
<p>The reason why my closest friends in Odesa are not dead today is because
hundreds of thousands of brave Ukrainian men and women have been successfully
defending their country from terrorists and barbarians with the use of Western
weapons.</p>
<p>To say that Ukraine should not be given weapons is tantamount to saying that
all of my friends should be dead. And, I suppose, that I should be dead too.
It’s only blind luck that neither cruise missiles nor Shahed drones have
struck a building that I was staying in. Although come to think of it, a
Shahed drone did indeed hit a building where I used to live. Possibly even the
same floor of that building. There have been so many attacks that I don’t
perfectly recall.</p>
<p>And yet, I’ll bet that if I were to use the same phrase at that conference — if
I were to say that I “feel unsafe” — I somehow doubt that my complaint would be
taken seriously. I am — superficially anyway — not a part of the persecuted
class, so violence against me is fine.</p>
]]></description>
    <pubDate>Fri, 15 Nov 2024 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2024/11/I-feel-unsafe/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>
<item>
    <title>Is it c? Or is it с?</title>
    <link>https://jezenthomas.com/2024/07/is-it-c/</link>
    <description><![CDATA[<p>Someone working on the team at Supercede asked the following question
regarding some perplexing GHCi output.</p>
<blockquote>
<p>I must have missed something obvious because I’ve been staring myself blind
at this for the past few minutes. Isn’t it saying one thing is not in scope
and then immediately suggesting that very same thing as a replacement?</p>
</blockquote>
<div class="highlight"><pre><span></span>ghci&gt; :t API.Handler.V20201001.Types.tscaExcluded

&lt;interactive&gt;:1:1-40: error:
    Not in scope: &#39;API.Handler.V20201001.Types.tscaExcluded&#39;
    Perhaps you meant one of these:
      &#39;API.Handler.V20201001.Types.tsсaExcluded&#39; (imported from API.Handler.V20201001.Types),
</pre></div>

<p>Can you spot the error?</p>
<p>The problem could have been related to some surprising behaviour in GHCi when
references are held to old values after their names are shadowed. Or perhaps it
was something related to the build cache since we use incremental compilation.
But those would have been guesses two and three.</p>
<p>Based on experience — and some luck — here was my first guess.</p>
<blockquote>
<p>You know, we had an interesting issue once where a c was substituted for a с.
See the difference?</p>
</blockquote>
<p>Lo and behold…</p>
<blockquote>
<p>Emacs says one is a LATIN SMALL LETTER C and the other is a CYRILLIC SMALL
LETTER ES but I would never have guessed. And would you believe – this is
indeed what has happened. Wow!</p>
</blockquote>
<p>Perhaps this deserves a new linting rule.</p>
]]></description>
    <pubDate>Tue, 16 Jul 2024 00:00:00 UT</pubDate>
    <guid>https://jezenthomas.com/2024/07/is-it-c/</guid>
    <dc:creator>Jezen Thomas</dc:creator>
</item>

    </channel>
</rss>
