<?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>Forem: Jonathan Hall</title>
    <description>The latest articles on Forem by Jonathan Hall (@jhall).</description>
    <link>https://forem.com/jhall</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F287061%2Fec33a650-03c8-4167-970b-8590903f76cb.jpg</url>
      <title>Forem: Jonathan Hall</title>
      <link>https://forem.com/jhall</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jhall"/>
    <language>en</language>
    <item>
      <title>Testify is making your Go tests worse</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Tue, 21 Apr 2026 14:33:25 +0000</pubDate>
      <link>https://forem.com/jhall/testify-is-making-your-go-tests-worse-30nn</link>
      <guid>https://forem.com/jhall/testify-is-making-your-go-tests-worse-30nn</guid>
      <description>&lt;p&gt;Pop quiz.&lt;/p&gt;

&lt;p&gt;Does this &lt;code&gt;testify&lt;/code&gt; assertion pass or fail?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're like me, you have no idea. Arguments for both passing and failing seem reasonable. Let's jump to the docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://pkg.go.dev/github.com/stretchr/testify/assert#Equal" rel="noopener noreferrer"&gt;func Equal&lt;/a&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Equal asserts that two objects are equal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well that's no help. I still don't know if an empty slice is considered equal to a nil slice! To answer the question, I have to dig through the source code, or just try it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is the learning curve worth it?
&lt;/h2&gt;

&lt;p&gt;Assertion libraries are popular in Go, and for a solid reason: they make tests shorter. But in exchange, you're signing up for some hefty costs, which are often overlooked. A few, from the &lt;a href="https://go.dev/wiki/TestComments#assert-libraries" rel="noopener noreferrer"&gt;official Go wiki&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They require developers to learn a whole new sub-language just to read or write tests&lt;/li&gt;
&lt;li&gt;Most assertions abort a test early, omitting potentially useful information from the output&lt;/li&gt;
&lt;li&gt;They hurt expressiveness, both in communicating what is being asserted, and in how you present failures&lt;/li&gt;
&lt;li&gt;They make it easy to write imprecise tests&lt;/li&gt;
&lt;li&gt;They duplicate features already found in the language, such as evaluation, comparison, and often more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And a few more reasons of my own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many assertion libraries are internally inconsistent (&lt;code&gt;testify&lt;/code&gt; is one such example)&lt;/li&gt;
&lt;li&gt;They require a combinatoric explosion of functions to express slight variants on certain checks, which are much easier expressed using first-class language features such as &lt;code&gt;!&lt;/code&gt; or &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Then why is &lt;code&gt;testify&lt;/code&gt; so popular?
&lt;/h2&gt;

&lt;p&gt;If any of these downsides are true, why do assertion libraries remain popular in Go?&lt;/p&gt;

&lt;p&gt;In a word: Habit. In many languages, there is no testing framework provided by the language. This means that to do unit testing, you &lt;em&gt;must&lt;/em&gt; use a third-party tool, and historical momentum has made xUnit-style testing libraries common. So when folks start learning Go, they naturally carry those habits with them, because it's comfortable.&lt;/p&gt;

&lt;p&gt;But Go treats testing as a first-class citizen, shipping with its own testing framework, as well as the &lt;code&gt;testing&lt;/code&gt; package, and related libraries, included in the standard library. So the explicit need for a third-party testing framework isn't there. Is there sufficient reason to still prefer a third-party assertion library? Below are the most common arguments in favor, and why they don't really hold up.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;"It's easier to read."&lt;/strong&gt; — While "readability" is mostly subjective, what's readable is mostly what's familiar. If all else is equal, any convention can be readable if you're familiar with it. As we'll discuss later, though, assertion libraries, in general &lt;em&gt;are not equal&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"It's shorter."&lt;/strong&gt; — While technically true, this is mostly irrelevant. Yes, it makes many assertions shorter, but is that a virtue? Not if it makes them harder to understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"It makes complex comparisons easier."&lt;/strong&gt; — If you're comparing &lt;code&gt;assert.Equal&lt;/code&gt; to a long list of individual struct field comparisons, yes, the assert library is the clear winner on all counts: easier to write, easier to read, easier to reason about.  But there's an alternative that's better than either of these.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Go philosophy
&lt;/h2&gt;

&lt;p&gt;Why does Go do tests differently from so many other languages?&lt;/p&gt;

&lt;p&gt;It's not a dig at other languages. It's a matter of Go's philosophy. Every language prioritizes certain things over others. And one thing Go prioritizes is making things obvious. Go's notoriously verbose error handling is a good example of this principle in action. You've no doubt written &lt;code&gt;if err != nil&lt;/code&gt; more times in the last year than you've written your own postal code in your entire lifetime. And while this is an endless source of annoyance for some, it exists for a reason: It makes it &lt;em&gt;obvious&lt;/em&gt; when an error might occur, and how it's being handled. The common alternative of exceptions, by comparison, makes problems opaque.&lt;/p&gt;

&lt;p&gt;Assertion libraries are to Go's testing philosophy what exceptions are to Go's error handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  An idiomatic Go test
&lt;/h2&gt;

&lt;p&gt;Let's pause to look at what an &lt;em&gt;idiomatic&lt;/em&gt; Go test would actually look like, as a point of reference for the rest of this discussion. Here's what the test from the quiz above might look like, written using only the &lt;code&gt;testing&lt;/code&gt; library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;slices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected x and y to be equal"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, of course, you'll be forgiven if you think this looks less "readable" than the &lt;code&gt;assert&lt;/code&gt; version above. It certainly is more verbose.  But it gives us several improvements over the testify-based version. Let's talk about them.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Readability" FTW
&lt;/h3&gt;

&lt;p&gt;It's time for the big reveal: the &lt;code&gt;assert.Equal(x, y)&lt;/code&gt; call from the quiz will &lt;em&gt;fail&lt;/em&gt;. Testify treats empty and nil slices as unequal.&lt;/p&gt;

&lt;p&gt;In contrast, &lt;code&gt;slices.Equal(x, y)&lt;/code&gt; returns true, so that version of the test will &lt;em&gt;pass&lt;/em&gt;. That's different! Why?&lt;/p&gt;

&lt;p&gt;Well, while &lt;code&gt;assert.Equal&lt;/code&gt;'s precise behavior isn't explicitly documented, &lt;code&gt;slices.Equal&lt;/code&gt;'s is (emphasis added):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://pkg.go.dev/slices#Equal" rel="noopener noreferrer"&gt;func Equal&lt;/a&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func Equal[S ~[]E, E comparable](s1, s2 S) bool
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Equal reports whether two slices are equal: the same length and all elements equal. If the lengths are different, Equal returns false. Otherwise, the elements are compared in increasing index order, and the comparison stops at the first unequal pair. &lt;strong&gt;Empty and nil slices are considered equal.&lt;/strong&gt; Floating point NaNs are not considered equal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now as I said at the top of the post, I can imagine arguments both for and against nil and empty slices being considered equal. And I don't know exactly why the Go team decided that &lt;code&gt;slices.Equal&lt;/code&gt; should treat them as equal—though I suppose that in the context of &lt;em&gt;slice&lt;/em&gt; comparison, for practical purposes, they are generally equal.  But I &lt;em&gt;do&lt;/em&gt; know that I use the &lt;code&gt;slices&lt;/code&gt; package all the time in my code, and knowing how &lt;code&gt;slices.Equal&lt;/code&gt; works is valuable information regardless of how I write my tests.  If I use &lt;code&gt;assert.Equal&lt;/code&gt; in my tests, I have to learn a second set of rules just for my tests.&lt;/p&gt;

&lt;p&gt;Comparing &lt;code&gt;assert.Equal&lt;/code&gt; to &lt;code&gt;slices.Equal&lt;/code&gt; might seem like a nitpick. And if that were the only issue with using an assertion library, it probably would be.  Here are a few other quiz questions for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does calling &lt;code&gt;Contains&lt;/code&gt; on a map check against keys, values, or both?  (answer: keys)&lt;/li&gt;
&lt;li&gt;What's the difference between &lt;code&gt;Equal&lt;/code&gt; and &lt;code&gt;EqualValues&lt;/code&gt;?  (answer: &lt;code&gt;EqualValues&lt;/code&gt; coerces values for comparison)&lt;/li&gt;
&lt;li&gt;How does &lt;code&gt;Empty&lt;/code&gt; treat bool values?  (answer: zero values are considered empty, so false is "empty")&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;testify&lt;/code&gt; is a whole new  language
&lt;/h3&gt;

&lt;p&gt;Of course, &lt;code&gt;testify&lt;/code&gt; doesn't expose just one equality assertion function.  Let's take a &lt;a href="https://pkg.go.dev/github.com/stretchr/testify@v1.11.1/assert#pkg-functions" rel="noopener noreferrer"&gt;quick look at the other equality functions included in the package&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Equal&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EqualError&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EqualExportedValues&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EqualValues&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And most of these have &lt;code&gt;Not*&lt;/code&gt; and &lt;code&gt;*f&lt;/code&gt; variants, for a total of 12 equality assertion functions.&lt;/p&gt;

&lt;p&gt;Oh, but I forgot these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Exactly&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;False&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Nil&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Same&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;True&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Zero&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are &lt;em&gt;also&lt;/em&gt; equality assertions by a different name. That makes a total of 30 functions that all handle subtly different senses of exact equality—effectively wrapping either &lt;code&gt;==&lt;/code&gt; or &lt;code&gt;!=&lt;/code&gt;. And that's to say nothing of the over 100 other assert functions in the library, many of which directly mirror functionality built into the standard library, with slightly different calling conventions; &lt;code&gt;Contains&lt;/code&gt;, &lt;code&gt;DirExists&lt;/code&gt;, and &lt;code&gt;LessOrEqual&lt;/code&gt; to name a few.&lt;/p&gt;

&lt;p&gt;And the language doesn't even agree with itself. &lt;code&gt;Equal&lt;/code&gt; takes &lt;code&gt;(expected, actual)&lt;/code&gt;. &lt;code&gt;EqualError&lt;/code&gt; takes &lt;code&gt;(actual, expected)&lt;/code&gt;. Both are asserting that two things are equal. There's no design reason for the flip. You just have to memorize it, function by function.&lt;/p&gt;

&lt;p&gt;That's &lt;em&gt;a lot&lt;/em&gt; of assertion functions to either memorize, or be constantly looking up, every time you write or read a test.  Is it &lt;em&gt;really&lt;/em&gt; easier to read something that requires looking up vocabulary in the dictionary all the time?&lt;/p&gt;

&lt;h3&gt;
  
  
  Okay, but what about complex data structures?
&lt;/h3&gt;

&lt;p&gt;Nobody wants to read or write this test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"Alice"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Expected Name = Alice, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Expected Age = 30, got %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"alice@example.com"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Expected Email = alice@example.com, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreatedAt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;January&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Expected CreatedAt = 2020-01-01, got %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreatedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of the most common objections I hear when presenting about avoiding assertion libraries. "So the Go wiki says to avoid assert libraries, but I don't want to write 50 lines of boilerplate code to test my structs!"  Fair criticism!  But the Go wiki &lt;a href="https://go.dev/wiki/TestComments#compare-full-structures" rel="noopener noreferrer"&gt;also says something else&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your function returns a struct, don’t write test code that performs an individual comparison for each field of the struct. Instead, construct the struct that you’re expecting your function to return, and compare in one shot using diffs or deep comparisons. The same rule applies to arrays and maps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sounds like a valuable thing that assertion libraries actually provide! But can we get that value without the weight of an assertion library?  Sure!  &lt;a href="https://pkg.go.dev/github.com/google/go-cmp/cmp#Diff" rel="noopener noreferrer"&gt;&lt;code&gt;cmp.Diff&lt;/code&gt;&lt;/a&gt; is the tool that the Go wiki suggests for just this problem. And not only does it replace the one-shot, deep-equality checks of most assertion libraries, it does it with a &lt;em&gt;lot&lt;/em&gt; more flexibility!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cmp.Diff&lt;/code&gt; is part of the &lt;a href="https://pkg.go.dev/github.com/google/go-cmp/cmp#Diff" rel="noopener noreferrer"&gt;&lt;code&gt;github.com/google/go-cmp/cmp&lt;/code&gt;&lt;/a&gt; package, from Google. It's not part of the standard library (at least not yet, though it has been considered for inclusion), but it is from Google, and is officially recommended by the Go team.&lt;/p&gt;

&lt;p&gt;So how does it work? Let's illustrate by revisiting our original quiz example one more time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"expected x and y to be equal, diff: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this version of the test, &lt;code&gt;cmp.Diff&lt;/code&gt; returns a textual diff representation of the difference between the two arguments.  In this case, it returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;   &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;   &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-&lt;/code&gt; line is the first argument (&lt;code&gt;x&lt;/code&gt;, our nil slice), and the &lt;code&gt;+&lt;/code&gt; line is the second (&lt;code&gt;y&lt;/code&gt;, the empty slice). One line, one type label, one difference called out. So now we're back to &lt;code&gt;testify&lt;/code&gt;'s semantics—treating nil and empty as distinct.  But remember  when I said &lt;code&gt;cmp.Diff&lt;/code&gt; is flexible?  We can instruct it to treat empty and nil slices as equal, if that's the correct behavior for our application. Just one line changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmpopts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EquateEmpty&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And beyond that, the &lt;code&gt;cmpopts&lt;/code&gt; package provides the ability to ignore specific fields, do approximate time-matching, and a ton of other useful options. It even lets you write your own custom comparison functions, when you really need to get into the details.&lt;/p&gt;

&lt;h2&gt;
  
  
  The exception to the rule
&lt;/h2&gt;

&lt;p&gt;Having made the case against using &lt;code&gt;testify&lt;/code&gt;, I have a confession to make: I was writing tests with &lt;code&gt;testify&lt;/code&gt; just this morning.&lt;/p&gt;

&lt;p&gt;That's because there's one specific case where I see using &lt;code&gt;testify&lt;/code&gt;, or other assertion libraries, as justifiable:  You're writing code for a team whose established convention dictates it.&lt;/p&gt;

&lt;p&gt;One of my clients uses &lt;code&gt;testify&lt;/code&gt; for their tests. Now, I could use the idiomatic Go approach when adding tests to their codebase. And maybe the individual tests would be better as a result. But the project as a whole would suffer. Rather than a single, coherent testing style, there would be two conflicting styles. If my goal is to reduce the burden of reading tests, consistently using &lt;code&gt;testify&lt;/code&gt; is clearly better than using an alternative half of the time. That's what I was doing this morning.&lt;/p&gt;

&lt;p&gt;Unless the team has decided to migrate from one test style to another, I'd rather adhere to established convention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going deeper
&lt;/h2&gt;

&lt;p&gt;Writing idiomatic tests in Go is a lot more than just avoiding &lt;code&gt;testify&lt;/code&gt;. How do you avoid the overuse of mocks? How do you test code that calls a live, third-party service? How can you avoid hard-coded sleeps when testing concurrency?  Is there any way to avoid flaky tests that depend on the clock? If these are topics you'd like me to help you explore, I'd like to invite you to join my live 6-week course, &lt;strong&gt;Idiomatic Testing in Go&lt;/strong&gt;, starting May 5. It's a small group: 15 seats, weekly 90-minute sessions, and I review your actual test code each week. Early bird enrollment ends April 28.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/idiomatic-testing/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=launch&amp;amp;utm_content=testify_post"&gt;See the syllabus and reserve your seat&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
    </item>
    <item>
      <title>Three things that can go before a package clause in Go</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Mon, 14 Oct 2024 23:09:12 +0000</pubDate>
      <link>https://forem.com/jhall/three-things-that-can-go-before-a-package-clause-in-go-39b</link>
      <guid>https://forem.com/jhall/three-things-that-can-go-before-a-package-clause-in-go-39b</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is an &lt;a href="https://boldlygo.tech/archive/2024-10-14-packages/" rel="noopener noreferrer"&gt;excerpt&lt;/a&gt; from my email list, &lt;strong&gt;Boldy Go: Daily&lt;/strong&gt;. &lt;a href="https://boldlygo.tech/daily/" rel="noopener noreferrer"&gt;Join for more content like this every day&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you’ve done any Go coding at all, you’ve seen at least one package clause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you probably know that it comes at the top of each Go source file.&lt;/p&gt;

&lt;p&gt;But did you know there are three other things that &lt;em&gt;may&lt;/em&gt; come first?  Let's look at all three:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Comments, including GoDoc. It's good practice to include a descriptive GoDoc paragraph &lt;em&gt;immediately&lt;/em&gt; before the &lt;code&gt;package&lt;/code&gt; clause (i.e. with no blank lines between). You need only do this in a single file (in case of a multi-file package).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Package foo Foos all the Bars.&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build constraints and other directives (these are treated as comments, but are worth mentioning separately).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//go:build !js&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In this example, we tell the compiler to ignore this file when building for a JS target (i.e. WebAssembly or GopherJS).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A shebang line (only as the very first line of the file).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="o"&gt;!/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;What?!&lt;/p&gt;

&lt;p&gt;Didn't know that was possible?&lt;/p&gt;

&lt;p&gt;This actually isn't a Go thing at all, it's more a shell thing. But all common Unix/Linux shells will recognize such a line, and interpret it as the name of an interpretor to pass the file to.  You really should not ever need this in Go, but some folks have fun writing Go for shell-script types of tasks. If that describes you, this will apply. I included this here mostly for completeness sake, not as an endorsement of this approach. 😉&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What if we put all three together, just for fun?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="o"&gt;!/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;

&lt;span class="c"&gt;// this comment does nothing special. It's not GoDoc, becuase&lt;/span&gt;
&lt;span class="c"&gt;// there's no package clause or declaration on the next line,&lt;/span&gt;
&lt;span class="c"&gt;// and it's not a build constraint.&lt;/span&gt;

&lt;span class="c"&gt;//go:build !js&lt;/span&gt;

&lt;span class="c"&gt;//go:generate /path/to/utility&lt;/span&gt;

&lt;span class="c"&gt;// Package main is a utility that does something interesting.&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>go</category>
      <category>shell</category>
    </item>
    <item>
      <title>Don't panic!</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Thu, 28 Mar 2024 08:56:18 +0000</pubDate>
      <link>https://forem.com/jhall/dont-panic-3g09</link>
      <guid>https://forem.com/jhall/dont-panic-3g09</guid>
      <description>&lt;p&gt;&lt;em&gt;This post comes from my daily email list: Boldly Go! Daily. &lt;a href="https://boldlygo.tech/daily"&gt;Sign up to learn a bit more about Go every day!&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;Don’t panic.&lt;/p&gt;

&lt;p&gt;Don’t panic is such ubiquitous Go advice that it’s one of the famous &lt;a href="https://go-proverbs.github.io/"&gt;Go proverbs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So why do we have a built-in &lt;code&gt;panic&lt;/code&gt; function if we’re not supposed to use it?&lt;/p&gt;

&lt;p&gt;Well, it’s not so much that it’s never appropriate to use, as much as it’s often heavily overused. Especially by programmers who are accustomed to using exceptions and try/catch blocks to manage control flow.&lt;/p&gt;

&lt;p&gt;Don’t do that!&lt;/p&gt;

&lt;p&gt;At the moment I’m helping one client with a massive refactor of their application to remove the problematic, non-idiomatic pattern of using &lt;code&gt;panic&lt;/code&gt; rather than proper Go error handling.&lt;/p&gt;

&lt;p&gt;I’m sure we’ll talk a lot more about this in the future, but probably the most important reason not to panic is that it’s very non-obvious. This problem exists in languages that uses exceptions for error handling, too (and is why Go’s design doesn’t encourage this pattern). Consider this code (taken from the above mentioned client’s code base, with names edited to protect the innocent):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CreateRecordWithIDAndType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;typ&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;userID&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;appctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticatedUserIdOptional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;userID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;recordReq&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;RecordRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ActionRequest&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ActionRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;learnType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;CreateRecordWithCDP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recordReq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the question: Can the call to &lt;code&gt;CreateRecordWithCDP&lt;/code&gt; result in an error condition?&lt;/p&gt;

&lt;p&gt;It’s impossible to be sure. Although we have one strong clue: It accepts a &lt;code&gt;context.Context&lt;/code&gt; value, which is often, though not always, an indication that the function call may block, and be terminated early if the context is cancelled. This would suggest that an error state is possible. Although the context could just be used to read a value, in which case it may legitimately not be possible for &lt;code&gt;CreateRecordWithCDP&lt;/code&gt; to result in an error condition. It also doesn’t return anything, so whatever it’s “creating”, presumably is stored somewhere–probably in a database. And database operations, as a rule, can err.&lt;/p&gt;

&lt;p&gt;In any case, since we don’t know, we’re forced to either investigate &lt;code&gt;CreateRecordWithCDP&lt;/code&gt; (and any functions it calls) to determine if it might panic, or just play it safe, and add a deferred &lt;code&gt;recover&lt;/code&gt; before we call it.&lt;/p&gt;

&lt;p&gt;Wouldn’t it be much easier if we had some obvious indication? Perhaps like this new version?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CreateRecordWithIDAndType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;typ&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;userID&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;appctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticatedUserIdOptional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;userID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;recordReq&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;RecordRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ActionRequest&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ActionRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;learnType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CreateRecordWithCDP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recordReq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This make the fact that calling &lt;code&gt;CreateRecordWithCDP&lt;/code&gt; (and in turn &lt;code&gt;CreateRecordWithIDAndType&lt;/code&gt;) can result in an error condition. And it makes programming to use these functions much simpler, and eliminates a lot of guesswork.&lt;/p&gt;

&lt;p&gt;Of course, this does lead to the situation many complain about, of cluttering your code with &lt;code&gt;if err != nil { ... }&lt;/code&gt;. But IMO, while this is a bit annoying to type, typing is a very small price to pay for the clarity it provides.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Error handling in Go web apps shouldn't be so awkward</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Wed, 10 Jan 2024 15:18:21 +0000</pubDate>
      <link>https://forem.com/jhall/error-handling-in-go-web-apps-shouldnt-be-so-awkward-4e2k</link>
      <guid>https://forem.com/jhall/error-handling-in-go-web-apps-shouldnt-be-so-awkward-4e2k</guid>
      <description>&lt;p&gt;In this post I’m going to describe an error-handling pattern I’ve found to be fairly elegant when writing REST, gRPC, or other services in Go. I have three goals in writing this post:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To explain the pattern I’ve implemented for a few clients, so that others developing on the same codebase will understand it.&lt;/li&gt;
&lt;li&gt;To give others a pattern they may wish to implement in their own applications.&lt;/li&gt;
&lt;li&gt;To solicit feedback. Is there a better pattern out there I haven’t seen yet? Are there tweaks I can make to this pattern to make it better?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Before I explain the pattern I use, let me explain what it replaces, so that we might understand the problems it's meant to solve.&lt;/p&gt;

&lt;p&gt;Let's look at a simple HTTP handler, using the standard library's &lt;a href="https://pkg.go.dev/net/http#HandlerFunc"&gt;HandlerFunc&lt;/a&gt; pattern, which simply fetches a widget record from the database, and serves it to the client as JSON&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseForm&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"widget_id"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrNoRows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;widgetJSON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widgetJSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this should be a more or less realistic example, it's intentionally over-simplified from what I typically find in production services. In particular, I've never seen &lt;a href="https://pkg.go.dev/net/http#Error"&gt;&lt;code&gt;http.Error&lt;/code&gt;&lt;/a&gt; used in a real service. Much more likely, you'll have a custom error format you want to send back. Possibly utilizing a JSON error response, with some additional error context or internal error codes, etc.  Or maybe you want to render the error as HTML. In any case, I'll assume your app replaces the &lt;code&gt;http.Error()&lt;/code&gt; call with something more sophisticated. Which likely means your code is even more annoying and repetitive than what I've shown above.&lt;/p&gt;

&lt;p&gt;That aside, let me call out a few specific problems I see with the above code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The error handling is repetitive, and non-idiomatic.  Go is (in)famous for its &lt;code&gt;if err != nil { return err }&lt;/code&gt; idiom. Yet we can't even use &lt;em&gt;that&lt;/em&gt; here, because the &lt;a href="https://pkg.go.dev/net/http#HandlerFunc"&gt;HandlerFunc&lt;/a&gt; signature doesn't return an error.  Instead, for every error, we must (a) serve the error, and separately (b) return.&lt;/li&gt;
&lt;li&gt;We must explicitly handle the HTTP status for every error case. If you have dozens or hundreds of handlers (and you probably do), this quickly becomes repetitive, and error-prone. There's no DRY here. In a single handler like this, maybe it's not a big deal. But it would be nice if we had some sort of default HTTP status code for an error—probably 500 / Internal Server Error.&lt;/li&gt;
&lt;li&gt;This handler has to concern itself with database internals. In particular, it checks whether we received a &lt;a href="https://pkg.go.dev/database/sql#pkg-variables"&gt;&lt;code&gt;sql.ErrNoRows&lt;/code&gt;&lt;/a&gt; error. The HTTP handler should be completely database agnostic, so this detail should not need to be exposed here. This is some ugly tight-coupling we can get rid of.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What if, instead...
&lt;/h2&gt;

&lt;p&gt;What if, instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for every error, we could simply &lt;code&gt;return err&lt;/code&gt;, and the right thing would happen? The error would be rendered to the proper format, and sent to the user?&lt;/li&gt;
&lt;li&gt;the magic that renders the error would know the proper HTTP status to set, too?  400 for invalid input, 404 for not found, 401 for unauthorized access, etc?&lt;/li&gt;
&lt;li&gt;the data store, whether an SQL database, or MongoDB, or the filesystem, would just tell us "this error means not found", and that could be automatically converted to a 404 instead of the handler knowing the implementation details?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern I'm about to describe gives us all of these things. Not only that, but it enables a number of other emergant patterns which are quite powerful as well. I'll mention some of them at the end, and may write more extensively about some of them later on (let me know if that would interest you).&lt;/p&gt;

&lt;h2&gt;
  
  
  Idiomatic error handling
&lt;/h2&gt;

&lt;p&gt;The three behaviors I've described that we want all depend on two things, the first of which is "idiomatic error handling".  We need to be able to simply &lt;code&gt;return err&lt;/code&gt; in our handlers.  Unfortunately, the standard libray doesn't give us this.  But some third-party frameworks do. The most popular one I'm familiar with is &lt;a href="https://echo.labstack.com/"&gt;labstack echo&lt;/a&gt;, whose &lt;a href="https://pkg.go.dev/github.com/labstack/echo/v4#HandlerFunc"&gt;&lt;code&gt;HandlerFunc&lt;/code&gt;&lt;/a&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HandlerFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I don't believe you should need to adopt a heavy framework like Echo just to get handy error-handling primitives.  So you can do this yourself.  Here's a simple adapter function pattern you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// customHandler converts an error-returning handler to a standard http.HandlerFunc.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;customHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Wait, alwyas 500? More on that later&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With such an adapter function, our earlier handler gets simplified to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseForm&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"widget_id"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;widgetJSON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widgetJSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course this requires that we actually &lt;em&gt;use&lt;/em&gt; the adapter function when setting up our routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/widget"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course we've also actually &lt;em&gt;broken&lt;/em&gt; this endpoint. It now treats &lt;em&gt;all&lt;/em&gt; errors as internal server errors. So we'll address that next.&lt;/p&gt;

&lt;h2&gt;
  
  
  But first, an experiment I'm working on
&lt;/h2&gt;

&lt;p&gt;But before we do, I want to call out an experimental library I'm working on, with the hope it may eventually become an official proposal to the standard library (although I think it's a long shot it would be accepted) to extend the definition of the &lt;a href="https://pkg.go.dev/net/http#HandlerFunc"&gt;&lt;code&gt;http.HandlerFunc&lt;/code&gt;&lt;/a&gt; type to include an optional error return value. The library is &lt;a href="https://pkg.go.dev/gitlab.com/flimzy/httpe"&gt;gitlab.com/flimzy/httpe&lt;/a&gt;, and it adds -&lt;code&gt;WithError&lt;/code&gt; variants to &lt;code&gt;http.Handler&lt;/code&gt;, &lt;code&gt;http.HandlerFunc&lt;/code&gt;, &lt;code&gt;ServeHTTP&lt;/code&gt;, and related middlewares.  It's based on work I've been using for years with clients, but now living in its own stand-alone library for easy inclusion, if you wish.&lt;/p&gt;

&lt;p&gt;If you choose to use this library, the new version of the handler remains unchanged, but in places of calling &lt;code&gt;customHandler&lt;/code&gt;, you could do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"gitlab.com/flimzy/httpe"&lt;/span&gt;

&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/widget"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main advantage to the &lt;code&gt;httpe&lt;/code&gt; library over your own custom handler is that it provides support for middleware adapters, and inter-mixing standard and error-enabled handlers, with some behind-the-scenes error propagation. But that's beyond the scope of this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to handle different HTTP statuses
&lt;/h2&gt;

&lt;p&gt;The second thing these improvements depends on is some way to specify an HTTP status. We've observed that while this new handler pattern makes error handling &lt;em&gt;simpler&lt;/em&gt;, it also breaks it, by treating all errors as 500 / Internal Server Error (or whatever arbitrary status you set in your &lt;code&gt;customHandler&lt;/code&gt; function).  Let's address that now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Errors are interfaces
&lt;/h3&gt;

&lt;p&gt;Recall that in Go, the &lt;code&gt;error&lt;/code&gt; type is an interface type, define as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is powerful, because it means we can create our own custom error types. And what's more, for our purposes, we can &lt;em&gt;extend&lt;/em&gt; the error type to include other methods.&lt;/p&gt;

&lt;p&gt;We want to take advantage of both of these capabilities to create a custom error type that includes an HTTP status, and add a method to expose that status.  Here's the simple custom type we'll be using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now already this is a "complete" error type. It already satisfies the &lt;code&gt;error&lt;/code&gt; interface by virtue of embedding the &lt;code&gt;error&lt;/code&gt; type (so its methods are promoted to our type's methods). And it includes a status code.  But we need a couple more pieces to make this complete.  First, let's add an &lt;code&gt;Unwrap&lt;/code&gt; method, to allow &lt;a href="https://pkg.go.dev/errors#Unwrap"&gt;&lt;code&gt;errors.Unwrap&lt;/code&gt;&lt;/a&gt; and the related &lt;a href="https://pkg.go.dev/errors#Is"&gt;&lt;code&gt;errors.Is&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://pkg.go.dev/errors#As"&gt;&lt;code&gt;errors.As&lt;/code&gt;&lt;/a&gt;, etc, to work properly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we also want to add a method to expose the included status.  Strictly speaking, this isn't &lt;em&gt;necessary&lt;/em&gt;.  You &lt;em&gt;can&lt;/em&gt; get at the status code by type-converting an error back to the &lt;code&gt;statusError&lt;/code&gt; type with a type assertion, or with the use of &lt;code&gt;errors.Is&lt;/code&gt; or &lt;code&gt;errors.As&lt;/code&gt;. But it's a bit cubersome, and requires exporting the field (unless your entire application is in a single package--I sure hope that's not the case!) Further, by exposing the status via an interface method, we have the freedom to use multiple implementations of our custom error type, which is something I virtually always do.  So let's add that detail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you could name your method whatever you want. I've settled on &lt;code&gt;HTTPStatus&lt;/code&gt;, after initially using simply &lt;code&gt;Status()&lt;/code&gt;, because it's less ambiguous, but still short enough not to be annoying.  You can just as eaisly use any other method (or multiple methods).  For example, maybe you want &lt;code&gt;JSONRPCStatus()&lt;/code&gt; if you're building a JSON-RPC service. Or if you're building a gRPC service, there's already an interface defined for you: &lt;code&gt;GRPCStatus() *status.Status&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using our custom error type
&lt;/h2&gt;

&lt;p&gt;Now that we have our &lt;code&gt;statusError&lt;/code&gt; type, let's incorporate it into our handler, to un-break our status code handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseForm&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"widget_id"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;widgetJSON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widgetJSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now we've (mostly) unbroken our status codes.  The one exception is the database call. We treat all errors as status 500, when we should treat a missing widget as 404.  The solution here is to make our data access layer aware of these new error types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="c"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrNoRows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNotFound&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One last thing: We need to update our &lt;code&gt;customHandler&lt;/code&gt; to understand this new error type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// customHandler converts an error-returning handler to a standard http.HandlerFunc.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;customHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
            &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;statusErr&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;error&lt;/span&gt;
                &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;statusErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statusErr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay... so now we're back to a fully-functional widget handler.  And we've also decoupled our databaes logic from our HTTP handler. So that's a win.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further improvments
&lt;/h2&gt;

&lt;p&gt;But our handler is still kind of ugly, with a bunch of repeated &lt;code&gt;customErrror{}&lt;/code&gt; structs. We also have both our handler and our data access layer depending on a concrete &lt;code&gt;statusError&lt;/code&gt; type. Which isn't even exported, which implies that our data access layer and handler are in the same package. Ick. We really don't want that.  So let's move our custom error type to its own package. And we'll add a convenient and descriptive constructor function, as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;apperr&lt;/span&gt; &lt;span class="c"&gt;// Use a descriptive name&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WithHTTPStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;statusError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our handler can be updated to the slightly more readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseForm&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;apperr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"widget_id"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;apperr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="c"&gt;// No call to apperr.WithStatus here, as we trust the db has already set the appropriate status code for us&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;widgetJSON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;apperr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widgetJSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting a default status
&lt;/h2&gt;

&lt;p&gt;We can do one other big improvement to this setup: Setting a default status.&lt;/p&gt;

&lt;p&gt;In fact, you may have noticed that our improved &lt;code&gt;customHandler&lt;/code&gt; func &lt;em&gt;has no default status&lt;/em&gt;. This means that if we pass it an error that doesn't include an HTTP status, it will try to serve an HTTP response with status of &lt;code&gt;0&lt;/code&gt;. Probably not ideal.&lt;/p&gt;

&lt;p&gt;Let's solve this problem by adding a helper function to our &lt;code&gt;apperr&lt;/code&gt; package, which can also be used from other places:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;apperr&lt;/span&gt;

&lt;span class="c"&gt;// HTTPStatus returns the HTTP status included in err. If err is nil, this&lt;/span&gt;
&lt;span class="c"&gt;// function returns 0. If err is non-nil, and does not include an HTTP status,&lt;/span&gt;
&lt;span class="c"&gt;// a default value of [net/http.StatusInternalServerError] is returned.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;statusErr&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;error&lt;/span&gt;
        &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;statusErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;statusErr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this new function in our pocket, our custom handler can be simplified and improved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// customHandler converts an error-returning handler to a standard http.HandlerFunc.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;customHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;apperr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our handler can also be improved by omitting the call to &lt;code&gt;apierr.WithStatus&lt;/code&gt; when we want the default status of 500 / Internal Server Error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further improvements
&lt;/h2&gt;

&lt;p&gt;This is really only the beginning of what using an app-wide standard error extension and matching handlers can provide.&lt;/p&gt;

&lt;p&gt;The next areas I usually improve on apps where I implement this pattern is to add a couple standard middlewares:&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging middleware
&lt;/h3&gt;

&lt;p&gt;A middleware to log, with an associated error, if relevant, is a great addition. And it eliminates the "need" to log an error every time it happens--just pass it to your caller, and let the middleware log it for you.  Here's a simplified example, using the function signatures in &lt;a href="https://pkg.go.dev/gitlab.com/flimzy/httpe"&gt;gitlab.com/flimzy/httpe&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;loggingMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithErrorFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTPWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apperr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"request served with error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"request served"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that a handler can still call &lt;code&gt;w.WriteHeader&lt;/code&gt; with a status distinct from that contained in &lt;code&gt;err&lt;/code&gt; (or even in the absence of an error). So a robust implementation will check for that as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error-serving middleware
&lt;/h3&gt;

&lt;p&gt;An improvement over the &lt;code&gt;customHandler&lt;/code&gt; function shown above, is to move the error serving into a middleware.  This does require the &lt;code&gt;httpe&lt;/code&gt; package, or a similar implemenatation, that can work with middlewares.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;serveErrors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithErrorFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTPWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;apperr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Panc-recovery middleware
&lt;/h3&gt;

&lt;p&gt;Most web apps have this (or they should!), but a version that works with error-returning handlers can be nice, as it just has to convert panics to errors, rather than serving them directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;serveErrors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;httpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerWithErrorFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
                    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%v"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTPWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Domain-specific error codes
&lt;/h2&gt;

&lt;p&gt;What's better than having your entire application set HTTP statuses on errors all over the place, is to define your own domain-specific error codes. For a small, web-only app, maybe HTTP status codes are sufficient, but in most real-world apps, they aren't.  Everything else about this pattern can still be used with your own domain-specific error codes.  Simply make your custom error types also return the appropriate HTTP (or JSON-RPC or gRPC or whatever...) codes as well. After such a change, our above database method might look more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="c"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrNoRows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;apperror&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrWidgetNotFound&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the various callers can do their own error inspection, as appropriate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;internalCode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;apperror&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// The internal error code&lt;/span&gt;

&lt;span class="n"&gt;httpStatus&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;apperror&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// The HTTP status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I leave the exact implementation of &lt;code&gt;apperror.ErrWidgetNotFound&lt;/code&gt; and the associated functions as an exercise for the reader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;This approach doesn't come without some drawbacks. It's worth calling a few of them out.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It's non-standard.  Obviously. There's a cost in verbosity to be paid to convert from an error-returning handler to a standard handler.  Although it seems many people are happy to pay this cost, in the form of adopting a heavy framework that offers this benefit (along with others, of course).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are now &lt;em&gt;two&lt;/em&gt; ways to send responses to the client.  This annoys me.  But I have yet to find any way around it. And in practice, it doesn't seem to be a big problem, but it does require keeping it in mind.  You can set the HTTP status of a resonse &lt;em&gt;either&lt;/em&gt; by calling &lt;code&gt;w.WriteHeader()&lt;/code&gt;, &lt;em&gt;or&lt;/em&gt; by returning an error.  Each response can have only a single status, obviously.  And if you call &lt;code&gt;w.WriteHeader()&lt;/code&gt;, that one generally takes precident (unless you've implemented your own &lt;code&gt;http.ResponseWriter&lt;/code&gt; with different behavior).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It makes certain behaviors implicit. Or at least it can. As an example, the shown &lt;code&gt;apperr.HTTPStatus()&lt;/code&gt; function returns a default status for errors that don't contain a status. While I believe this makes good sense, and is a benefit, it is a bit "magical", and may surprise someone who's not familiar with the pattern at play.  It can also be confusing to see &lt;code&gt;apperr.WithStatus(err, http.StatusNotFound)&lt;/code&gt; the first time. While it should be apparent upon plain reading that it's including an HTTP status with an error, it's not apparent what other code consumes that status, or how its used.  Of course, the purpose of this post is to help solve this drawback.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Other limitations
&lt;/h2&gt;

&lt;p&gt;This is by no means a one-size-fits-all solution.  A couple of obvious limitations I have run into on various applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It doesn't provide any ergonomic way to specify a non-200, non-error status (such as 201). For this, you still must fall back on &lt;code&gt;w.WriteHeader()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Some applications would be better served with a function signature such as &lt;code&gt;func(*http.Request) (any, error)&lt;/code&gt;, such that a response (likely to be renderd as JSON) is the first return argument.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;I mentioned at the outset that this pattern tends to lend itself to additional improvements. Let me just mention a few, without going into detail here.  If you'd like a longer explanation on any of these, &lt;a href="https://boldlygo.tech/contact"&gt;let me know&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Include additional metadata in errors. Stack traces are an obvious one, which is nicely provided by &lt;a href="https://pkg.go.dev/github.com/pkg/errors"&gt;&lt;code&gt;github.com/pkg/errors&lt;/code&gt;&lt;/a&gt;, for example. Expand your logging middleware to extract the stack trace and include it in logs.&lt;/li&gt;
&lt;li&gt;Hide error messages for certain HTTP statuses. I typically write my error-serving middleware to return simply &lt;code&gt;Internal Server Error&lt;/code&gt; to the client any time there's a 500 status, to avoid the risk of potentially reporting sensitive information, which can happen in some unsanitized errors. HTTP statuses 401 and 403 are also good candidates for this.&lt;/li&gt;
&lt;li&gt;Similar to obscuring certain errors, maybe you want to expose a user-friendly version of an error message to the users of your app, while logging the nitty gritty details that the error originally included. Add a &lt;code&gt;Public() string&lt;/code&gt; method to such errors, and send the &lt;code&gt;Public()&lt;/code&gt; version to your users, and the &lt;code&gt;Error()&lt;/code&gt; version to your logs.&lt;/li&gt;
&lt;li&gt;HTTP statuses not detailed enough for you? Maybe you need to distinguish between &lt;code&gt;widget not found&lt;/code&gt; and &lt;code&gt;user not found&lt;/code&gt;? You can create your own internal error status/codes, for use internally, which resolve to a common HTTP status.&lt;/li&gt;
&lt;li&gt;Look for ways to DRY up your code. For example, from the handler example, consider moving the call to &lt;code&gt;r.ParseForm&lt;/code&gt; and &lt;code&gt;strconv.Atoi&lt;/code&gt; to a common function—or use a validation library such as &lt;a href="https://pkg.go.dev/github.com/go-playground/validator/v10"&gt;github.com/go-playground/validator/v10&lt;/a&gt; in place of &lt;code&gt;strconv&lt;/code&gt; calls—which returns an error with 400 status.  Then your handler can just pass that error through.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What other use cases have you seen, or can you think of? &lt;a href="https://boldlygo.tech/contact"&gt;I'd love to hear from you&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is there a better way?
&lt;/h2&gt;

&lt;p&gt;I don't know.&lt;/p&gt;

&lt;p&gt;I'm always on the lookout for a better way to do things.&lt;/p&gt;

&lt;p&gt;If you know of a better pattern, or even small ways I can improve on this pattern, please, let me know! I'd love to learn from you!&lt;/p&gt;




&lt;p&gt;Banner image by &lt;a href="https://www.flickr.com/photos/ian_munroe/3848413116"&gt;ian munroe&lt;/a&gt;, &lt;a href="https://creativecommons.org/licenses/by/2.0/"&gt;CC-BY-2.0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>rest</category>
    </item>
    <item>
      <title>I'm going back to school, Live</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Mon, 16 Oct 2023 12:31:50 +0000</pubDate>
      <link>https://forem.com/jhall/im-going-back-to-school-live-g2d</link>
      <guid>https://forem.com/jhall/im-going-back-to-school-live-g2d</guid>
      <description>&lt;p&gt;I’m going back to school. And you’re invited along.&lt;/p&gt;

&lt;p&gt;Specifically, I’m preparing to go through &lt;a href="https://www.boot.dev/"&gt;boot.dev&lt;/a&gt;’s online course, “Learn Web Servers”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_WxMK9dC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwoo9pypkoh0yrwq7m76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_WxMK9dC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwoo9pypkoh0yrwq7m76.png" alt="Image description" width="800" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Boot.dev is building the smartest way to master backend development by tackling the hardest problem with e-learning: boredom. The platform uses tactics learned from modern game design to push ambitious students toward their goal: a career in backend development. Through hands-on lessons that balance theory with practice, and an active Discord community, students are prepared to tackle technical interviews and forge a successful programming career.&lt;/p&gt;

&lt;p&gt;It offers courses in Python, a wee bit of JavaScript, and most important, obviously… &lt;em&gt;Go!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you’re new to Go or web servers, this will be an easy introduction to the concepts, and a chance to ask questions as you watch me make mistakes.&lt;/p&gt;

&lt;p&gt;Save the link, and be sure to subscribe to the &lt;a href="https://www.youtube.com/@boldlygo"&gt;Boldly Go youtube channel&lt;/a&gt;. I'll be going live in just a half an hour!&lt;/p&gt;

&lt;p&gt;Or if you're reading this in the future, of course you can still watch the replay.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/kwQ5npugi8Y"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I hope to see you there!&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>backend</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>Resolving type parameter ambiguities</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Thu, 03 Aug 2023 07:41:38 +0000</pubDate>
      <link>https://forem.com/jhall/resolving-type-parameter-ambiguities-4bol</link>
      <guid>https://forem.com/jhall/resolving-type-parameter-ambiguities-4bol</guid>
      <description>&lt;p&gt;I stumbled upon a bit of a WTF in the &lt;a href="https://go.dev/ref/spec"&gt;Go Specification&lt;/a&gt;, while writing my &lt;a href="https://boldlygo.tech/daily/"&gt;daily Go email&lt;/a&gt; and had to dig in a bit to make sense of it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://go.dev/ref/spec#Type_parameter_declarations"&gt;Type parameter declarations&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;…&lt;/p&gt;

&lt;p&gt;A parsing ambiguity arises when the type parameter list for a generic type declares a single type parameter P with a constraint C such that the text P C forms a valid expression:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type T[P *C] …
type T[P (C)] …
type T[P *C|Q] …
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SN48glEE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bs7za8ydw04adpmwar0r.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SN48glEE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bs7za8ydw04adpmwar0r.gif" alt="Image description" width="498" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re up for it, I’ll try to break this thing down. If you’re not up for it, no worries. See you later! 👋😆&lt;/p&gt;

&lt;p&gt;Let’s consider the first example provided: &lt;code&gt;type T[P *C] …&lt;/code&gt;. How can this be ambiguous?&lt;/p&gt;

&lt;p&gt;Well, it looks like an array type declaration, where the array length is derrived from a constant expression, such as in this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="c"&gt;// T is of type [12]int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other expressions are possible, too, which is what leads to this possible ambiguity.&lt;/p&gt;

&lt;p&gt;So, we need a way to solve this WTF scenario, and Go gives us two of them…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In these rare cases, the type parameter list is indistinguishable from an expression and the type declaration is parsed as an array type declaration. To resolve the ambiguity, embed the constraint in an interface or use a trailing comma:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type T[P interface{*C}] …
type T[P *C,] …
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;So either wrap your constraint in &lt;code&gt;interface{…}&lt;/code&gt;, or add a magical comma at the end. &lt;em&gt;Poof!&lt;/em&gt; problem solved.&lt;/p&gt;

&lt;p&gt;But still. WTF?!&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Building a Go linter from scratch</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Mon, 31 Jul 2023 08:47:50 +0000</pubDate>
      <link>https://forem.com/jhall/building-a-go-linter-from-scratch-454g</link>
      <guid>https://forem.com/jhall/building-a-go-linter-from-scratch-454g</guid>
      <description>&lt;p&gt;🤔 Ever wonder how linters work in Go? ❓&lt;/p&gt;

&lt;p&gt;In my latest video, I go through Denis Isaev's tutorial "Writing Useful go/analysis Linter", to learn how to build a linter myself to learn what's involved.  Follow along and see if you can learn something, too...&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ycU-GXL_ix4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>The 10 best Go versions, ranked</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Thu, 27 Jul 2023 07:29:48 +0000</pubDate>
      <link>https://forem.com/jhall/the-10-best-go-versions-ranked-22gl</link>
      <guid>https://forem.com/jhall/the-10-best-go-versions-ranked-22gl</guid>
      <description>&lt;p&gt;Go 1.21 is just around the corner, which will be the 22nd major Go release to date. So I thought it would be a good time to look back on the best Go releases we've had to date.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ay4nCpbOuko"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Go Lexical elements: Rune literals pt 3</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Sun, 09 Jul 2023 06:00:00 +0000</pubDate>
      <link>https://forem.com/jhall/go-lexical-elements-rune-literals-pt-3-24o3</link>
      <guid>https://forem.com/jhall/go-lexical-elements-rune-literals-pt-3-24o3</guid>
      <description>&lt;p&gt;Let’s continue our disection of &lt;code&gt;rune&lt;/code&gt; literals. If you missed the parts, check them out from &lt;a href="https://dev.to/tinydevops/go-lexical-elements-rune-literals-pt-1-intro-to-unicode-dn"&gt;Friday&lt;/a&gt; when we discussed Unicode, and &lt;a href="https://dev.to/tinydevops/go-lexical-elements-rune-literals-pt-2-3dn7"&gt;yesterday&lt;/a&gt; when we discussed quoting single characters.&lt;/p&gt;

&lt;p&gt;Today we’re looking at the various escape sequences supported by the &lt;code&gt;rune&lt;/code&gt; literal syntax.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://go.dev/ref/spec#Rune_literals"&gt;Rune literals&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Several backslash escapes allow arbitrary values to be encoded as ASCII text. There are four ways to represent the integer value as a numeric constant: &lt;code&gt;\x&lt;/code&gt; followed by exactly two hexadecimal digits; &lt;code&gt;\u&lt;/code&gt; followed by exactly four hexadecimal digits; &lt;code&gt;\U&lt;/code&gt; followed by exactly eight hexadecimal digits, and a plain backslash &lt;code&gt;\&lt;/code&gt; followed by exactly three octal digits. In each case the value of the literal is the value represented by the digits in the corresponding base.&lt;/p&gt;

&lt;p&gt;Although these representations all result in an integer, they have different valid ranges. Octal escapes must represent a value between 0 and 255 inclusive. Hexadecimal escapes satisfy this condition by construction. The escapes &lt;code&gt;\u&lt;/code&gt; and &lt;code&gt;\U&lt;/code&gt; represent Unicode code points so within them some values are illegal, in particular those above &lt;code&gt;0x10FFFF&lt;/code&gt; and surrogate halves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s take these one at a time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A single octal byte&lt;/strong&gt; — &lt;code&gt;\OOO&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll probably never use this, so let's get it out of the way first. But it's allowed. You can specify a byte using octal notation. However, note that as described, this is limited to values 0-255 inclusive, which means you can create an invalid &lt;code&gt;rune&lt;/code&gt; representation this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\400'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// # 400 octal == 256 decimal&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Produces the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  octal escape value 256 &amp;gt; 255
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One, two, or four hexidecimal bytes&lt;/strong&gt; — &lt;code&gt;\xXX&lt;/code&gt;, &lt;code&gt;\uXXXX&lt;/code&gt;, &lt;code&gt;\UXXXXXXXX&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows you to a single byte with two hexidecimal digits, (&lt;code&gt;\xXX&lt;/code&gt;), two bytes with four digits (&lt;code&gt;\uXXXX&lt;/code&gt;), or the full 4 bytes of a &lt;code&gt;rune&lt;/code&gt; with eight hexidecimal digits (&lt;code&gt;\UXXXXXXXX&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;And finally, there are some special escape sequences supported for &lt;code&gt;rune&lt;/code&gt; literals:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After a backslash, certain single-character escapes represent special values:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\a   U+0007 alert or bell
\b   U+0008 backspace
\f   U+000C form feed
\n   U+000A line feed or newline
\r   U+000D carriage return
\t   U+0009 horizontal tab
\v   U+000B vertical tab
\\   U+005C backslash
\'   U+0027 single quote  (valid escape only within rune literals)
\"   U+0022 double quote  (valid escape only within string literals)
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;(That last one arguably doesn't belong here, as it's not valid in a &lt;code&gt;rune&lt;/code&gt; literal, but it's nice to know that it's explicitly excluded here.)&lt;/p&gt;

&lt;p&gt;Let's round out today's email with the rest of the &lt;code&gt;rune&lt;/code&gt; literal section, which is just the boring EBNF syntax, and some examples, which we don't need to discuss in any detail.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An unrecognized character following a backslash in a rune literal is illegal.&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rune_lit         = "'" ( unicode_value | byte_value ) "'" .
unicode_value    = unicode_char | little_u_value | big_u_value | escaped_char .
byte_value       = octal_byte_value | hex_byte_value .
octal_byte_value = `\` octal_digit octal_digit octal_digit .
hex_byte_value   = `\` "x" hex_digit hex_digit .
little_u_value   = `\` "u" hex_digit hex_digit hex_digit hex_digit .
big_u_value      = `\` "U" hex_digit hex_digit hex_digit hex_digit
                           hex_digit hex_digit hex_digit hex_digit .
escaped_char     = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ) .
&lt;/code&gt;&lt;/pre&gt;



&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'a'
'ä'
'本'
'\t'
'\000'
'\007'
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'
'\''         // rune literal containing single quote character
'aa'         // illegal: too many characters
'\k'         // illegal: k is not recognized after a backslash
'\xa'        // illegal: too few hexadecimal digits
'\0'         // illegal: too few octal digits
'\400'       // illegal: octal value over 255
'\uDFFF'     // illegal: surrogate half
'\U00110000' // illegal: invalid Unicode code point
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Go Lexical elements: Rune literals pt 2</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Sat, 08 Jul 2023 06:00:00 +0000</pubDate>
      <link>https://forem.com/jhall/go-lexical-elements-rune-literals-pt-2-3dn7</link>
      <guid>https://forem.com/jhall/go-lexical-elements-rune-literals-pt-2-3dn7</guid>
      <description>&lt;p&gt;I write a daily email about Go, and this is a repost from my series &lt;a href="https://go.dev/ref/spec"&gt;Exploring the Go Spec&lt;/a&gt;. You're invited to &lt;a href="https://boldlygo.tech/daily?utm_source=devto&amp;amp;utm_campaign=runes&amp;amp;utm_medium=blog"&gt;sign up&lt;/a&gt; and follow along.&lt;/p&gt;




&lt;p&gt;Let’s continue our exploration of rune literals, which began on Monday. In summary from &lt;a href="https://dev.to/tinydevops/go-lexical-elements-rune-literals-pt-1-intro-to-unicode-dn"&gt;yesterday&lt;/a&gt;, a rune in Go represents a Unicode code point. Continuing from there…&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://go.dev/ref/spec#Rune_literals"&gt;Rune literals&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A rune literal is expressed as one or more characters enclosed in single quotes, as in &lt;code&gt;'x'&lt;/code&gt; or &lt;code&gt;'\n'&lt;/code&gt;. Within the quotes, any character may appear except newline and unescaped single quote. A single quoted character represents the Unicode value of the character itself, while multi-character sequences beginning with a backslash encode values in various formats.&lt;/p&gt;

&lt;p&gt;The simplest form represents the single character within the quotes; since Go source text is Unicode characters encoded in UTF-8, multiple UTF-8-encoded bytes may represent a single integer value. For instance, the literal &lt;code&gt;'a'&lt;/code&gt; holds a single byte representing a literal &lt;code&gt;a&lt;/code&gt;, Unicode U+0061, value &lt;code&gt;0x61&lt;/code&gt;, while &lt;code&gt;'ä'&lt;/code&gt; holds two bytes (&lt;code&gt;0xc3 0xa4&lt;/code&gt;) representing a literal &lt;code&gt;a&lt;/code&gt;-dieresis, U+00E4, value &lt;code&gt;0xe4&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a few things I want to call out about this section of the spec, that aren’t always obvious, or are easily forgotten. Especially if you’re not already very familiar with Unicode.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;rune&lt;/code&gt; represents a single “character” (technically: unicode code point, see yesterday's discussion).&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;rune&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a single byte. (In fact, &lt;code&gt;rune&lt;/code&gt; is an alias for &lt;code&gt;int32&lt;/code&gt;, so it’s actually 4 bytes)&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;rune&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; necissarily a single visible character, as many visible characters are built by combining multiple codepoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As pointed out in the spec, both &lt;code&gt;'a'&lt;/code&gt; and &lt;code&gt;'ä'&lt;/code&gt; are valid &lt;code&gt;rune&lt;/code&gt; literals. The first also corresponds to a single ASCII (or Unicode) byte: &lt;code&gt;0x61&lt;/code&gt;. The second corresponds to two UTF-8 bytes: &lt;code&gt;0xc3&lt;/code&gt;, &lt;code&gt;0xa4&lt;/code&gt;. So it’s immediately clear that a &lt;code&gt;rune&lt;/code&gt; may contain multiple bytes.&lt;/p&gt;

&lt;p&gt;But recall the example from yesterday as well: &lt;code&gt;'ў'&lt;/code&gt; is a valid rune literal, and represents two bytes: &lt;code&gt;0xd1&lt;/code&gt;, &lt;code&gt;0x9e&lt;/code&gt;. But in contrast, the visually identical &lt;code&gt;'ў'&lt;/code&gt; is not a valid &lt;code&gt;rune&lt;/code&gt; literal, because it contains two Unicode code points, each of two bytes: &lt;code&gt;у&lt;/code&gt; (&lt;code&gt;0xd1&lt;/code&gt;, &lt;code&gt;0x83&lt;/code&gt;) followed by the breve mark, &lt;code&gt;˘&lt;/code&gt;, (&lt;code&gt;0xcc&lt;/code&gt;, &lt;code&gt;0x86&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;As you might expect, this can be an easy place to get tripped up. What you see on the screen is quite frequently not the whole story. I know of no fool-proof way to solve this confusion. The best I know is to be aware that the confusion exists, so when you see an error along the lines of “more than one character in rune literal”, you know where to begin your search.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Go Lexical elements: Rune literals pt 1, Intro to Unicode</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Fri, 07 Jul 2023 14:12:36 +0000</pubDate>
      <link>https://forem.com/jhall/go-lexical-elements-rune-literals-pt-1-intro-to-unicode-dn</link>
      <guid>https://forem.com/jhall/go-lexical-elements-rune-literals-pt-1-intro-to-unicode-dn</guid>
      <description>&lt;p&gt;I write a daily email about Go, and this is a repost from my series &lt;a href="https://go.dev/ref/spec"&gt;Exploring the Go Spec&lt;/a&gt;. You're invited to &lt;a href="https://boldlygo.tech/daily?utm_source=devto&amp;amp;utm_campaign=runes&amp;amp;utm_medium=blog"&gt;sign up&lt;/a&gt; and follow along.&lt;/p&gt;




&lt;p&gt;Runes… Oh boy! This is one of bits of Go that shines for its elegant simplicity, but constantly trips up everyone (myself included). As such, I think this may be a 2-, or maybe even a 3-parter.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://go.dev/ref/spec#Rune_literals"&gt;Rune literals&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A rune literal represents a &lt;a href="https://go.dev/ref/spec#Constants"&gt;rune constant&lt;/a&gt;, an integer value identifying a Unicode code point.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’re already familiar with Unicode, and have a strong understanding of what a “code point” is, you can probably skip this one. See you later! 👋&lt;/p&gt;

&lt;p&gt;If you’re not completely sure what a Unicode code point is, stick around… I’ll do my best to untangle this seemingly simple phrase.&lt;/p&gt;

&lt;p&gt;First off, what is Unicode? It’s emojis, right? Ehh. If that’s your understanding of Unicode, which would be completely understandable, if your career in software is relatively young, then you need a bit more context. I encourage you to read a bit about the history of why Unicode was invented, and the problems it was meant to solve. This PDF, &lt;a href="https://digitaltools.labcd.unipi.it/wp-content/uploads/2021/05/Introduction-to-Unicode.pdf"&gt;&lt;em&gt;Introduction to Unicode: History of Character Codes&lt;/em&gt;&lt;/a&gt; is a good starting point.&lt;/p&gt;

&lt;p&gt;But here are the highlights:&lt;/p&gt;

&lt;p&gt;Before Unocide, we had many different coding systems. The most popular was ASCII, the &lt;em&gt;American Standard Code for Information Interchange&lt;/em&gt;. But since not all of the world is American, this had obvious drawbacks. Different countries or languages would often have their own coding schemes, but this made it very difficult to share documents between regions.&lt;/p&gt;

&lt;p&gt;If I wrote a document using the Cyrillic alphabet, then sent it to my colleague in France, he would likely see a jumble of French letters in seemingly random order.&lt;/p&gt;

&lt;p&gt;So Unicode came along to &lt;em&gt;Unify&lt;/em&gt; all the codes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0QeAtHrL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owngnbb1dkeuf960lwqi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0QeAtHrL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owngnbb1dkeuf960lwqi.jpg" alt="One Code to Rule them All" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great. So now instead of 127 possible characters in &lt;a href="https://en.wikipedia.org/wiki/ASCII"&gt;ASCII&lt;/a&gt;, we have a virtually unlimited number of characters, right?&lt;/p&gt;

&lt;p&gt;Not so fast.&lt;/p&gt;

&lt;p&gt;While there’s room in Unicode for more than 1 million individual code points, most are not (yet) defined. But what’s more, Unicode is smarter than ASCII in a number of ways. It is possible to &lt;a href="https://en.wikipedia.org/wiki/Combining_character"&gt;combine&lt;/a&gt; Unicode code points to form a single physical character.&lt;/p&gt;

&lt;p&gt;For example, if you want to display the Cyrillic letter &lt;em&gt;ў&lt;/em&gt;, this can be done by combining the Cyrillic Y (&lt;em&gt;у&lt;/em&gt;) with the breve mark (&lt;em&gt;˘&lt;/em&gt;), to give you &lt;em&gt;ў&lt;/em&gt;. But while this looks like a single character, and in print terms it is, it’s actually &lt;em&gt;two&lt;/em&gt; Unicode codepoints. As such, this code won’t compile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;у&lt;/span&gt;&lt;span class="err"&gt;̆'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because while it visually looks like we’re quoting a single character, that character is composed of two Unicode codepoints, and (as we’ll see in the next section), a rune literal must be a single Unicode codepoint.&lt;/p&gt;

&lt;p&gt;Now if that’s not confusing enough, this code &lt;em&gt;will&lt;/em&gt; compile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'ў'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What’s the difference?&lt;/p&gt;

&lt;p&gt;Well, Unicode includes a number of precomposed characters. This is a nice convenience for languages that commonly use a large number of these types of diacritics. But it’s an incovenience for us programmers. Not only does it mean that of these two character representations, only one is a valid &lt;code&gt;rune&lt;/code&gt;, it also introduces certain headaches when trying to compare Unicode strings for equality, or when sorting, etc.&lt;/p&gt;

&lt;p&gt;A last note for today, especially for anyone very new to Unicode. This concept of combining characters to add diacritics and other markings to an existing letter is the same way that Unicode emojis are modified to change skin tone, gender, or other attributes.&lt;/p&gt;

&lt;p&gt;Unicode is pretty powerful. And confusing at times.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Guess-Driven Development</title>
      <dc:creator>Jonathan Hall</dc:creator>
      <pubDate>Tue, 04 Jul 2023 00:00:00 +0000</pubDate>
      <link>https://forem.com/jhall/guess-driven-development-3him</link>
      <guid>https://forem.com/jhall/guess-driven-development-3him</guid>
      <description>&lt;p&gt;Have you ever seen a pull request with half a dozen, seemingly unrelated changes, all in the name of fixing a specific bug?&lt;/p&gt;

&lt;p&gt;The last time this happened to me, I requested clarification on the purpose of a number of the changes, suggested a couple small refactors, pointed out that a couple of the changes were unnecessary or even counter-productive…&lt;/p&gt;

&lt;p&gt;After a few back-and-forths, the PR went from about 40 lines changed to 2 lines changed. All the unrelated, unnecessary bits had been removed.&lt;/p&gt;

&lt;p&gt;This is the result of what I have come to call Guess-Driven Development.&lt;/p&gt;

&lt;p&gt;It happens when someone doesn’t really know what’s causing a bug, so they just start changing things, until the bug goes away. Then they commit their entire change set, without much thought.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you enjoyed this message, &lt;a href="https://jhall.io/daily"&gt;subscribe&lt;/a&gt; to &lt;u&gt;The Daily Commit&lt;/u&gt; to get future messages to your inbox.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>guessdrivendevelopme</category>
      <category>antipatterns</category>
      <category>pullrequests</category>
    </item>
  </channel>
</rss>
