<?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: Chris James</title>
    <description>The latest articles on Forem by Chris James (@quii).</description>
    <link>https://forem.com/quii</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%2F61881%2F0c870cae-d5c4-4603-ac34-8d6eb02ab1fa.png</url>
      <title>Forem: Chris James</title>
      <link>https://forem.com/quii</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/quii"/>
    <language>en</language>
    <item>
      <title>HTMX is the future</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Fri, 05 May 2023 14:31:26 +0000</pubDate>
      <link>https://forem.com/quii/htmx-is-the-future-157j</link>
      <guid>https://forem.com/quii/htmx-is-the-future-157j</guid>
      <description>&lt;h2&gt;
  
  
  The current state of web application development
&lt;/h2&gt;

&lt;p&gt;User expectations of the web are now that you have this super-smooth no-reload experience. Unfortunately, it's an expectation that is usually delivered with single-page applications (SPAs) that rely on libraries and frameworks like React and Angular, which are very specialised tools that can be complicated to work with. &lt;/p&gt;

&lt;p&gt;A new approach is to put the ability to deliver this UX back into the hands of engineers that built websites before the SPA-craze, leveraging their existing toolsets and knowledge, and HTMX is the best example I've used so far. &lt;/p&gt;

&lt;h2&gt;
  
  
  The costs of SPA
&lt;/h2&gt;

&lt;p&gt;SPAs have allowed engineers to create some great web applications, but they come with a cost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Hugely increased complexity both in terms of architecture and developer experience. You have to spend considerable time learning about frameworks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tooling is an ever-shifting landscape in terms of building and packaging code.&lt;/li&gt;
&lt;li&gt;Managing state on both the client and server&lt;/li&gt;
&lt;li&gt;Frameworks, on top of libraries, on top of other libraries, on top of polyfills. &lt;a href="https://react.dev" rel="noopener noreferrer"&gt;React even recommend using a framework on top of their tech&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;React is a library. It lets you put components together, but it doesn’t prescribe how to do routing and data fetching. To build an entire app with React, we recommend a full-stack React framework.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;By their nature, a fat client requires the client to execute a lot of JavaScript. If you have modern hardware, this is fine, but these applications will be unusable &amp;amp; slow for those on older hardware or in locations with slow and unreliable internet connections.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is very easy to make an SPA incorrectly, where you need to use the right approach with hooks to avoid ending up with abysmal client-side performance.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Some SPA implementations of SPA throw away progressive enhancement (a notable and noble exception is &lt;a href="https://remix.run" rel="noopener noreferrer"&gt;Remix&lt;/a&gt;). Therefore, you &lt;em&gt;must&lt;/em&gt; have JavaScript turned on for most SPAs. &lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;If you wish to use something other than JavaScript or TypeScript, you must traverse the treacherous road of transpilation.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;It has created backend and frontend silos in many companies, carrying high coordination costs.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Before SPAs, you'd choose your preferred language and deliver HTML to a user's browser in response to HTTP requests. This is &lt;em&gt;fine&lt;/em&gt;, but it offers little interactivity and, in some cases, could make an annoying-to-use UI, especially regarding having the page fully reload on every interaction. To get around this, you'd typically sprinkle varying amounts of JS to grease the UX wheels. &lt;/p&gt;

&lt;p&gt;Whilst this approach can feel old-fashioned to some, this approach is what inspired the &lt;a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm" rel="noopener noreferrer"&gt;original paper of &lt;strong&gt;REST&lt;/strong&gt;&lt;/a&gt;, especially concerning &lt;strong&gt;hypermedia&lt;/strong&gt;. The hypermedia approach of building websites led to the world-wide-web being an incredible success.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hypermedia?
&lt;/h3&gt;

&lt;p&gt;The following is a response from a data API, not hypermedia.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12-34-56"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"87654321"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"balance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123.45"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To make this data useful in an SPA, the code must understand the structure and decide what to render and what controls to make available.&lt;/p&gt;

&lt;p&gt;REST describes the use of hypermedia. Hypermedia is where your responses are not just raw data but are instead a payload describing the media (think HTML tags like &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, headers, etc.) &lt;em&gt;and&lt;/em&gt; how to manipulate it (like &lt;code&gt;form&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;A server returning HTML describing a bank account, with some form of controls to work with the resource, is an example of hypermedia. The server is now responsible for deciding how to render the data (with the slight caveat of CSS) and &lt;em&gt;what&lt;/em&gt; controls should be displayed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;dl&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dt&amp;gt;&lt;/span&gt;Sort&lt;span class="nt"&gt;&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&lt;/span&gt;12-34-56&lt;span class="nt"&gt;&amp;lt;/dd&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dt&amp;gt;&lt;/span&gt;Number&lt;span class="nt"&gt;&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&lt;/span&gt;87654321&lt;span class="nt"&gt;&amp;lt;/dd&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dt&amp;gt;&lt;/span&gt;Balance&lt;span class="nt"&gt;&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&lt;/span&gt;£123.45&lt;span class="nt"&gt;&amp;lt;/dd&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dl&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/transfer-funds"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Amount &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- etc --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Do transfer"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The approach means you have one universal client, the web browser; it understands how to display the hypermedia responses and lets the user work with the "controls" to do whatever they need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://changelog.com/gotime/266" rel="noopener noreferrer"&gt;Carson Gross on The Go Time podcast&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;...when browsers first came out, this idea of one universal network client that could talk to any application over this crazy hypermedia technology was really, really novel. And it still is.&lt;/p&gt;

&lt;p&gt;If you told someone in 1980, “You know what - you’re gonna be using the same piece of software to access your news, your bank, your calendar, this stuff called email, and all this stuff”, they would have looked at you cross-eyed, they wouldn't know what you were talking about, unless they happened to be in one of the small research groups that was looking into this sort of stuff.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whilst ostensibly, people building SPAs talk about using "RESTful" APIs to provide data exchange to their client-side code, the approach is not RESTful in the purist sense because it does not use hypermedia. &lt;/p&gt;

&lt;p&gt;Instead of one universal client, &lt;em&gt;scores of developers create bespoke clients&lt;/em&gt;, which have to understand the raw data they fetch from web servers and then render controls according to the data. With this approach, the browser is more of a JavaScript, HTML and CSS runtime. &lt;/p&gt;

&lt;p&gt;By definition, a fatter client will carry more effort and cost than a thin one. However, the "original" hypermedia approach arguably is not good enough for all of today's needs; the controls that the browser can work with and the way it requires a full page refresh to use them mean the user experience isn't good enough for many types of web-app we need to make. &lt;/p&gt;

&lt;h3&gt;
  
  
  HTMX and hypermedia
&lt;/h3&gt;

&lt;p&gt;Unlike SPAs, HTMX &lt;strong&gt;doesn't throw away the architectural approach of REST&lt;/strong&gt;; it &lt;em&gt;augments the browser&lt;/em&gt;, &lt;strong&gt;improving its hypermedia capabilities&lt;/strong&gt; and making it simpler to deliver a rich client experience without having to write much JavaScript if any at all. &lt;/p&gt;

&lt;p&gt;You can use &lt;strong&gt;whatever programming language you like&lt;/strong&gt; to deliver HTML, just like we used to. This means you can use battle-tested, mature tooling, using a "true RESTful" approach, resulting in a far more straightforward development approach with less accidental complexity. &lt;/p&gt;

&lt;p&gt;HTMX allows you to design pages that fetch &lt;strong&gt;fragments of HTML&lt;/strong&gt; from your server to update the user's page as needed without the annoying full-page load refresh.&lt;/p&gt;

&lt;p&gt;We'll now see this in practice with the classic TODO-list application. &lt;/p&gt;

&lt;h2&gt;
  
  
  Clojure HTMX TODO
&lt;/h2&gt;

&lt;p&gt;First-of-all, please don't get overly concerned with this being written in Clojure. I did it in Clojure for fun, but the beauty of this approach is that you can use whatever language you like, so long as it responds to HTTP requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FmJCwSLf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FmJCwSLf.gif" alt="The todo list app demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nothing special here, but it &lt;strong&gt;does feel like a SPA&lt;/strong&gt;. There are no full-page reloads; it's buttery smooth, just like all the other SPA demos you would've seen. &lt;/p&gt;

&lt;p&gt;The difference here is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I did not write any JavaScript.&lt;/li&gt;
&lt;li&gt;I also didn't cheat by transpiling Clojure into JavaScript. (see &lt;a href="https://clojurescript.org" rel="noopener noreferrer"&gt;ClojureScript&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I made a web server that responds to HTTP requests with hypermedia. &lt;/p&gt;

&lt;p&gt;HTMX adds the ability to define &lt;strong&gt;richer hypermedia&lt;/strong&gt; by letting you annotate &lt;em&gt;any HTML element&lt;/em&gt; to ask the browser to make HTTP requests to fetch fragments of HTML to put on the page. &lt;/p&gt;

&lt;h3&gt;
  
  
  The edit control
&lt;/h3&gt;

&lt;p&gt;The most exciting and impressive part of this demo is the edit action. The way an input box instantly appears for you to edit and then quickly update it again &lt;em&gt;feels&lt;/em&gt; like it would require either a lot of vanilla JS writing or a React-esque approach to achieve, but what you'll see is it's absurdly simple. &lt;/p&gt;

&lt;p&gt;Let's start by looking at the markup for a TODO item. I have clipped the non-edit markup for clarity.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"closest li"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/todos/2a5e549c-c07e-4ed5-b7d4-731318987e05"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/todos/2a5e549c-c07e-4ed5-b7d4-731318987e05"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;📝&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It maybe looks a lot, but the main things to focus on for understanding how the edit functionality works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;, an attribute &lt;code&gt;hx-target&lt;/code&gt; tells the browser, "When you get a fragment to render, this is the element I want you to replace". The children inherit this attribute, so for any HTMX actions inside this &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;, the &lt;code&gt;HTML&lt;/code&gt; returned will replace the contents of the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hx-get&lt;/code&gt; on the edit button means when you click it, &lt;code&gt;HTMX&lt;/code&gt; with tell the browser to do an &lt;code&gt;HTTP GET&lt;/code&gt; to the &lt;code&gt;URL&lt;/code&gt; and fetch some new markup to render to the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; in place of what's there.&lt;/li&gt;
&lt;li&gt;The form is not essential for the example, but it allows us to support the functionality for non-JavaScript users, which will be covered later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you start working with HTMX, an easy way to understand what's going on is to look at the network in the browser's developer tools. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FlnobOm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FlnobOm5.png" alt="the browser is requesting the todo resource"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a user clicks the edit button, the browser does an &lt;code&gt;HTTP GET&lt;/code&gt; to the &lt;em&gt;specific todo resource&lt;/em&gt;. The server returns a hypermedia response, which is a representation of that resource with some hypermedia controls. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/todos/45850279-bf54-4e2e-a95c-c8c25866a744/edit"&lt;/span&gt;
      &lt;span class="na"&gt;hx-patch=&lt;/span&gt;&lt;span class="s"&gt;"/todos/45850279-bf54-4e2e-a95c-c8c25866a744"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"done"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Learn Rust"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;HTMX then takes that HTML and replaces whatever we defined as the &lt;code&gt;hx-target&lt;/code&gt;. So the user now sees these hypermedia controls for them to manipulate the resource, instead of the row pictured before.&lt;/p&gt;

&lt;p&gt;You'll notice the form has a &lt;code&gt;hx-patch&lt;/code&gt; attribute, which means when it is submitted, the browser will send a &lt;code&gt;PATCH&lt;/code&gt; with the data to update the resource. The server then responds with the updated item to render. &lt;/p&gt;

&lt;h2&gt;
  
  
  Embracing the web
&lt;/h2&gt;

&lt;p&gt;There's more to HTMX, but this is the crux of the approach, which is the same as the approach that most websites were made before SPAs became popular.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user goes to a &lt;code&gt;URL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The server returns hypermedia (HTML), which is content with controls.&lt;/li&gt;
&lt;li&gt;Browser renders hypermedia&lt;/li&gt;
&lt;li&gt;Users can use the controls to do work, which results in an HTTP request sent from the browser to the server.&lt;/li&gt;
&lt;li&gt;The server does business logic, and then returns new hypermedia for the user to work with&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All HTMX does, is make the browser &lt;strong&gt;better&lt;/strong&gt; at hypermedia by giving us more options regarding &lt;strong&gt;what can trigger an HTTP request&lt;/strong&gt; and &lt;strong&gt;allowing us to update a part of the page rather than a full page reload&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By embracing the hypermedia and not viewing the browser as merely a JavaScript runtime, we get a lot of simplicity benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can use any programming language.&lt;/li&gt;
&lt;li&gt;We don't need lots of libraries and other cruft to maintain what were basic benefits of web development.

&lt;ul&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;SEO-friendliness&lt;/li&gt;
&lt;li&gt;The back button working as you'd expect&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;It is very easy to support users who do not wish to, or cannot use JavaScript&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This final point is crucial to me and to my current employer. I work for a company that works on products used worldwide, and our content and tools must be as usable by as many people as possible. It is unacceptable for us to exclude people through poor technical choices. &lt;/p&gt;

&lt;p&gt;This is why we adopt the approach of &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement" rel="noopener noreferrer"&gt;&lt;strong&gt;progressive enhancement&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Progressive enhancement&lt;/strong&gt; is a design philosophy that provides a baseline of essential content and functionality to as many users as possible, while delivering the best possible experience only to users of the most modern browsers that can run all the required code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All the features in the TODO app (search, adding, editing, deleting, marking as complete) all work with JavaScript turned off. HTMX doesn't do this for "free", it still requires engineering effort, but because of the approach, it is inherently simpler to achieve. It took me around an hour's effort and did not require significant changes. &lt;/p&gt;

&lt;h3&gt;
  
  
  How it supports non-JavaScript
&lt;/h3&gt;

&lt;p&gt;When the browser sends a request that was prompted by HTMX, it adds a header &lt;code&gt;HX-Request: true&lt;/code&gt; , which means on the server, we can send different responses accordingly, very much like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation" rel="noopener noreferrer"&gt;content negotiation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The rule of thumb for a handler is roughly:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

parseAndValidateRequest()
myBusinessLogic()

if request is htmx then
    return hypermedia fragment
else
    return a full page
end


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's a concrete example of the HTTP handler for dealing with a new TODO:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;handle-new-todo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get-todos,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add-todo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new-todo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:params&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:todo-name&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;add-todo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;htmx-or-vanilla&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="w"&gt;
                               &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;view/todos-fragment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-todos&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
                               &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/todos"&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The third line is our "business logic", calling a function to add a new TODO to our list. &lt;/p&gt;

&lt;p&gt;The fourth line is some code to determine what kind of request we're dealing with, and the subsequent lines either render a fragment to return or redirect to the page. &lt;/p&gt;

&lt;p&gt;So far, this seems a recurring theme when I've been developing hypermedia applications with HTMX. By the very architectural nature, if you can support updating part of a page, return a fragment; otherwise, the browser &lt;em&gt;needs&lt;/em&gt; to do a full page reload, so either redirect or just return the entire HTML. &lt;/p&gt;

&lt;p&gt;HTML templating on the server is in an incredibly mature state. There are many options and excellent guides on how to structure and add automated tests for them. Importantly, they'll all offer some composition capabilities, so the effort to return a fragment or a whole page is extremely simple. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why is it &lt;em&gt;The Future&lt;/em&gt; ?
&lt;/h2&gt;

&lt;p&gt;Obviously, I cannot predict the future, but I do believe HTMX (or something like it) will become an increasingly popular approach for making web applications in the following years. &lt;/p&gt;

&lt;p&gt;Recently, &lt;a href="https://github.blog/2023-04-12-github-accelerator-our-first-cohort-and-whats-next/" rel="noopener noreferrer"&gt;HTMX was announced as one of 20 projects in the GitHub Accelerator&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  It makes "the frontend" more accessible.
&lt;/h3&gt;

&lt;p&gt;Learning React is an industry in itself. It moves quickly and changes, and there are tons to learn. I sympathise with developers who &lt;em&gt;used&lt;/em&gt; to make fully-fledged applications being put off by modern frontend development and instead were happy to be pigeonholed into being a "backend" dev. &lt;/p&gt;

&lt;p&gt;I've made reasonably complex systems in React, and whilst some of it was pretty fun, &lt;strong&gt;the amount you have to learn to be effective is unreasonable for most applications&lt;/strong&gt;. React has its place, but it's overkill for many web applications. &lt;/p&gt;

&lt;p&gt;The hypermedia approach with HTMX is not hard to grasp, especially if you have some REST fundamentals (which many "backend" devs should have). It opens up making rich websites to a broader group of people who don't want to learn how to use a framework and then keep up with its constantly shifting landscape.&lt;/p&gt;

&lt;h3&gt;
  
  
  Less churn
&lt;/h3&gt;

&lt;p&gt;Even after over 10 years of React being around, it still doesn't feel settled and mature. A few years ago, hooks were the new-fangled thing that everyone had to learn and re-write all their components with. In the last six months, my Twitter feed has been awash with debates and tutorials about this new-fangled "RSC" - react server components. Joy emoji. &lt;/p&gt;

&lt;p&gt;Working with HTMX has allowed me to leverage things I learned 15-20 years ago &lt;strong&gt;that still work&lt;/strong&gt;, &lt;a href="https://quii.dev/How_my_website_works" rel="noopener noreferrer"&gt;like my website&lt;/a&gt;. The approach is also well-understood and documented, and the best practices are independent of programming languages and frameworks.&lt;/p&gt;

&lt;p&gt;I have made the example app in Go &lt;em&gt;and&lt;/em&gt; Clojure with no trouble at all, and I am a complete Clojure novice. Once you've figured out the basic syntax of a language and learned how to respond to HTTP requests, you have enough to get going; and you can re-use the architectural and design best practices without having to learn a new approach over and over again. &lt;/p&gt;

&lt;p&gt;How much of your skills would be transferable from React if you had to work with Angular? Is it easy to switch from one react framework to another? How did you feel when class components became "bad", and everyone wanted you to use hooks instead?&lt;/p&gt;

&lt;h3&gt;
  
  
  Cheaper
&lt;/h3&gt;

&lt;p&gt;It's just less effort! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://hotwired.dev" rel="noopener noreferrer"&gt;Hotwire&lt;/a&gt; is a library with similar goals to HTMX, driven by the Ruby on Rails world. DHH tweeted the following.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/dhh/status/1341758748717510659" rel="noopener noreferrer"&gt;Hotwiring Rails expresses the desire to gift a lone full-stack developer all the tools they need to build the next Basecamp, GitHub, or Shopify. Not what a team of dozens or hundreds can do if they have millions in VC to buy  specialists. Renaissance tech for renaissance people.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's why it's so depressing to hear the term "full stack" be used as a derogative. Or an impossible mission. That we HAVE to be a scattered band of frontend vs backend vs services vs whatever group of specialists to do cool shit. Absolutely fucking not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without the cognitive overload of understanding a vast framework from the SPA world and the inherent complexities of making a fat client, you can realistically create rich web applications with far fewer engineers. &lt;/p&gt;

&lt;h3&gt;
  
  
  More resilient
&lt;/h3&gt;

&lt;p&gt;As described earlier, using the hypermedia approach, making a web application that works without JavaScript is relatively simple. &lt;/p&gt;

&lt;p&gt;It's also important to remember that the browser is an &lt;strong&gt;untrusted environment&lt;/strong&gt;, so when you build a SPA, you have to work extremely defensively. You have to implement lots of business logic client side; but because of the architecture, this same logic needs to be replicated on the server too. &lt;/p&gt;

&lt;p&gt;For instance, let's say we wanted a rule saying you cannot edit a to-do if it is marked as done. In an SPA world, I'd get raw JSON, and I'd have to have business logic to determine whether to render the edit button on the client code somewhere. However, if we wanted to ensure a user couldn't circumvent this, I'd have to have this same protection on the server. This sounds low-stakes and simple, but this complexity adds up, and the chance of misalignment increases. &lt;/p&gt;

&lt;p&gt;With a hypermedia approach, the browser is "dumb" and doesn't need to worry about this. As a developer, I can capture this rule in one place, the server. &lt;/p&gt;

&lt;h3&gt;
  
  
  Reduced coordination complexity
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The complexity of SPAs has created a shift into backend and frontend silos&lt;/strong&gt;, which carries a cost.&lt;/p&gt;

&lt;p&gt;The typical backend/frontend team divide causes a lot of inefficiencies in terms of teamwork, with hand-offs and miscommunication, and &lt;strong&gt;makes getting stuff done harder&lt;/strong&gt;. Many people mistake individual efficiencies as the most critical metric and use that as justification for these silos. They see lots of PRs being merged, and lots of heat being generated, but ignoring the coordination costs.&lt;/p&gt;

&lt;p&gt;For example, let's assume you want to add a new piece of data to a page or add a new button. For many teams, that'll involve meetings between teams to discuss and agree on the new API, creating fakes for the frontend team to use and finally coordinating releases. &lt;/p&gt;

&lt;p&gt;In the hypermedia approach, you &lt;strong&gt;don't have this complexity at all&lt;/strong&gt;. If you wish to add a button to the page, you can add it, and you don't need to coordinate efforts. You don't have to worry so much about API design. You are free to change the markup and content as you please.&lt;/p&gt;

&lt;p&gt;Teams exchanging data via JSON can be &lt;strong&gt;extremely brittle&lt;/strong&gt; without care and always carries a coordination cost. Tools like consumer-driven contracts can help, but this is just &lt;em&gt;another&lt;/em&gt; tool, &lt;em&gt;another&lt;/em&gt; thing to understand and &lt;em&gt;another&lt;/em&gt; thing that goes wrong. &lt;/p&gt;

&lt;p&gt;This is not to say there is no room for specialisation. I've worked on teams where the engineers built the web application "end to end", but we had people who were experts on semantic, accessible markup who helped us make sure the work we did was of good quality. It is incredibly freeing not to have to negotiate APIs and hand off work to one another to build a website.&lt;/p&gt;

&lt;h3&gt;
  
  
  More options
&lt;/h3&gt;

&lt;p&gt;Rendering HTML on the server is a very well-trodden road. Many battle-tested and mature tools and libraries are available to generate HTML from the server in every mainstream programming language and most of the more niche ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;I encourage developers looking to reduce the costs and complexities of web application development to check out HTMX. If you've been reluctant to build websites due to the fair assessment that front-end development is difficult, HTMX can be a great option. &lt;/p&gt;

&lt;p&gt;I'm not trying to claim that SPAs are now redundant; there will still be a real need for them when you need very sophisticated and fast interactions where a roundtrip to the server to get some markup won't be good enough.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quii.dev/The_Web_I_Want" rel="noopener noreferrer"&gt;In 2018 I asserted that a considerable number of web applications could be written with a far simpler technological approach&lt;/a&gt; than SPAs. Now with the likes of HTMX, this assertion carries even more weight. The frontend landscape is dominated by waiting for a new framework to relieve the problems of the previous framework you happened to be using. The SPA approach is &lt;strong&gt;inherently more complicated than a hypermedia approach&lt;/strong&gt;, and piling on more tech might not be the answer, give hypermedia a go instead.&lt;/p&gt;

&lt;p&gt;Check out some of the links below to learn more. &lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading and listening
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The author of HTMX has written an excellent, &lt;a href="https://hypermedia.systems" rel="noopener noreferrer"&gt;free book, explaining hypermedia&lt;/a&gt;. It's an easy read and will challenge your beliefs on how to build web applications. If you've only ever created SPAs, this is an essential read.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://htmx.org" rel="noopener noreferrer"&gt;HTMX&lt;/a&gt;. The examples section, in particular, is very good in showing you what's possible. The essays are also great. &lt;/li&gt;
&lt;li&gt;I was lucky enough to be invited onto &lt;a href="https://changelog.com/gotime/266" rel="noopener noreferrer"&gt;The GoTime podcast with the creator of HTMX, Carson Gross to discuss it&lt;/a&gt;! Even though it's a Go podcast, the majority of the conversation was about the hypermedia approach. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/quii/todo" rel="noopener noreferrer"&gt;The Go version&lt;/a&gt; was my first adventure with HTMX, creating the same todo list app described in this post&lt;/li&gt;
&lt;li&gt;I worked on &lt;a href="https://github.com/ndchorley/todo" rel="noopener noreferrer"&gt;The Clojure version&lt;/a&gt; with my colleague, Nicky&lt;/li&gt;
&lt;li&gt;&lt;a href="https://world.hey.com/dhh/the-time-is-right-for-hotwire-ecdb9b33" rel="noopener noreferrer"&gt;DHH on Hotwire&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement" rel="noopener noreferrer"&gt;Progressive enhancement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Five years ago, I wrote &lt;a href="https://quii.dev/The_Web_I_Want" rel="noopener noreferrer"&gt;The Web I Want&lt;/a&gt;, where I bemoaned the spiralling costs of SPAs. It was originally prompted by watching my partner's 2-year-old ChromeBook grind to a halt on a popular website that really could've been static HTML. In the article, I discussed how I wished more of the web stuck to the basic hypermedia approach, rendering HTML on the server and using progressive enhancement to improve the experience. Reading back on this has made me very relieved the likes of HTMX have arrived.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>htmx</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Reduce WIP by practicing trunk-based development, rather than pull requests</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Mon, 26 Jul 2021 10:14:58 +0000</pubDate>
      <link>https://forem.com/quii/reduce-wip-by-practicing-trunk-based-development-rather-than-pull-requests-116e</link>
      <guid>https://forem.com/quii/reduce-wip-by-practicing-trunk-based-development-rather-than-pull-requests-116e</guid>
      <description>&lt;p&gt;Poorly managed work in progress (WIP) is a common cause for low performance in development teams. When you have a team juggling too much work, it engages in frequent, expensive context switching, which reduces quality and slows delivery. Your team is working hard, but not delivering.&lt;/p&gt;

&lt;p&gt;The reduction in quality has a compounding effect on WIP as you will get unexpected bugs, re-work, and outages; which in itself causes more WIP. Unplanned work is poison for productivity and predictability. &lt;/p&gt;

&lt;p&gt;Managing WIP involves looking at how work &lt;strong&gt;flows&lt;/strong&gt; through your system, trying to make it go quickly, smoothly and predictably. Identifying bottlenecks &amp;amp; constraints allows you to manage them more effectively and focus your efforts on improving them and making sure only the highest priority work goes to them. Any efforts to improve efficiency outside these constraints is waste because it’s the bottlenecks in your system that dictate pace. With a focus on quality you can reduce the amount of unplanned work which helps you manage WIP. &lt;/p&gt;

&lt;p&gt;There is no one true way of working, the best method depends on your team and the context they’re in. Managing WIP, and having a smooth flow of work, is not a negotiation if you are serious about managing an effective team. &lt;/p&gt;

&lt;p&gt;Pretend you are the lead of a 4-person development team. How your team approaches creating value obviously has a big impact on its ability to deliver it, yet many teams copy other team’s rigid models, rather than thinking about the context they are in and tailoring the process to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The open source, pull-request model
&lt;/h2&gt;

&lt;p&gt;This is an often-cited, popular way for teams to work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each developer picks up a ticket/story/task&lt;/li&gt;
&lt;li&gt;Developer writes code on a branch. This allows them to work isolated, focused, and not affect other team members with their work which may not be completed.&lt;/li&gt;
&lt;li&gt;When the developer believes the work is finished, they raise a pull request. When another developer is free, they can take a look at the work and then initiate a feedback cycle with the person who raised the PR until it is of sufficient quality.&lt;/li&gt;
&lt;li&gt;The code gets merged and deployed to customers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Often the reasons people adopt this model is it allows a degree of gatekeeping and socialising knowledge. It’s argued that it can help prevent mistakes from being shipped and maintain code quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  High WIP
&lt;/h3&gt;

&lt;p&gt;For a team of 4 developers, having at least 4 tickets in play at a time &lt;em&gt;feels&lt;/em&gt; like high WIP. Chasing 100% “resource” allocation is not a desirable management goal because all systems need a level of slack to cope with unexpected work. If a team is running at full-capacity it is inflexible, and inflexible things tend to break under pressure. &lt;/p&gt;

&lt;p&gt;If you raise a PR and none of your colleagues are free, you may be tempted to pick up another ticket. The WIP of the team has now increased to 5. You can easily imagine, and have probably experienced, scenarios where this is a slippery slope to climbing WIP. &lt;/p&gt;

&lt;p&gt;How many times have you heard:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s done, it just needs to be reviewed&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In software development, the word “just” is often doing a lot of heavy lifting. &lt;strong&gt;The work is not “done” until it is actually delivering value.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The feedback cycle in the PR can take some time with asynchronous back-and-forth, so you may end up having to switch context between multiple tickets at a time. In lean terms, &lt;strong&gt;the process has caused a bottleneck&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even with a team of only 4 you can easily end up in a situation where they’re context switching between the story they’re assigned to, but also reviewing lots of other developers of code. The personal WIP for each team member can climb steeply depending on how back-and-forth the review process is. As the WIP increases for each person, the ability to get code reviewed diminishes.&lt;/p&gt;

&lt;p&gt;PRs are remote-friendly due to their asynchronous nature. This is true, but you have to accept then you will have a lot of unfinished work in play, which will raise your team’s WIP. &lt;/p&gt;

&lt;p&gt;If I were to be managing a team working like this, I think it would be prudent to ensure that you only have 3 developers working on stories at a time, giving your system some slack. The other developer can help reviews happen quicker, find ways to improve flow, increase quality in other ways (improve tests, logging, metrics, e.t.c.), and you’ll have more slack to deal with unplanned work.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Slow integration
&lt;/h3&gt;

&lt;p&gt;The longer your code lives on a branch, the less integrated you are with the rest of your team. Whilst the 4 of you are described as a team, you are all working on different versions of the code, as individuals.&lt;/p&gt;

&lt;p&gt;If you find it hard to get your colleagues to review your changes, this slow integration compounds, and teams that adopt this system often have to deal with challenging merge conflicts. In the previous example this way of working can lead to multiple PRs that need merging which can result in multiple merge conflicts having to be resolved. This is &lt;strong&gt;waste&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unpredictable flow
&lt;/h3&gt;

&lt;p&gt;The review back-and-forth can last minutes, hours, days, or even weeks. In the worst cases, it involves a lot of re-work. Once the developer falls in to the trap of picking up another story whilst their other is in review, WIP can quickly spiral out of control. &lt;/p&gt;

&lt;p&gt;Plenty of successful teams ship software like this, it’s not unworkable, but I’m not convinced it’s simple or efficient. I think even when it is managed extremely well, it still causes a lot of waste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trunk-based development (TBD) and pair programming
&lt;/h2&gt;

&lt;p&gt;What is the most obvious way to reduce WIP?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do less work concurrently&lt;/li&gt;
&lt;li&gt;Concentrate on finishing work&lt;/li&gt;
&lt;li&gt;Increase quality to reduce unexpected re-work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of having 4 developers work on 4 tickets, let's instead have 2 developers pairing per ticket.&lt;/p&gt;

&lt;p&gt;By having 2 heads work on a problem, it liberates us from having to gate-keep the main branch. We should trust that 2 developers on our team can take ownership of a problem from idea to production. Therefore, they can commit their code straight to main. &lt;strong&gt;This simplifies the flow of work&lt;/strong&gt;. We no-longer have a wasteful bottleneck to shipping value.&lt;/p&gt;

&lt;h3&gt;
  
  
  No, I can’t trust 2 developers to take an idea from kick-off to production.
&lt;/h3&gt;

&lt;p&gt;How many then? 3, 4? Or worse, can it only be put into the main branch if it is blessed by the lead? If you’re a lead making yourself a bottleneck, you’re not doing a good job. You’re not spreading your knowledge, you’re not coaching well enough, you’re increasing &lt;a href="https://gist.github.com/quii/30cd1f59b9f05c6f89dbd0e423120644"&gt;bus factor&lt;/a&gt;, and you’re hurting the productivity of your team. &lt;/p&gt;

&lt;h3&gt;
  
  
  Improved flow, higher quality and less re-work
&lt;/h3&gt;

&lt;p&gt;By integrating frequently through the day, the chance of merge conflict is low and even when it happens it is typically trivial to fix. Far easier than having to merge a week’s worth of changes back into main. &lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;true continuous integration&lt;/strong&gt;, the team can consistently see what everyone is working on, which helps collaboration. No longer will you hear excuses like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I’d like to refactor the blah blah, but I can’t because I know Alice is working on a PR related to it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By removing the barriers to changing code and having a tight integration with your team (rather than disparate branches) you can now fearlessly refactor.&lt;/p&gt;

&lt;p&gt;It’s an assumption, but not an unfair one, that the quality of code should be higher if 2 people are working on a change. High internal-quality makes changing our system simpler and should reduce the chance of unexpected re-work.&lt;/p&gt;

&lt;p&gt;If you practice continuous deployment, it means you’ll release smaller changes frequently throughout the day. This reduces risk and makes recovery easier compared to diagnosing a pull request which may have been worked on for a number of days (or weeks!) rather than hours. &lt;/p&gt;

&lt;p&gt;The idea of code-review and socialising ideas is now constant and easily available. Developers don’t have to write large amounts of code and then inconvenience another developer, forcing them to context switch to give feedback on your ideas. Instead, you have a colleague that you can easily bounce ideas with. &lt;/p&gt;

&lt;p&gt;To make sure the socialising of code is spread amongst all developers, we ensure that we rotate the pairs frequently. We’ll also do a “code review” session every week for a couple of hours when we can talk about our code in broader strokes, in a more holistic way; rather than focusing on an isolated change in a PR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Risk
&lt;/h3&gt;

&lt;p&gt;If the idea of pushing directly to main is uncomfortable for you, it’s likely you’re working on an unsafe system. For TBD to work, you need to engineer your system so that it is safe to work on. You’ll need things like: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Good alerting&lt;/li&gt;
&lt;li&gt;Easy or automatic rollbacks&lt;/li&gt;
&lt;li&gt;An excellent test-suite&lt;/li&gt;
&lt;li&gt;Observability&lt;/li&gt;
&lt;li&gt;“Test in prod”&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/mipsytipsy/status/1147863838647185408"&gt;If you aren't testing in prod you aren't testing in reality -- just a weak dime store knockoff.  Then you light the fuse and walk away with your fingers crossed. Test in prod.  Please.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— Charity Majors&lt;/p&gt;

&lt;p&gt;Gatekeeping around PRs and releasing is often &lt;strong&gt;reliability-theatre&lt;/strong&gt;. Nothing can save you from mistakes, they’re inevitable. What you need to focus on is your &lt;a href="https://en.wikipedia.org/wiki/Mean_time_to_recovery"&gt;&lt;strong&gt;mean time to recovery&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To commit to main directly, safely &amp;amp; frequently you need an excellent, fast test-suite and a well configured CI-pipeline. Developers need to be disciplined and only commit code they’re happy to put on the main branch.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every developer is touching mainline, so all features grow in the mainline… which acts as a communication point. With CI, the mainline must always be healthy, so in theory (and often in practice) you can safely release after any commit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— Martin Fowler&lt;/p&gt;

&lt;p&gt;To live with the constraints of wanting to continuously integrate but not make “bad” commits, you need to find ways to break your work down into small, achievable pieces. This discipline makes work more achievable and will &lt;em&gt;reduce&lt;/em&gt; risk. By working like this, I’d expect our 2 pairs of engineers to push several times per day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying TBD
&lt;/h2&gt;

&lt;p&gt;If you do decide to try TBD, be prepared for some friction and growing-pains if you have a team unfamiliar working in this way. &lt;a href="https://quii.dev/Gamifying_Continuous_Integration"&gt;A few years back, I wrote about how I introduced TBD to a team that was previously familiar with a PR-based approach.&lt;/a&gt;It will be a journey of uncovering issues in quality, bottlenecks and collaborating to find ways to improve them.&lt;/p&gt;

&lt;p&gt;TBD may expose some uncomfortable shortcomings in your system, and the quality of your code and architecture. I’ve noticed that often a PR flow masks problems like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers finding it hard to break problems down in to smaller, less risky changes. &lt;a href="https://cloud.google.com/architecture/devops/devops-process-working-in-small-batches"&gt;They have not learned how to work in small batches&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Low internal quality. If your system suffers from a lot of inappropriate tight coupling, you’ll tend to trip over each other’s toes when working together on the main branch.&lt;/li&gt;
&lt;li&gt;Poor/inadequate tests. Lots of teams use the “CI server” as a crutch for poorly written tests that they run slowly and infrequently. Every so often, the system is designed in such a way that important tests are impossible to run locally. 

&lt;ul&gt;
&lt;li&gt;If you’re pushing every hour, you need to be able to test locally and be confident your change is shippable and won’t affect your colleagues negatively.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a journey that many factories (real factories!) have gone through. To work leanly, with excellent flow, managing WIP requires you to look at &lt;em&gt;how&lt;/em&gt; you do work and commit to increase quality from start to finish as a team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which is best for your team?
&lt;/h2&gt;

&lt;p&gt;TBD is not niche or unusual. Plenty of big businesses, in well-regulated industries, work with pairs of developers committing many times a day to do the main branch. &lt;a href="https://aboodman.medium.com/in-march-2011-i-drafted-an-article-explaining-how-the-team-responsible-for-google-chrome-ships-c479ba623a1b"&gt;Chromium releases every day and does not use branches&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=bHKHdp4H-8w&amp;amp;feature=youtu.be"&gt;In this short video, Dave Farley shows a fin-tech company in a well-regulated space working with TBD&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usually, these high-performing teams ship these changes extremely frequently to customers, so they can get real feedback quickly and build superior products.&lt;/p&gt;

&lt;p&gt;Whilst pairing may seem like an expensive frivolity, the workflow is simpler, more focused and of higher quality. You’ll find that this approach can out-perform the same team working as individuals on branches. There is plenty of evidence to back up this assertion. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/tastapod/status/1415588779176480770"&gt;Five years' worth of academically defensible State of DevOps research that shows &lt;em&gt;causality&lt;/em&gt; of feature branching with poor performance.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;—  Daniel Terhorst-North&lt;/p&gt;

&lt;p&gt;PRs optimise for individual resource allocation, but introduce bottlenecks in your system which drive up WIP, and make the flow of work less smooth than it could be. &lt;strong&gt;High WIP diminishes a team’s productivity and is a management dysfunction, making work harder than it needs to be.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To those unfamiliar with TBD, it may seem risky and even unprofessional, but it forces you to work with more discipline, adopt best practices which will make your system more resilient and the work simpler. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.amazon.com/Continuous-Delivery-Deployment-Automation-Addison-Wesley/dp/0321601912"&gt;(Mainline development) is an extremely effective way of developing, and the only one which enables you to perform continuous integration.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— Continuous Delivery: Jez Humble &amp;amp; David Farley&lt;/p&gt;

&lt;p&gt;Many arguments that dismiss TBD as impractical for their team often are centred around &lt;strong&gt;fear, and a lack of trust&lt;/strong&gt;. If you’re a leader of a team, don’t dodge these issues with walls and process. Deal with it. &lt;/p&gt;

&lt;p&gt;Pull-requests work excellently in the open-source, where you can't trust external contributors. &lt;em&gt;For your closed-source, day job though? &lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/jezhumble/status/1415908836439773185/photo/2"&gt;Despite abundant evidence that trunk-based development practices contribute to better software delivery performance, some developers who are used to the GitHub-recommended workflow remain skeptical&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— 2017 State of DevOps Report&lt;/p&gt;

&lt;p&gt;Think about &lt;strong&gt;your context&lt;/strong&gt;, examine how work flows through your system, set a WIP limit and stick to it. Find ways to improve the flow and your team’s performance will improve.&lt;/p&gt;

</description>
      <category>methodology</category>
      <category>git</category>
    </item>
    <item>
      <title>The TDD Thinking Hats</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Fri, 25 Jun 2021 09:02:19 +0000</pubDate>
      <link>https://forem.com/quii/the-tdd-thinking-hats-2355</link>
      <guid>https://forem.com/quii/the-tdd-thinking-hats-2355</guid>
      <description>&lt;p&gt;When working with people who are learning test-driven development (TDD), I have a habit of talking about “the hat we’re wearing”. &lt;/p&gt;

&lt;p&gt;This comes from reading the book &lt;a href="https://en.wikipedia.org/wiki/Six_Thinking_Hats"&gt;Six Thinking Hats&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The premise of the method is that the human brain thinks in a number of distinct ways which can be deliberately challenged, and hence planned for use in a structured way allowing one to develop tactics for thinking about particular issues. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When a group wears a particular hat, they engage and discuss an idea in a deliberate way. For instance, if the group wears the yellow hat, they should think positively about an idea, even if that feels unnatural to them. This means everyone explores positives in something, even if individuals within the group have some biases against it.&lt;/p&gt;

&lt;p&gt;I’ve seen developers who mix up the steps in TDD, where they are refactoring whilst the tests are failing, and they are trying to introduce new behaviour at the same time. These same developers frequently skip the explicit refactoring step too, so they make the whole process more difficult and still end up with code that requires a lot of improvement. &lt;/p&gt;

&lt;p&gt;I find trying to have a more focused, deliberate mindset during the TDD steps helps me practice it more effectively, simply, and avoid some common TDD pitfalls. &lt;/p&gt;

&lt;p&gt;This posts attempts to describe the hats you should wear during the TDD steps.&lt;/p&gt;

&lt;p&gt;TDD &lt;em&gt;feels right&lt;/em&gt; when you’re not wearing any single hat for a long time. If you’re switching through them frequently, that’s telling you that you’re iteratively making positive progress on the system. &lt;/p&gt;

&lt;h2&gt;
  
  
  When writing a new test: The green, ambitious hat
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Write the test you want to see&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this situation, we should be &lt;strong&gt;consumer focused&lt;/strong&gt;, and &lt;strong&gt;optimistic&lt;/strong&gt; about the kind of code we’re going to write. &lt;/p&gt;

&lt;p&gt;It can be helpful to ask yourself “if this code already existed in the open-source world, how would I want to use it, and how should it behave?” Try to be &lt;strong&gt;ambitious&lt;/strong&gt;, you get to design the API by describing how it would be used by a consumer, in this case your test.&lt;/p&gt;

&lt;p&gt;Take pride in the test you write, keep asking yourself whether the test describes the what and why effectively. Have &lt;strong&gt;empathy&lt;/strong&gt; for your colleagues who’ll be reading and maintaining these tests. &lt;/p&gt;

&lt;p&gt;At the same time, think about how you can cut scope sensibly, so you are confident that you’ll be able to make the test pass and have this positive change committed to source control in a reasonable amount of time. Have an eye on the end-state, but keep thinking about each small step toward that goal.&lt;/p&gt;

&lt;p&gt;Aim to wear this hat frequently, but for short periods, so that you’re working iteratively with fast feedback loops on your decisions. &lt;/p&gt;

&lt;h3&gt;
  
  
  But, I don’t feel confident
&lt;/h3&gt;

&lt;p&gt;This is normal! The first step, is often the hardest. There can be numerous reasons why writing a test is difficult:&lt;/p&gt;

&lt;h4&gt;
  
  
  The existing test suite is a hot mess
&lt;/h4&gt;

&lt;p&gt;Adding a new test to an existing suite can be difficult for various reasons. Perhaps the existing tests are poorly written. Often they are a reflection of poor design, such as lots of complicated mock setup. &lt;/p&gt;

&lt;p&gt;This might be time to reflect on the design of the code, and it may be prudent to pick up the blue hat to update the design of your system to facilitate the next change.&lt;/p&gt;

&lt;h4&gt;
  
  
  I don’t really know what I’m trying to make
&lt;/h4&gt;

&lt;p&gt;Talk to your colleagues and stakeholders. Ask them what they think might be the first valuable step. If you don’t understand the problem you’re trying to solve, it’s going to be impossible to write a test for it. &lt;/p&gt;

&lt;p&gt;You may wish to invest some time moving up a few abstraction levels to create an acceptance test to give you a more clearly defined north-star.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the tests are failing: The red, uncomfortable to wear hat
&lt;/h2&gt;

&lt;p&gt;When practicing TDD effectively, you’ll wear this hat frequently, but it should feel deliberate when you do, and &lt;em&gt;you should never be wearing it for very long&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When the tests are failing, &lt;strong&gt; you should feel uncomfortable&lt;/strong&gt;. Your software is not working correctly.&lt;/p&gt;

&lt;p&gt;Endeavour to get the tests passing (green) as quickly as possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You’re not safe to make changes that are not directly related to passing the test&lt;/strong&gt;, as you’ve lost your safety net. Any further changes not dedicated to making the tests pass can make the situation worse by adding confusion and complexity. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make the test work quickly, committing whatever sins necessary in the process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;-- Kent Beck&lt;/p&gt;

&lt;p&gt;It’s important to be thinking about good source control practice. Once you get the tests passing again, commit your changes. If you ended up wearing this hat during refactoring, it’s often better not to be precious about the code you wrote, just revert it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stop wearing multiple hats at once
&lt;/h3&gt;

&lt;p&gt;In my experience, many developers wear too many other hats whilst wearing this one in particular, and can make life difficult for themselves because by introducing more changes tends to make the failing test situation worse.&lt;/p&gt;

&lt;p&gt;Too often, developers worry too much about writing "beautiful code" and get distracted away from the goal, which is &lt;strong&gt;to make the software work&lt;/strong&gt;. We’ll have time to make the code great once we’ve made the test pass. &lt;/p&gt;

&lt;h2&gt;
  
  
  When you’re refactoring: The blue, confident hat
&lt;/h2&gt;

&lt;p&gt;We are free to be &lt;strong&gt;creative&lt;/strong&gt;! Maybe you were thinking about a design with the Red hat or the Green hat on - now is the time you can try it out. &lt;/p&gt;

&lt;p&gt;We feel &lt;strong&gt;safe&lt;/strong&gt; to make improvements because we get fast and reliable feedback that whatever changes we’re doing are valid. This allows us to aggressively refactor and &lt;strong&gt;take pride in our work&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make a positive change&lt;/li&gt;
&lt;li&gt;Verify the change is valid by running your unit tests.&lt;/li&gt;
&lt;li&gt;Commit the change to source control&lt;/li&gt;
&lt;li&gt;Go to 1&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All our efforts are backed by tests against real, desired behaviour, so design decisions we make will be “real”, rather than for imaginary concerns. &lt;/p&gt;

&lt;p&gt;When wearing this hat we get to improve the code, &lt;strong&gt;experiment and learn&lt;/strong&gt; what works. Be brave and try different approaches to improve the code. If it doesn’t work out, it’s not a problem, as you’ll always be able to get back to working code with a &lt;code&gt;git checkout src/whatever&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Wearing this hat frequently through your day will steadily make you a better developer because you get more chances to experiment and learn. &lt;/p&gt;

&lt;p&gt;If you have an idea for an improvement that you think will take many hours, pause for a moment. It might be worth going through a few more TDD cycles before making this commitment. By adding more tests, and therefore more behaviour; you are giving yourself more concrete information to make better design decisions. &lt;/p&gt;

&lt;p&gt;Like the other hats, don’t let your head get hot wearing it for many hours in a row, as you might end up in a refactoring rabbit-hole. &lt;em&gt;Little and often is the key&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wearing the hats while pairing/mobbing
&lt;/h2&gt;

&lt;p&gt;Six Thinking Hats says that everyone should be wearing the same hat at the same time, so that the group remains focused on the particular task, and you don’t end up moving in different directions and getting distracted. &lt;/p&gt;

&lt;p&gt;For instance, the group could be wearing the red hat, but you can see a way the code could be improved. Don’t break the group’s flow, just take a note and bring it up when you’re all wearing the blue hat. Remember, if you’re practicing TDD well, you’ll be switching hats frequently through the day.&lt;/p&gt;

&lt;p&gt;If you’re a more experienced member of the group, perhaps you can try using this thinking tool as a way of moderating how your team works through a problem more deliberately, and with better focus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you wear these hats?
&lt;/h2&gt;

&lt;p&gt;To those who feel confident and proficient with TDD, do these feelings and behaviours resonate with your experience? Do you disagree or do you have anything that’s missing here? &lt;a href="https://twitter.com/quii"&gt;Please reach out to me on Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Why of TDD</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Fri, 28 May 2021 14:42:37 +0000</pubDate>
      <link>https://forem.com/quii/the-why-of-tdd-3e6f</link>
      <guid>https://forem.com/quii/the-why-of-tdd-3e6f</guid>
      <description>&lt;p&gt;Many people have false starts with test-driven development (TDD). When I discuss it with people, many have some misunderstandings around the method, in particular the motivations behind it.&lt;/p&gt;

&lt;p&gt;I believe if developers have a better understanding of why to use it, they’ll have a better chance of practicing TDD more effectively and get more value out of it.&lt;/p&gt;

&lt;p&gt;This posts explores the reasons for using TDD and offers some guidance as to how to practice it more effectively.&lt;/p&gt;

&lt;p&gt;I was invited to speak about this topic at the GoSG, a meet-up for the Go programming enthusiasts in Singapore. &lt;a href="https://www.youtube.com/watch?v=-VKs3rrSHF8&amp;amp;t=2714s" rel="noopener noreferrer"&gt;You can find the recording on YouTube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.growing-object-oriented-software.com" rel="noopener noreferrer"&gt;This post quotes Growing Object-Oriented Software Guided by Tests (GOOS)&lt;/a&gt; (written by Steve Freeman and Nat Pryce) extensively as it aligns very closely with how I was taught TDD. I strongly suggest grabbing a copy and giving it a read. Ignore that the examples are in Java, the main lessons from the book are broadly language-agnostic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you’re new to software development, there’s several knowledge hurdles you need to leap over. The one you’ll be judged on the most is your ability to use the tools in front of you to get stuff working and get it to the customers. How well you do this and how delightful the result can be referred to as &lt;strong&gt;external quality&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once you get proficient at this, the main challenges facing mid-level and above are to do with &lt;strong&gt;internal quality&lt;/strong&gt;. This focuses on your ability to work on and design systems so that the cost of change is reasonable. This is important because if a system is useful, it will have to change over its lifetime.&lt;/p&gt;

&lt;p&gt;When talking to non-technical folk about this, you can use an analogy of the quality of a factory, and its equipment. If parts of your machinery are unreliable or hard to deal with, the factory will begin to grind to a halt. This is also true of software. &lt;strong&gt;If internal quality declines, the ability to affect the external quality of the software will decline too&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are a lot of software developers out there who can bash the code out enough to make useful software. A problem in our industry is we’re often incentivised and praised by our ability to work through “tickets” quickly and trying to hit (often arbitrary) deadlines. Frequently though, the internal quality gets neglected, and we hear these stories over and over again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why is the estimate for changing the system 3 weeks? It should be 3 days!&lt;/p&gt;

&lt;p&gt;We need to spend a month re-writing the Foobar module.&lt;/p&gt;

&lt;p&gt;I can’t stand to work on this legacy system again. Please let me move to a different project, or I’ll find somewhere else to work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are fewer developers who can write software that can live for many years without painful re-writes and staggering maintenance costs. The reason simply is, it’s really hard. It requires effort and study. I’ve been writing software for over 15 years and I still find it hard and feel the need to keep studying and reflecting.&lt;/p&gt;

&lt;p&gt;There are developers and stakeholders who have advanced skills in justifying reasons for not caring about internal quality. They’ll say things like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The only thing that matters is working software&lt;/p&gt;

&lt;p&gt;What about time to market?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;All&lt;/em&gt; worthwhile systems have to be changed (see &lt;a href="https://en.wikipedia.org/wiki/Lehman's_laws_of_software_evolution" rel="noopener noreferrer"&gt;Lehman’s laws of software evolution&lt;/a&gt;). &lt;strong&gt;“All that matters is working software” can’t be used as an excuse for poor internal quality today when you will have to change the external quality tomorrow.&lt;/strong&gt; People tend to under-estimate the costs of poor internal quality and &lt;em&gt;over-estimate&lt;/em&gt; the cost of keeping internal quality high.&lt;/p&gt;

&lt;p&gt;You need to be thinking about the design of your system because the problem you are solving is different to everyone else’s. Domain knowledge (or lack-of) has a giant impact on what designs are suitable, so no single blog post can tell you how to design &lt;em&gt;your&lt;/em&gt; system. It’s your responsibility as an engineer.&lt;/p&gt;

&lt;p&gt;Many developers work in environments which have a real fear around speed of delivery, and you can get tempted in to short-term promises of productivity. A new programming language! &lt;a href="https://dev.to/gypsydave5/why-you-shouldnt-use-a-web-framework-3g24"&gt;A shiny new framework&lt;/a&gt;. Even folder structures in the Go community seem to be endlessly discussed as some kind of silver-bullet to good software. Chasing these things is a distraction and is not equipping you to strengthen your skills at writing software with high internal quality, you’re just learning &lt;em&gt;another thing&lt;/em&gt; that will be unfashionable in a few years.&lt;/p&gt;

&lt;p&gt;This is why I think TDD is such a valuable method. It gives you a structured way to confront and think about the internal quality of &lt;strong&gt;your&lt;/strong&gt; system. TDD is a skill which can work in any context, &lt;a href="https://twitter.com/quii/status/1396731981698842625" rel="noopener noreferrer"&gt;even on Mars&lt;/a&gt;. It is an excellent tool for training yourself and your team to design better software.&lt;/p&gt;

&lt;p&gt;TDD can be seen as a developer frivolity that slows teams down. This is true when you are first learning it (like any skill) but with practice and training, you’ll find yourself working at a sustainable pace and consistently delivering value. &lt;strong&gt;High internal quality will facilitate improvements to external quality&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/adamluzsi" rel="noopener noreferrer"&gt;Adam Luzsi &lt;/a&gt;points out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;… most people who start to learn TDD, are also in the process of learning software design implicitly through TDD. And this causes the feeling of "this slows me down".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;High internal quality is not exclusive to practitioners of TDD but if you’re on the fence about TDD I hope this post encourages you to take another look. Maybe at least make you reflect on your own methods for writing great software.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is TDD?
&lt;/h2&gt;

&lt;p&gt;Test-driven development is conceptually simple to follow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a test for a small, desired behaviour&lt;/li&gt;
&lt;li&gt;See it fail&lt;/li&gt;
&lt;li&gt;Write just enough code to make it pass&lt;/li&gt;
&lt;li&gt;Refactor&lt;/li&gt;
&lt;li&gt;Go to 1 for next increment of behaviour&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Yet, there appears to be many developers diverging a lot from what was described by Kent Beck and others.&lt;/p&gt;

&lt;p&gt;This inconsistency makes discussing the merits of TDD difficult because every so often what someone believed to be a typical TDD process seemed to be following a TDD-like process but getting key parts of it wrong.&lt;/p&gt;

&lt;p&gt;Why does this happen? I think tech in general suffers a problem of being extremely faddy and people not really understanding &lt;em&gt;why&lt;/em&gt; they are adopting a particular framework or technique. &lt;strong&gt;If you don’t understand what TDD is for, you’re unlikely to practice it effectively.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So, why test-driven development?
&lt;/h2&gt;

&lt;p&gt;Here are the typical answers you’ll get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevent defects&lt;/li&gt;
&lt;li&gt;Good test coverage&lt;/li&gt;
&lt;li&gt;Confidence to refactor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rightly some will argue:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These benefits are not unique to writing tests first&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why write tests &lt;strong&gt;first?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It’s worth exploring the why of TDD in detail as I believe it helps clarify &lt;strong&gt;how to use the method effectively&lt;/strong&gt;. Many people have false starts with TDD.&lt;/p&gt;

&lt;p&gt;GOOS picks up on this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We’ve seen teams that write tests and code at about the same time where the code is a mess and the tests just raise the cost of maintenance. They’d made a start but hadn’t yet learned that the trick … to let the tests guide development.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  You have to know what behaviour you’re trying to build to write a test
&lt;/h3&gt;

&lt;p&gt;Developers go too fast, diving in to code and letting their imaginations run wild.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/jocrossick" rel="noopener noreferrer"&gt;Jo Crossick on Twitter&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When I write tests first, it's because I know that I'm itching to write over-complicated, over-ambitious code that is destined to become a hot mess, and tests is the only thing that can hold me back from creating instant technical debt&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A lack of method to the design process can lead to software designed against loose, ill-defined requirements. This design can quickly become a drag on the team’s productivity. It can confuse developers, baking-in to your system assumptions that are untrue and behaviours that aren’t actually needed.&lt;/p&gt;

&lt;p&gt;Writing a test first &lt;strong&gt;demands you precisely define, and focus on what you’re trying to achieve; this is a key part of the design process&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing a test first means you have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;remove any ambiguity, meaning you have to &lt;strong&gt;really understand the behaviour you need&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;cut down the scope to a small piece of useful functionality, &lt;strong&gt;liberating you from having to design the whole system&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than having to be somehow clever enough to know all the requirements the system would ever need and committing to a design, instead you design code for behaviour you have precisely defined. You design, for one thing at a time, and you do it properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  It offers a fast and continuous feedback loop on your design
&lt;/h3&gt;

&lt;p&gt;Writing a test gives you a sense of the design of a particular unit &lt;strong&gt;at the beginning&lt;/strong&gt;. Many developers will dive in, creating types and abstractions for hours on end and only when they plug it all together and run their application do they begin to see the flaws in their design. &lt;strong&gt;Until code is executed and the behaviours observed, the design has had no &lt;em&gt;real&lt;/em&gt; validation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With TDD you get feedback at the start and as you iterate through more behaviour you will keep getting guidance from your tests. There is no faster way of getting feedback on your design than by declaring what success looks like at the start.&lt;/p&gt;

&lt;p&gt;You will have a sense of progress as you take small, validated steps toward your goal. If practiced well, you won’t end up in situations of having to throw hours or days worth of code away.&lt;/p&gt;

&lt;p&gt;Whilst not being unique to &lt;strong&gt;test-first&lt;/strong&gt;, tests reflect your design back at you. If a test is difficult to read or write, it is telling you something. A key skill for practicing TDD well is to &lt;strong&gt;listen to your tests&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  It gives you momentum and by focusing on internal quality will help you continue to change your software cheaply.
&lt;/h3&gt;

&lt;p&gt;Many developers “spin many plates”, darting from one part of the code to the other, changing different bits of code and in general working in a fairly chaotic way. This way of working makes life difficult and more prone to error and re-work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing a test first acts as a stabiliser&lt;/strong&gt;. This sets you a clear, short-term objective and lets you focus on doing one thing well, rather than worrying about competing concerns.&lt;/p&gt;

&lt;p&gt;The refactoring step improves your chances of maintaining good internal quality which is &lt;em&gt;essential&lt;/em&gt; for a system to be malleable. We’ve all worked on systems where the internal quality is terrible and how frustrating it is how difficult it can be to make a seemingly simple change.&lt;/p&gt;

&lt;p&gt;The iterative nature of TDD means you keep working on achieving one small improvement at a time.&lt;/p&gt;

&lt;h4&gt;
  
  
  It does not slow you down
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.geepawhill.org/2018/04/14/tdd-the-lump-of-coding-fallacy/" rel="noopener noreferrer"&gt;https://www.geepawhill.org/2018/04/14/tdd-the-lump-of-coding-fallacy/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GeePaw has an excellent video which dispels the idea that TDD slows you down. In fact, it's the opposite when you forget about the silly idea that software development's bottleneck is simply typing code. &lt;strong&gt;Thinking is the bottleneck&lt;/strong&gt;, we work in a knowledge-based field and TDD offers us a way to think with clarity.&lt;/p&gt;

&lt;p&gt;It’s true that when you first practice TDD you will go slower than before. In cases where maybe your design skills aren’t as strong as you think, TDD may feel frustrating, but you can use it as a tool to improve your ability to write modular code.&lt;/p&gt;

&lt;p&gt;It’s a skill that has to be learned and practiced but with time you’ll find yourself working quicker, confidently and with more focus.&lt;/p&gt;

&lt;h3&gt;
  
  
  The qualities required to make code unit-testable are good qualities in themselves
&lt;/h3&gt;

&lt;p&gt;GOOS:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“…the effort of writing a test first also gives us rapid feedback about the quality of our design ideas—that making code accessible for testing often drives it towards being cleaner and more modular.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Modular code is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to repurpose and re-use within different contexts&lt;/li&gt;
&lt;li&gt;Focused&lt;/li&gt;
&lt;li&gt;Simple to test&lt;/li&gt;
&lt;li&gt;Small, with clear responsibility&lt;/li&gt;
&lt;li&gt;Easy to understand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many developers have a healthy skepticism to premature abstraction, but it can go too far.&lt;/p&gt;

&lt;p&gt;It is not good to have that &lt;em&gt;what&lt;/em&gt; and the &lt;em&gt;how&lt;/em&gt; of code mixed up within a function featuring 100s of lines of code, with mixed up and complected concerns. Rich Hickey covers the topic of easiness vs simplicity in his incredible talk &lt;a href="https://www.infoq.com/presentations/Simple-Made-Easy/" rel="noopener noreferrer"&gt;Simple Made Easy&lt;/a&gt;. Having all your code in one method is “easy”, but it is not simple.&lt;/p&gt;

&lt;p&gt;Systems built up of modular, &lt;em&gt;cohesive&lt;/em&gt; units are simpler to understand and easier to change.&lt;/p&gt;

&lt;h3&gt;
  
  
  It’s easier to write good tests beforehand
&lt;/h3&gt;

&lt;p&gt;Writing tests after the code is written is challenging to get right. You can end up with tests that may not fail when you want them to, have cryptic error messages or simply not have good coverage. You’ll also fall in to the trap of testing your design, rather than the behaviour (more on this later).&lt;/p&gt;

&lt;p&gt;Writing tests first and seeing them fail helps you validate their usefulness and helps you focus on testing from the consumer’s point of view, rather than the person who wrote it.&lt;/p&gt;

&lt;h3&gt;
  
  
  It requires you to constantly refactor
&lt;/h3&gt;

&lt;p&gt;A key, but often skipped step by novices is the refactoring step. It is far easier and more sustainable to do frequent, small refactors around the code you’re actually working on throughout the day, rather than leaving it for “a refactoring/technical-debt sprint”.&lt;/p&gt;

&lt;p&gt;Ill-factored code makes the system harder to re-design. Often the &lt;em&gt;act&lt;/em&gt; of refactoring reveals designs. As you consolidate code and DRY things up you start to “see” abstractions that can simplify matters.&lt;/p&gt;

&lt;h4&gt;
  
  
  Digression: Refactoring sprints are an absurd idea and point to some real team disfunction
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You want the benefits of increased internal quality &lt;strong&gt;now&lt;/strong&gt;, not in 3 weeks time.&lt;/li&gt;
&lt;li&gt;Everyone knows they are hard to do and frequently fail to give the pay-off you’d hope for.&lt;/li&gt;
&lt;li&gt;It’s your job to maintain internal quality because &lt;strong&gt;that’s what helps you deliver external quality at a reasonable cost&lt;/strong&gt;. Don’t ask for permission to do your job.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
   How to use TDD
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Work iteratively, in small positive steps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Working on a single, small, well-defined thing is simple, and you’re more likely to succeed. You’ll get fast feedback on whether you’re going in the right direction.&lt;/li&gt;
&lt;li&gt;Working on many, large, loosely defined things at once is difficult, and you’re more likely to make mistakes. The feedback loop is slow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When practicing TDD you should always be thinking about how to reach the vague end-state with specific, achievable steps. If you’re writing a unit test that you know will take hours of effort to make it pass, you need to rethink your approach.&lt;/p&gt;

&lt;p&gt;It can be challenging to break work down into small steps, and it will also challenge your design skills but working this way means you are more likely to succeed, and you’ll reduce waste.&lt;/p&gt;

&lt;h4&gt;
  
  
  When TDD feels right
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Constant, small progress throughout the day. Never feels slow, feels deliberate.&lt;/li&gt;
&lt;li&gt;Frequent commits to source control per hour.&lt;/li&gt;
&lt;li&gt;Work feels “safe”, less chaotic than maybe you’re used to.&lt;/li&gt;
&lt;li&gt;Mistakes are rarely large. Happy to revert changes if you realise you’ve gone down a wrong path.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Writing the test first
&lt;/h3&gt;

&lt;p&gt;There’s a difference between knowing to write a test first and doing it in a way that helps you design your software.&lt;/p&gt;

&lt;p&gt;GOOS:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We want each test to be as clear as possible an expression of the behaviour to be performed by the system or object. While writing the test, we ignore the fact that the test won’t run, or even compile, and just concentrate on its text”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Rather than worrying about &lt;em&gt;how&lt;/em&gt; the code will work at this point, &lt;strong&gt;concentrate on the behaviour, particularly from the user’s point of view&lt;/strong&gt;. It’s essential you block out implementation detail from your head at this point in the process because you’re just trying to nail down exactly &lt;em&gt;what&lt;/em&gt; you want to achieve.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;what and the how are two separate design activities&lt;/strong&gt; which are too often mixed up, which makes coherent decision-making more difficult than it needs to be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Focus on being precise and limited in scope&lt;/strong&gt;, this will help you uncover assumptions and help you keep focused.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TDD is an iterative approach to development&lt;/strong&gt;. When you are writing your tests you should be mindful of how to keep the work moving with fast feedback loops and small positive steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start from the top down for new features
&lt;/h3&gt;

&lt;p&gt;TDD is focused on letting you design for the behaviour you precisely need, iteratively. When starting on a new area you need to identify a key, important behaviour and then aggressively cut scope.&lt;/p&gt;

&lt;p&gt;From there you want to take a “top down” approach, starting with an acceptance test (AT) that exercises the behaviour from the outside. This will act as a north-star for your efforts. All you should be focused on is making that test pass. This test will likely be failing for a while whilst you develop enough code to make it pass.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FpxTaYu4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FpxTaYu4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have your AT set up you can then break into the TDD process to drive out enough units to make the AT pass. The trick is to not worry too much about design at this point, just get enough code to make the AT pass because at this point you’re still learning and exploring the problem.&lt;/p&gt;

&lt;p&gt;Taking this first step is often bigger than you think, setting up web-servers, routing, configuration e.t.c, which is why keeping the scope of the work small is important. We want to make that first positive step on our blank canvas, have it backed by a passing AT so that we can then continue to iterate quickly and safely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Ft5y5opw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Ft5y5opw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you develop, listen to your tests, and they should give you signals to help you push your design in a better direction but again, anchored to the behaviour rather than our imagination.&lt;/p&gt;

&lt;p&gt;Typically, your first “unit” that does the hard work to make the AT pass will grow too big to be comfortable, even for this small amount of behaviour. This is when you can start thinking about how to break the problem down and introduce new collaborators.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FUYqd7Cq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FUYqd7Cq.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where test-doubles are very useful because most of the complexity that lives internally within software doesn’t usually reside in implementation detail, but “between” the units and how they interact with each other.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
The design "outside the braces" is what often has 
the biggest impact on internal quality
*/

func NewStockCheckHandler(
    stockChecker StockChecker, 
    productStore ProductStore,
) http.Handler {

/* 
implementation detail inside the braces is usually 
low thrills and simple to test
*/

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can use test-doubles to explore the interactions between our collaborators with a much tighter feedback loop than if we tried to design and develop units isolated and then integrate them later.&lt;/p&gt;

&lt;p&gt;For further iterations we may not need to write a new AT, we can simply add new behaviours to our existing units at a faster pace than the first one. We’ve made our first step, and we’re confident that we’re not developing them blindly because the units are integrated with the rest of the system.&lt;/p&gt;

&lt;h4&gt;
  
  
  On “TDD-ing a design”
&lt;/h4&gt;

&lt;p&gt;Too often people assert that TDD is only compatible with a “bottom-up” approach where you imagine a bunch of abstractions up-front and then you “TDD them”.&lt;/p&gt;

&lt;p&gt;This is called “TDD-ing a design”. You’re not using TDD as a design method, merely a way of writing tests around some code. This often results in classes or functions being overly developed in isolation for extended periods and then only when you try to integrate them into the system and use them you realise the design is wrong.&lt;/p&gt;

&lt;p&gt;This is the point where people declare TDD to be a poor design tool when in practice, they already had a design in their head and just added a very long feedback loop to it, exhaustively testing code and various edge-cases before &lt;em&gt;using it in their actual system&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Remember that TDD demands we start with a test for a desired &lt;em&gt;behaviour,&lt;/em&gt; not a &lt;em&gt;design&lt;/em&gt;. This is very much “top down” development. When done correctly you stop “over-designing” and you write and design the code you actually need.&lt;/p&gt;

&lt;p&gt;By TDD-ing a design you can fall into the trap of tests being tightly coupled to implementation rather than behaviour. This becomes extremely problematic when you want to change your implementation detail and your tests will become a burden. &lt;a href="https://quii.dev/The_Tests_Talk" rel="noopener noreferrer"&gt;I talk about this in detail in “The Tests Talk”.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Listen to your tests
&lt;/h3&gt;

&lt;p&gt;If you follow the TDD process well you should end up with modular, loosely coupled, cohesive units within your system. This journey is rarely smooth. As requirements and knowledge changes your design will have to evolve with it.&lt;/p&gt;

&lt;p&gt;Tests can offer you a &lt;em&gt;focused lens&lt;/em&gt; into areas in your system where you can view the impact of your design isolated, which makes it far easier to appraise. &lt;strong&gt;Tests reflect your design back at you&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here are some common test smells to look out for. Commit them to memory, and you’ll be able to raise some interesting questions about your design to answer.&lt;/p&gt;

&lt;h4&gt;
  
  
  High number of test-doubles (mocks), complicated setup
&lt;/h4&gt;

&lt;p&gt;This is telling you that the unit under test has to collaborate with many things, this pain in your test world will be multiplied in all the cases you want to use this unit.&lt;/p&gt;

&lt;p&gt;This pain can sometimes feel hidden in the “real” usages but comes apparent when you start to change things and feel the pain of the tight and inappropriate coupling. You should be asking yourself why this unit has to collaborate with so many other things.&lt;/p&gt;

&lt;p&gt;It points to leaky abstractions which could be remedied by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look at the test doubles. Are you having to mock out lots of methods? Perhaps you can consolidate this interaction into another more cohesive unit

&lt;ul&gt;
&lt;li&gt;Maybe the unit itself has too many, unrelated behaviours. See if you can come up with a more cohesive design.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Unclear intent
&lt;/h4&gt;

&lt;p&gt;Does your test &lt;em&gt;really&lt;/em&gt; explain the code’s behaviour and why?&lt;/p&gt;

&lt;p&gt;GOOS:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A test called testBidAccepted() tells us what it does, but not what it’s for.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the test is unclear it could mean the responsibilities of the unit being tested is unclear and warrants a redesign.&lt;/p&gt;

&lt;h4&gt;
  
  
  Wide scope
&lt;/h4&gt;

&lt;p&gt;This points to a lack of focus. Perhaps you need to break the problem down in to smaller parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Value the quality of your tests
&lt;/h3&gt;

&lt;p&gt;Start being more attentive about the quality of your test code. This will result in you writing tests that are cheaper to maintain and will challenge you to write more focused, modular code resulting a better designed system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing high-quality tests is cheaper than maintaining poorly written ones&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a high-performing team where it must respond to client needs quickly and cheaply, good tests will enable them to have a productive experience. The opposite is also true.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Write the tests you want to see&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The easiest, most generic feedback I give to my colleagues is asking them to explain their tests out-loud. Often it’s harder than they imagine, even when the tests appear terse; and then an interesting conversation about the design almost always follows.&lt;/p&gt;

&lt;p&gt;Reflect on the tests you have now. Do they express the intent of the behaviour well? Do they describe the &lt;em&gt;why&lt;/em&gt; clearly? If not, what would it take? Is it a simple refactoring of your tests or does it require some redesign?&lt;/p&gt;

&lt;h3&gt;
  
  
  Be attentive when you watch the test fail
&lt;/h3&gt;

&lt;p&gt;Be sure it fails the way you expect and that it fails with a clear message. If you skip this step you may be glossing over design decisions, or perhaps you don’t understand the requirements clearly enough.&lt;/p&gt;

&lt;p&gt;Usually making the test fails “nicely” is a multi-step process, but it’s important to go through the steps until you get a satisfactory failure message due to your code not exhibiting the failure you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  View being in “the red” as something to get out of as soon as possible
&lt;/h3&gt;

&lt;p&gt;You should be running your unit tests extremely frequently, which is why it’s important they run quickly and don’t depend on slow things like the network or file-system.&lt;/p&gt;

&lt;p&gt;If at any point your tests are failing (so you’re in the red), you should be thinking about the shortest path to get back to “green”.&lt;/p&gt;

&lt;p&gt;Often the safest way to do this is to revert your changes. By working in small increments this should never feel like a big deal.&lt;/p&gt;

&lt;p&gt;It is forbidden to refactor or redesign code in the red state because your feedback loop as to whether the changes are valid is broken.&lt;/p&gt;

&lt;h3&gt;
  
  
  Commit your work frequently
&lt;/h3&gt;

&lt;p&gt;To be able to use your tests to help you guide your design they need to be green, but it’s inevitable that sometimes you’ll go down the wrong path and want to get back to safety. It’s therefore critical that you practice good source control practices and commit your work frequently.&lt;/p&gt;

&lt;p&gt;I usually commit my work once I’ve made the test pass and that means if I get into a bad state during refactoring I can easily get back to working software again.&lt;/p&gt;

&lt;p&gt;So much of applying TDD is working in small, safe steps, so your mind is freer to think about the design of your system rather than juggling multiple concerns at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refactor aggressively when in the green
&lt;/h3&gt;

&lt;p&gt;Most of the time your system should be in a state when you can refactor freely.&lt;/p&gt;

&lt;p&gt;Ill-factored code is problematic because it becomes hard to understand, which makes it harder to re-design. The process of refactoring in general will reveal improvements in the design for you.&lt;/p&gt;

&lt;p&gt;Read Martin Fowler’s refactoring book and get in to the habit of applying common refactors. A lot of code I observe is not well-factored, but the good news is it’s a relatively easy skill to learn and once you’re proficient takes a matter of seconds or minutes to perform; in particular with help from your IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;If you don’t practice TDD, what is your method for designing software? You do you! Can you describe your method to someone else, so they can follow a similar approach? It’s healthy to retrospect on how you work, to see if there are ways to improve.&lt;/p&gt;

&lt;p&gt;No matter your design method, internal quality is essential for the productivity of your team. So many systems suffer from poor productivity and high costs because some developers and teams will neglect internal quality. It’s a false-economy to ignore internal quality and the pace at which you will be able to affect the external quality of the system will decrease quickly if you do.&lt;/p&gt;

&lt;p&gt;It is of course possible to have software with high internal quality without practicing TDD, but I am not especially clever and want an easy life.&lt;/p&gt;

&lt;p&gt;When I design up front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it’s often wrong&lt;/li&gt;
&lt;li&gt;I have to think about too many things at once&lt;/li&gt;
&lt;li&gt;I design for things I don’t need&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TDD offers a methodical, incremental way of designing code which feels like a simpler, more evidence-based way of creating useful, malleable software.&lt;/p&gt;

&lt;p&gt;Stick to the simple TDD process, listen to your tests and practice. This should result in you designing software, verified against concrete desired behaviours; rather than your imagination.   &lt;/p&gt;

</description>
      <category>tdd</category>
      <category>testing</category>
      <category>design</category>
    </item>
    <item>
      <title>How my website works</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Thu, 27 Aug 2020 14:47:52 +0000</pubDate>
      <link>https://forem.com/quii/how-my-website-works-22f2</link>
      <guid>https://forem.com/quii/how-my-website-works-22f2</guid>
      <description>&lt;p&gt;I recently redesigned &lt;a href="https://quii.dev"&gt;my website&lt;/a&gt;. It’s not exactly a technical marvel, but I feel that is its strength, and I wish more projects I observed prioritised delivering useful content rather than expensive to implement designs. &lt;a href="https://quii.dev/The_Web_I_Want"&gt;Most people just want to read some text and look at some pictures&lt;/a&gt; and it’s extremely easy to do this if you don’t tie yourself up in flavour-of-the-month technologies.&lt;/p&gt;

&lt;p&gt;On the way I got a chance to brush up on some of the more modern CSS techniques which was a lot of fun. People who complain about modern-day web development don’t know how lucky they’ve got it. &lt;/p&gt;

&lt;p&gt;There’s so many fantastic techniques and tools built into web browsers compared to 10 years ago that don’t require a lick of JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  The approach
&lt;/h2&gt;

&lt;p&gt;Under-the-hood not much has changed. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server has a &lt;code&gt;posts&lt;/code&gt; folder which contains markdown files for each post.&lt;/li&gt;
&lt;li&gt;The web server is written in Go. When it starts up it opens up every markdown file, converts it into HTML and puts it in an in-memory map. &lt;/li&gt;
&lt;li&gt;When it gets requests, the server simply looks at the path and matches it to a key in the map of posts, returning the pre-rendered post.&lt;/li&gt;
&lt;li&gt;The frontend is plain HTML and CSS because it’s the best, simplest, most performant way of delivering textual content to users. &lt;/li&gt;
&lt;li&gt;It is deployed to Heroku and sits behind CloudFlare CDN. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ll use the simplest tools I can to deliver a good experience. This will sometimes rely on using CSS techniques that won’t work on older browsers. This is fine so long as my content is still accessible and looks &lt;em&gt;ok&lt;/em&gt;. This is called "graceful degradation".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Graceful_degradation"&gt;Graceful degradation is a design philosophy that centers around trying to build a modern web site/application that will work in the newest browsers, but falls back to an experience that while not as good still delivers essential content and functionality in older browsers.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  New things I learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties"&gt;CSS Variables&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;On the face of it they seem like a nice way to DRY up some code and give some semantics to things like colours. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:root {
    --nav-colour: hsla(354, 100%, 71%, 1);
    --link-colour: hsl(354, 100%, 71%);
    --bg-colour: hsla(30, 100%, 99%, 1);
    --code-colour: hsla(327, 24%, 35%, 1);
    --text-colour: hsla(280, 12%, 20%, 1);
    --header-colour: hsla(280, 12%, 20%, 1);

    --font-size: 2.2rem;
    --line-height-multiplier: 1.5;
}

time {
    color: var(--code-colour);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I think they’re an interesting way of identifying the complexity of your design. If you give yourself the constraint that the only place you’re allowed to declare a colour value is within your variables then you’ll have a well-organised list of colours on your website. If that list gets long, or it becomes hard to name your variables ask yourself&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do I really need all these colours for my website? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can take the same line of thinking in respect to the variables you use with your typography and your general spacing. By using variables it forces you to &lt;strong&gt;think&lt;/strong&gt; and will help give your design a more consistent and less cluttered feel. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme"&gt;Media query for dark mode&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Dark-mode feels pretty faddy to me but I am pleased there is a nice progressive way to change the style of your website without relying on any wonky JavaScript. &lt;/p&gt;

&lt;p&gt;If supported, my website will automatically change into dark-mode with no prompting from the user. In OS X you can set dark mode to automatic which will go from light mode to dark through the day and my website will respect the user’s wish. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--laO6FkYf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/mwvLVrg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--laO6FkYf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/mwvLVrg.png" alt="Dark &amp;amp; light mode in OS X"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This feels much better than expecting users to have to update some kind of setting on every website they visit. &lt;/p&gt;

&lt;p&gt;This works especially well with CSS variables. To enable dark-mode all I had to do was change the value of my variables. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media (prefers-color-scheme: dark) {
    :root {
        --nav-colour: #15B097;
        --link-colour: #3282b8;
        --bg-colour: #051923;
        --code-colour: #15B097;
        --text-colour: #EDF6F9;
        --header-colour: #1C77C3;
    }

    img {
        filter: brightness(.8) contrast(1.2);
    }

    body {
        font-weight: 350;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Easy! &lt;/p&gt;

&lt;h3&gt;
  
  
  Fallback for older browsers
&lt;/h3&gt;

&lt;p&gt;Without any effort, my website is still useable for users of Internet Explorer (and probably Netscape Navigator).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AcerFFMf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/FsuA3eZ.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AcerFFMf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/FsuA3eZ.jpg" alt="IE11 without any fallback"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Web browsers are very forgiving and will do their best effort to render even if they see syntax they don’t understand. As I am relying on robust, battle-tested technology (HTML &amp;amp; CSS) it "works" - the content is still accessible. &lt;/p&gt;

&lt;p&gt;If I had done some react-whizz-bang framework single page app I would have to jump through a lot more hoops to reliably deliver some text.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fallback techniques
&lt;/h4&gt;

&lt;p&gt;Including this in the head of the document means this CSS file will only be loaded by users of IE9 and older.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!--[if lte 9]&amp;gt;
    &amp;lt;link rel="stylesheet" type="text/css" href="/static/fallback.css"&amp;gt;
&amp;lt;![endif]--&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The following media query lets me style for IE10 and IE11 &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
    body {
        /* IE 10 &amp;amp; 11 specific style declarations */
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I don’t anticipate many users of IE11 or under being especially interested in a programmer’s blog, but it can’t hurt to help them out. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QP9KfQbQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/MAfD5nk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QP9KfQbQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/MAfD5nk.png" alt="the website in IE11"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not pixel-perfect, but it doesn't have to be. I have seen teams spend &lt;em&gt;days&lt;/em&gt; fixing minor pedantic styling issues with Internet Explorer and I can't imagine that's the best way to spend expensive developer time. Are you building websites to satisfy your users or designers?&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pVxzJvfE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/FsvfvBh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pVxzJvfE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/FsvfvBh.png" alt="Screenshot of assets downloaded for the website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All the content delivered and styled in 40ms with under 5kb of payload&lt;/strong&gt;&lt;br&gt;
&lt;i&gt;(excluding post-specific images, which I try to minimise)&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;All these fancy computers we use have an impact on the environment. By taking a minimalist approach my website's carbon footprint is &lt;a href="https://www.websitecarbon.com/website/www-quii-dev/"&gt;cleaner than 99% of the websites tested on websitecarbon.com&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Big deal Chris, it’s only HTML and CSS, it’s not a real website&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yeah, it’s only HTML and CSS, brilliant isn’t it. Easy to make, accessible and performant. I made my first website around 21 years ago, and I find it quite comforting the same technology I worked with then works now. &lt;/p&gt;

&lt;p&gt;I wish more websites were written like this rather than clogging my network and computer with megabytes of useless JavaScript written by developers running transpilers over transpilers on frameworks built on top of other frameworks and for what? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fancy transitions?&lt;/li&gt;
&lt;li&gt;The client not doing a full page refresh going between pages?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do your users actually care about this? &lt;a href="https://quii.dev/archive"&gt;Click between links on my archive page&lt;/a&gt; and tell me it’s too slow and has a bad user experience.&lt;/p&gt;

&lt;p&gt;There are projects where SPAs are a good fit, but many developers are poor at making this decision and add a huge amount of complexity for no real reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Making a static website does not require a fancy blog generator built on top of a gig of &lt;code&gt;node_modules&lt;/code&gt;. &lt;strong&gt;You do not need special tools to make a great website.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even if you’re not a confident “backend” developer you don't &lt;em&gt;have to write a web server&lt;/em&gt; like I did; you can still… create websites with plain old HTML files, written by hand!&lt;/p&gt;

&lt;p&gt;This is a totally legitimate way of making many kinds of websites and will most likely result in the best user experience for the least effort.&lt;/p&gt;

</description>
      <category>html</category>
      <category>css</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Start naming your test doubles correctly</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Thu, 30 Jul 2020 10:07:02 +0000</pubDate>
      <link>https://forem.com/quii/start-naming-your-test-doubles-correctly-oad</link>
      <guid>https://forem.com/quii/start-naming-your-test-doubles-correctly-oad</guid>
      <description>&lt;p&gt;A lot of developers are very vague when they name their test doubles which makes tests needlessly more difficult to understand. &lt;/p&gt;

&lt;p&gt;In conversation there’s also often ambiguities which cause problems&lt;/p&gt;

&lt;p&gt;I overheard on a podcast&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Have you ever used a mock where you make assertions on the call?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This post will hopefully illuminate why that sentence is a bit silly!&lt;/p&gt;

&lt;p&gt;By making a little more effort to be precise with your naming, you can communicate the intent of your tests and the design of your system more effectively&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick primer on dependencies
&lt;/h2&gt;

&lt;p&gt;To separate concerns, we often make objects that will “depend” on other objects. &lt;/p&gt;

&lt;p&gt;We “inject” or “pass in” these dependencies when we construct them, so they can do a job. &lt;/p&gt;

&lt;p&gt;This is called &lt;em&gt;Dependency Injection&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;ShoppingCart&lt;/code&gt; sends an email when its &lt;code&gt;sendOrder&lt;/code&gt; method is called&lt;/p&gt;

&lt;p&gt;We don’t want &lt;code&gt;ShoppingCart&lt;/code&gt; to have to know &lt;em&gt;how&lt;/em&gt; to send emails as well as everything else so we give it an &lt;code&gt;Emailer&lt;/code&gt; when we create it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;new ShoppingCart(new MailgunEmailer())&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It can then use the emailer without having to know &lt;em&gt;how&lt;/em&gt; emails are sent, and you have your separation of concerns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sendOrder() {
    // interesting domain logic
    this.emailer.send(confirmation)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach has implications for our tests. &lt;/p&gt;

&lt;h3&gt;
  
  
  With tests, we prefer not to use real objects for dependencies because we want to be able to control them, so we use something different
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It would not be desirable to send a real email every time a test is run.&lt;/li&gt;
&lt;li&gt;We sometimes depend on things that are slow, but we like our tests to be fast because feedback loops are extremely important &lt;/li&gt;
&lt;li&gt;It would be hard for us to exercise failure scenarios using real dependencies. How do you get a 3rd party email service to deliberately fail?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use “Test Doubles”
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Not&lt;/em&gt; specifically mocks&lt;/p&gt;

&lt;p&gt;A test double is what you inject into an "object under test" (OUT) to control a dependency. &lt;/p&gt;

&lt;p&gt;Like a stunt double!&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the precise words for test doubles helps reveal intent and documents your design more effectively
&lt;/h3&gt;

&lt;p&gt;It’s not about being big and clever, it helps you communicate unambiguously. Software development is a team-sport so clear communication will help your team work better.&lt;/p&gt;

&lt;h2&gt;
  
  
  The different kinds of test doubles
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Dummies
&lt;/h2&gt;

&lt;p&gt;Sometimes you have arguments to functions that you don’t care about. Dummies are the arguments you pass in.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const dummyLogger = jest.fn()&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stubs
&lt;/h2&gt;

&lt;p&gt;Some objects will &lt;em&gt;query&lt;/em&gt; dependencies for data.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stub&lt;/em&gt; the dependency&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const stubUserService = jest.fn(() =&amp;gt; 'Miss Jones')&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Spies
&lt;/h2&gt;

&lt;p&gt;Sometimes you want to call a method (or more abstractly &lt;em&gt;send a command&lt;/em&gt;) to a dependency. &lt;/p&gt;

&lt;p&gt;It can be hard to tell in a test this happened from the outside as it’s an internal detail.&lt;/p&gt;

&lt;p&gt;If you want to verify these commands, use a &lt;em&gt;spy&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const spyEmailSender = jest.fn()
// do some stuff
expect(spyEmailSender.mock.calls.length).toBe(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fakes
&lt;/h2&gt;

&lt;p&gt;Usually a “real” implementation but constrained.&lt;/p&gt;

&lt;p&gt;Like an in-memory database.&lt;/p&gt;

&lt;p&gt;Not as popular anymore due to things like Docker which let you spin up local versions of databases without the risk of there being differences between a fake and a real implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mocks
&lt;/h2&gt;

&lt;p&gt;Mocks are a &lt;em&gt;kind&lt;/em&gt; of test double!&lt;/p&gt;

&lt;p&gt;Mocks are precise and encapsulate the detail of your interactions more explicitly.&lt;/p&gt;

&lt;p&gt;You describe upfront what calls you expect on your test double&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order&lt;/li&gt;
&lt;li&gt;Arguments&lt;/li&gt;
&lt;li&gt;Specific return values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the object under test doesn’t call things as expected the mock will error.&lt;/p&gt;

&lt;p&gt;So returning to &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Have you ever used a mock where you make assertions on the call?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What is being described is just &lt;em&gt;a mock&lt;/em&gt;. If you're not worried about the calls, you're talking about a &lt;em&gt;stub&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why “mocking too much is bad”
&lt;/h2&gt;

&lt;p&gt;The risk is your tests become needlessly precise and coupled to implementation detail.&lt;/p&gt;

&lt;p&gt;This is also true of spies as they have a similar nature.&lt;/p&gt;

&lt;p&gt;If you're overly specific with your mocks, when you want to refactor things you may find tests failing for annoying reasons that have nothing to do with &lt;em&gt;behaviour&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why “having too many test doubles is bad”
&lt;/h2&gt;

&lt;p&gt;Listen to your tests if they cause you pain&lt;/p&gt;

&lt;p&gt;If you have many test doubles in a test &lt;strong&gt;that means your OUT has many dependencies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Does that sound right to you? It shouldn’t and it means you probably need to take a look at your design. &lt;/p&gt;

&lt;h2&gt;
  
  
  An anecdote
&lt;/h2&gt;

&lt;p&gt;Yesterday I reviewed a test which had a double named&lt;/p&gt;

&lt;p&gt;&lt;code&gt;getterFn&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I had to spend some time reading the test to understand what was going on, it turns out it should've been called:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;spyCSVFetcher&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once this was ascertained it turned out the writer had actually neglected to spy on the number of calls, which was actually a core part of what was supposed to be tested.&lt;/p&gt;

&lt;p&gt;If the double had been named correctly in the first place (which is very little effort) I would know to look for assertions on the way it was called to help me understand what the intent of the code is. Instead, it took some investigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Consistently using the recognised names for test doubles will help you be precise when communicating with other developers. It's a low-effort way to improve the way you work.&lt;/p&gt;

&lt;p&gt;For instance if you name something a &lt;code&gt;dummy&lt;/code&gt; rather than a &lt;code&gt;mock&lt;/code&gt; the readers of your tests can forget about that particular test double and focus on the important collaborators. &lt;/p&gt;

&lt;p&gt;Tests should act as documentation so describing your test doubles clearly will help reveal the design of the test for maintainers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quiz
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What does a test with lots of doubles tell you?&lt;/li&gt;
&lt;li&gt;How do you improve the design of a test with many test doubles?&lt;/li&gt;
&lt;li&gt;Name all the kinds of test doubles&lt;/li&gt;
&lt;li&gt;How is a mock different from a spy?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://martinfowler.com/articles/mocksArentStubs.html"&gt;Martin Fowler's post "Mocks aren't stubs"&lt;/a&gt; goes into this topic in great detail.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quii.gitbook.io/learn-go-with-tests/go-fundamentals/dependency-injection"&gt;Learn Go with tests: Dependency Injection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>tdd</category>
      <category>communication</category>
      <category>mocking</category>
    </item>
    <item>
      <title>Work 2019: Building a brand new team</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Sat, 28 Dec 2019 09:31:36 +0000</pubDate>
      <link>https://forem.com/quii/work-2019-building-a-brand-new-team-3708</link>
      <guid>https://forem.com/quii/work-2019-building-a-brand-new-team-3708</guid>
      <description>&lt;p&gt;This post is a summary of work stuff over the past year which covers my first adventures into&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technical leadership and line-management&lt;/li&gt;
&lt;li&gt;Hiring and building a brand new team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think I've helped build a pretty rad team, so if you're interested in that kind of thing, read on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rough start
&lt;/h2&gt;

&lt;p&gt;After working in one of the most productive, interesting and fun teams I've ever had the pleasure to be a part of, the team has to be disbanded due to complicated (and boring) politics.&lt;/p&gt;

&lt;p&gt;We were given freedom to move in to almost any team within the organisation but I &lt;em&gt;really&lt;/em&gt; didn't take our team being disbanded well at all so I think in my eyes every opportunity looked boring and unfulfilling. It was never going to work out.&lt;/p&gt;

&lt;h2&gt;
  
  
  New job
&lt;/h2&gt;

&lt;p&gt;Happily a new opportunity came about with my previous employer. I'd worked there for just under 2 years; it was really enjoyable, I liked the environment and I'm proud of the work we did and how we did it. It felt like we stood behind the good DevOps principles and it worked out well for us. &lt;/p&gt;

&lt;p&gt;This would be a different role though, I would a technical lead. I have been a technical lead before but in a different environment and without the line management responsibility needed for this role.  &lt;/p&gt;

&lt;p&gt;I was a little tentative about this at first. I hadn't been a line manager before and everyone I've spoken to about it to implies it's horrible. My future boss spun it pretty well though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'd get to hire my own team&lt;/li&gt;
&lt;li&gt;I'd get to run it &lt;em&gt;more-or-less&lt;/em&gt; how I like (so long as we deliver, obviously). 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://quii.dev/How_to_go_fast"&gt;He knows I have strong opinions about how teams should be run&lt;/a&gt; and is happy to give me the autonomy to try to make it happen.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I deliberated on this and thought about leads who had worked well with me and those who hadn't. A couple of people who've had the dubious pleasure of managing me have had a real positive effect on my career (and life, I suppose). They pushed me into things I never saw myself doing and gave me confidence to stand behind my convictions.&lt;/p&gt;

&lt;p&gt;When I put all that together with someone giving me this rare opportunity to pay it forward and to help some people find the joy I get out of software-engineering; I had to give it a go. I may never get this kind of opportunity again!&lt;/p&gt;

&lt;h3&gt;
  
  
  My personal goal for this job
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to create great teams who not only deliver good software with minimal stress, and actually enjoy it.&lt;/li&gt;
&lt;li&gt;Grow some engineers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hiring
&lt;/h2&gt;

&lt;p&gt;The initial suggested makeup for my team was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A senior&lt;/li&gt;
&lt;li&gt;A mid-level&lt;/li&gt;
&lt;li&gt;An associate (junior) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now where I work isn't as glamorous as one of these fancy fin-tech startup whatevers, but it &lt;em&gt;is&lt;/em&gt; a good place to work. The environment is great, we're empowered and work in a pretty cutting edge way. We go to DevOps conferences and hear about best practices and we can honestly say we do a lot of them. We deploy many many times per day, deployment is a non-event for us. &lt;/p&gt;

&lt;p&gt;Getting that across to the highly competitive London job market I guess is hard because I had to do &lt;em&gt;a lot&lt;/em&gt; of recruitment effort to eventually get the right people.&lt;/p&gt;

&lt;h3&gt;
  
  
  Diversity and all that
&lt;/h3&gt;

&lt;p&gt;I was determined not to hire 3-4 clones of myself. I am infuriating to work with. Studies show diverse teams have better results. Hiring diverse teams it's the right thing to do too.&lt;/p&gt;

&lt;p&gt;We approached Makers Academy to help us hire as their raison d'etre is bringing people from different backgrounds into software development. I've had a very positive experience working with Makers graduates over the past 5 years, they've always made the teams and people around them better so I wanted more of that.&lt;/p&gt;

&lt;p&gt;It was a fun and intense experience of pitches, chatting to lots of people and interviewing a number of great candidates. If it were up to me we would've hired more but in the end we hired 3 excellent developers who are thankfully nothing like me.&lt;/p&gt;

&lt;h3&gt;
  
  
  The team
&lt;/h3&gt;

&lt;p&gt;The stars aligned quite nicely in that after months of recruitment going nowhere my team of &lt;strong&gt;3 associates and a senior&lt;/strong&gt; more or less joined at the same time. It was super exciting to have a new team suddenly appear in the office.&lt;/p&gt;

&lt;p&gt;Having a brand new team, and role suddenly land on my lap all at once was pretty intimidating at first but the people I hired made it a lot easier because they're all excellent people and I had good support from other people in the department.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I tried to make it work
&lt;/h2&gt;

&lt;p&gt;Before leaving Springer Nature I had a meeting with one of the managers which was more impactful than he probably realises. He said&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You need to take learning management as seriously as you do learning software development. In the end you have a direct effect on people's lives&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OK, it's a bit dramatic but it is true. I reflected on managers who hadn't worked for me and how frustrated and annoyed I was about the situation even outside of work. &lt;/p&gt;

&lt;p&gt;It's definitely a problem that a lot of people seem to think that management comes naturally to certain people and is not a skill to learn and practice.&lt;/p&gt;

&lt;p&gt;So I picked up some books and watched some talks in the hope I could actually achieve my goals and not let my team down.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.amazon.co.uk/Phoenix-Project-DevOps-Helping-Business-ebook/dp/B00AZRBLHO"&gt;The Phoenix Project&lt;/a&gt; &amp;amp; &lt;a href="https://en.wikipedia.org/wiki/The_Machine_That_Changed_the_World_(book)"&gt;The Machine That Changed The World&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;These are two books that talk about the problems you have when trying to build big complicated things with lots of people. They're very different books, &lt;/p&gt;

&lt;p&gt;The Phoenix Project is described as a "DevOps Novel" which sounds lame as hell but is actually really enjoyable. &lt;/p&gt;

&lt;p&gt;The Machine That Changed The World talks about the approaches to manufacturing cars. From artisan bespoke cars, to mass production and then lean manufacturing. It sounds far away from software development but as you read it you find yourself nodding along, drawing parallels with our industry.&lt;/p&gt;

&lt;p&gt;There's &lt;em&gt;loads&lt;/em&gt; to take from them and here are the main bits I got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command and control definitely does not work. You need to empower the people who actually create things to make decisions as they're the people with the most up-to-date, relevant knowledge.&lt;/li&gt;
&lt;li&gt;You &lt;em&gt;must respect work in progress (WIP) limits&lt;/em&gt;. It's way better for a team to properly finish tasks and only work on a small number of things than hurriedly work through dozens of tasks. Disrespect of WIP &lt;em&gt;will&lt;/em&gt; slow you down.
&lt;/li&gt;
&lt;li&gt;A better understanding of "lean". Once you read these two books you have a very clear idea of where agile gets a lot of its ideas from.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I summarise these ideas in more detail in &lt;a href="https://quii.dev/The_ghost_of_Henry_Ford_is_ruining_your_development_team"&gt;The ghost of Henry Ford is ruining your development team&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://abookapart.com/products/resilient-management"&gt;Resilient management&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is a very practical book on technical leadership, it's quite short and I have found it invaluable. It has given me concrete things to do to help build my team.&lt;/p&gt;

&lt;h4&gt;
  
  
  Growing people
&lt;/h4&gt;

&lt;p&gt;It has some fascinating insights between the terms "coaching" and "mentoring" which I share with basically everyone because it really has changed the way I try to help people.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mentoring&lt;/strong&gt; Giving advice and perspective to help someone solve a problem. Quite a direct way of giving information. Good for overcoming roadblocks. Focused on the &lt;em&gt;problem and solution&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coaching&lt;/strong&gt; Asking open questions to explore a topic more. I like to see it as trying to help someone "join the dots" of an idea. This style will have a longer term impact on people and will help both parties explore ideas more. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having these ideas explained has made me more conscious about how I try to help people solve problems. I find myself looking for coaching opportunities more when working with people and have tried to take that into our workshops by encouraging coaches to draw on real-life analogies to help explain technical ideas (&lt;a href="https://twitter.com/gypsydave5"&gt;David Wickes&lt;/a&gt; is extremely good at this). &lt;/p&gt;

&lt;h4&gt;
  
  
  Self reflection
&lt;/h4&gt;

&lt;p&gt;The book discusses how when people go from engineering to leadership need to understand their "default work mode" and how it might not be compatible with different goals as a lead. I think my default work mode is "just fucking do it" and "ask for forgiveness, not permission"; this has broadly worked out quite well for me as an engineer in teams. However as a lead I need to check myself. &lt;/p&gt;

&lt;p&gt;Sometimes I just want to open my IDE and refactor some code I dont like and &lt;code&gt;git commit -am "refactor"&lt;/code&gt;. On a high level that is the right thing to do but how does that help my teammates in the long-run? I should see these things as a coaching opportunity and instead find time to bring it up with people and explore the space with them so that in future everyone else can see the problems in our code better.&lt;/p&gt;

&lt;p&gt;The book asks you what you think your management style is so you can reflect on it. Just asking that question of myself was weird and difficult, this is what I came up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No micromanaging. Feel strongly about empowerment, ownership and trust. I have no interest in denying clever people the opportunity to use their skills to achieve our goals.&lt;/li&gt;
&lt;li&gt;Reliant on honest feedback, sometimes I don’t observe myself not being great&lt;/li&gt;
&lt;li&gt;Hope to focus more on growing people than “getting shit done” but I will need to check myself because that is my “default work mode”. &lt;/li&gt;
&lt;li&gt;Want to act as a sponsor, finding opportunities for people to grow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I like to think that I've stuck to my guns with this style and it seems to be working out OK.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting direction
&lt;/h4&gt;

&lt;p&gt;The book also instructed me to write a vision (or North Star) for the team&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Be an amazing team that is continuously improving that ships well-engineered software with minimal hassle and stress by relying on craft and taking advantage of our autonomy to apply industry best practices. &lt;/p&gt;

&lt;p&gt;We will take pride in our actual agility to confidently change and evolve our software as and when we need to.&lt;/p&gt;

&lt;p&gt;If we get good at creating great systems, our stakeholders will always be happy with us and will continue to give us autonomy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And a mission, which is a more grounded version of it&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Openly and honestly communicate with each other to guide ourselves so we can grow&lt;/li&gt;
&lt;li&gt;A culture of learning and sharing knowledge&lt;/li&gt;
&lt;li&gt;Confidence to suggest changes to improve our ways of working and our code&lt;/li&gt;
&lt;li&gt;Continuously tightening feedback loops to guide improvement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And a strategy to get there&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finds ways to break problems down into smaller chunks so we’re never working on something that feels too intimidating. Perfect is the enemy of good, better to ship 80% of the feature quickly than 90% in 3 months time.&lt;/li&gt;
&lt;li&gt;Low WIP (work in progress) so we’re not spinning too many plates and that allows us to focus on small tasks that we can execute well.&lt;/li&gt;
&lt;li&gt;Culture of feedback. Practice saying something nice every day! Remember that giving someone “negative” feedback is an act of kindness (so long as it’s done kindly).&lt;/li&gt;
&lt;li&gt;Practice continuous integration. Both in respect to code and knowledge.&lt;/li&gt;
&lt;li&gt;Pairing, mobbing. Even if you work on a task by yourself it should be considered very unusual not to seek feedback on your work as you do it.&lt;/li&gt;
&lt;li&gt;Give ourselves time to research, in particular pre standup research times&lt;/li&gt;
&lt;li&gt;Share interesting things you learn.&lt;/li&gt;
&lt;li&gt;Ensure everyone has time to work on all aspects of our code and development practice, actively fight any silos of knowledge forming.&lt;/li&gt;
&lt;li&gt;Everyone on the team contributes in forming how we work.&lt;/li&gt;
&lt;li&gt;We should take pride in our work. If you’re not proud of something, we discuss how to make it better.&lt;/li&gt;
&lt;li&gt;Identify any single points of failure we may have in our ways of working and work to spread the knowledge &amp;amp; responsibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If nothing else it felt cathartic to write this down and I've encouraged the team to contribute to the document. &lt;/p&gt;

&lt;p&gt;I sometimes feel my role, &lt;em&gt;if anything&lt;/em&gt; is to keep pushing the team in the direction this describes so that we do become that team that I hope we will be.&lt;/p&gt;

&lt;h3&gt;
  
  
  A talk from Makers
&lt;/h3&gt;

&lt;p&gt;A few of us went to a Leading a Diverse Team workshop at Makers. It was interesting and one talk resonated with me a lot. It discussed how often as a leader we project our own ideas as to how to accomplish a goal based on our own experiences. This is fine and well intentioned but it's from a position of bias and you may be unintentionally shutting out different ideas.&lt;/p&gt;

&lt;p&gt;A better, more empowering way of trying to achieve what I'm trying to achieve is setting a vision but then encouraging the individuals in my team to think about the unique ways &lt;em&gt;they&lt;/em&gt; can contribute toward that vision that I may not be thinking of. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;My&lt;/em&gt; way of achieving goals is one means to that end but it doesn't have to be the only one; and there's probably better ones that my team can think of based on their own background, skills and experience. It's my job to encourage people and build a great environment so they can explore their own ideas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learned, things to improve
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Introvert Chris
&lt;/h3&gt;

&lt;p&gt;I am one of those introvert-ish people who can seem relatively outgoing most of the time but I definitely suffer from running out of social energy quite quickly and just wanting to get a break from people (no offence, team). &lt;/p&gt;

&lt;p&gt;This role definitely has taken its toll on introvert Chris at times and I need to find ways of managing that better but I dont have many good ideas yet. I think perhaps now my team is settled more I shall try and delegate a few more meetings to people as it will save me some social energy and is an opportunity for others to contribute in those areas.&lt;/p&gt;

&lt;h3&gt;
  
  
  You cant just mob
&lt;/h3&gt;

&lt;p&gt;I hear a lot of great things about mobbing and I am totally on-board but for whatever reason when we tried it did not go well. I suspect it was a function of the team being very unfamiliar with each other and the nature of the work (it was very new-project, infrastructure work). &lt;/p&gt;

&lt;p&gt;Still, like leadership it's probably something you have to study and not just an innate skill. I hope to read more about this and try it again next year.&lt;/p&gt;

&lt;h3&gt;
  
  
  General time management
&lt;/h3&gt;

&lt;p&gt;I'm not happy with the amount of time I've got to pair with everyone. I'd say I do it quite often but not enough. The times where I paired I've been able to give much more useful feedback in our one-to-ones.&lt;/p&gt;

&lt;p&gt;When the role was first offered to me it was proposed I would manage 3 people. That quickly turned to 5 and at the start of 2020 7. To serve all these people well I am definitely going to have to think carefully about what I am doing every day and try to find opportunities to delegate useful tasks that will help people grow and free my time up at the same time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Study more
&lt;/h3&gt;

&lt;p&gt;The few books I got through gave me some excellent ideas and set me up well. I want to continue reading this subject to get better. I'm currently reading &lt;a href="https://www.amazon.co.uk/Elegant-Puzzle-Systems-Engineering-Management-ebook/dp/B07QYCHJ7V"&gt;An Elegant Puzzle&lt;/a&gt; which is very interesting but seems maybe better suited to a head of engineering role rather than the one I'm in right now. &lt;/p&gt;

&lt;p&gt;The next books will be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.amazon.co.uk/Manager%60s-Path-Camille-Fournier/dp/1491973897"&gt;The Manager's Path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.co.uk/Thinking-Systems-Primer-Diana-Wright/dp/1844077268"&gt;Thinking in Systems: A Primer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final reflections
&lt;/h2&gt;

&lt;p&gt;I'm glad I didn't try and "wing-it" with management. I'm still learning though and there's lots of room for improvement but I &lt;em&gt;think&lt;/em&gt; the upfront study I did helped grease the wheels for my team and get it off to a good start. &lt;/p&gt;

&lt;p&gt;During hiring I was very upfront about what my expectations and aspirations for the team were which resulted in a group of people joining who seem to be bought into the idea and are contributing toward it.&lt;/p&gt;

&lt;p&gt;I'm really pleased and proud of how things are going. I shouldn't take for granted that we managed to turn a group of strangers with various backgrounds and experiences into a great team. The culture is fun, open, curious and we take pride in our work; which is honestly exactly what I wanted. &lt;/p&gt;

&lt;p&gt;I feel everyone has become better engineers since joining and I am confident we'll do great next year so long as we keep pushing ourselves to get better and better. (that felt like a bit of a lame manager-esque rallying call, sorry)&lt;/p&gt;

&lt;p&gt;I think the most gratifying moment for me was a small one. A few weeks after the team formed I went on holiday. When I came back one of my team mates told me they had changed the process. I replied:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Good&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's the team's process, not mine. I want them to be comfortable making decisions about how we work and voicing strong opinions about the way we do things, and this demonstrated we are heading in the right direction.&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>agile</category>
    </item>
    <item>
      <title>Gamifying Continuous Integration</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Thu, 28 Nov 2019 14:54:32 +0000</pubDate>
      <link>https://forem.com/quii/gamifying-continuous-integration-o1d</link>
      <guid>https://forem.com/quii/gamifying-continuous-integration-o1d</guid>
      <description>&lt;p&gt;If you read the internet, you'll soon realise that a large number of software developers don't understand what CI is and why it's important.&lt;/p&gt;

&lt;p&gt;It's important to state that &lt;strong&gt;continuous integration is not a server&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Like the word DevOps, people seem to think these important principals of software engineering are about tools and products. Perhaps misinformed managers think if they buy the right magic box they can finally deliver their projects on time. &lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous integration is &lt;em&gt;continuous integration&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Read the words&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;It's about making sure that when you are working on code is the most up to date version of the code as a team. &lt;/p&gt;

&lt;p&gt;In an ideal world if you could somehow all work on same computer at the same time comfortably, that would be pure CI. &lt;/p&gt;

&lt;p&gt;If you've ever used VS-code's Live Share plugin, that's as pure a CI experience you can get in a remote environment. If you've not used it, it allows you to connect to a colleague's VS code and edit the code together as if you're working on the same computer. The changes you make are reflected (or &lt;em&gt;integrated&lt;/em&gt;) to everyone else in the session - the feedback is immediate.&lt;/p&gt;

&lt;p&gt;A much simpler experience of CI is mobbing. Everyone is working from the same version of the code together.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you know if you're not practicing CI well?
&lt;/h2&gt;

&lt;p&gt;One obvious sign is developers wasting lots of time resolving large merge conflicts. Merge conflicts are a direct result of you working on a version of the code that isn't up to date. Your team are not integrating their changes &lt;em&gt;continuously&lt;/em&gt; and therefore as they make changes the risk of making invalid changes increases. &lt;/p&gt;

&lt;p&gt;The time wasted on merge conflicts has compounding effects as it increases the delays of integrating your own changes to the system.&lt;/p&gt;

&lt;p&gt;One might argue you can resolve this by structuring work differently to avoid conflicts, even going as far as to re-architect your &lt;em&gt;system&lt;/em&gt; to avoid merge conflicts. An often touted reason to go for microservices is it allows teams to work independently. &lt;/p&gt;

&lt;p&gt;Reader, I have worked on a team with 20 odd developers, shipping frequently on a monolith and very rarely did we have merge conflicts. We also didn't do pull requests, we committed to master.&lt;/p&gt;

&lt;h3&gt;
  
  
  If you don't practice CI you are not working with your team as well as you could
&lt;/h3&gt;

&lt;p&gt;Changes to the system are invisibly stored on your colleague's computers where they are of no use to you. &lt;/p&gt;

&lt;p&gt;You could be imagining some great abstraction given the code in front of you but unfortunately the code in front of you is &lt;em&gt;not&lt;/em&gt; the source of truth because unknown to you another developer merges a gigantic change after spending a week on a feature.&lt;/p&gt;

&lt;p&gt;People become reluctant to refactor parts of the code because someone is working on a branch that is vaguely near the code you want to change so you wait a few days and then forget about it.  &lt;/p&gt;

&lt;h2&gt;
  
  
  How do you CI well?
&lt;/h2&gt;

&lt;p&gt;The simplest way is for everyone to commit to master, frequently. It really is that obvious! &lt;/p&gt;

&lt;p&gt;To be good at continuous integration, you should continuously integrate your changes to master. That way everyone will be working with the same version of code for the most part.&lt;/p&gt;

&lt;p&gt;It's important that you respect your colleagues and run your tests before pushing. If the build is broken the team should &lt;em&gt;stop&lt;/em&gt; committing unless it's to directly fix the problem. If people keep committing whilst the build is broken it will become very difficult to diagnose what the problem is and the new commits may compound the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  The process, in full
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git pull -r&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Make a positive change to the system&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git commit -am "added blockchain terraform machine-learning module 2.0"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git pull -r&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;./build.sh &amp;amp;&amp;amp; git push&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This practice is simple to follow, doesn't require elaborate review systems, branch strategies etc, and forces good habits. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In order to push frequently, you need to pull changes frequently&lt;/li&gt;
&lt;li&gt;You can only push frequently if you work on small tasks, iteratively. There are many, many reasons why this is a wonderful, less risky and easier way of working. (see TDD, XP, any decent agile book, etc etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It wont &lt;em&gt;entirely&lt;/em&gt; stop merge conflicts occurring, but they should be very infrequent and because you're doing small changes they're typically trivial to resolve.&lt;/p&gt;

&lt;h3&gt;
  
  
  But what about code review?
&lt;/h3&gt;

&lt;p&gt;The industry seems to have conflated reviewing code with a very specific, relatively new process of looking at code when a pull request is submitted; usually too late once all the code is written. &lt;/p&gt;

&lt;p&gt;Did you know that you can talk about code, at any time during the day? &lt;/p&gt;

&lt;p&gt;Did you also know that the correct abstractions and patterns may not be apparent when the code is "done" and you'd be better off encouraging an environment where people are free to refactor code when they want to, rather than having to go through a laborious process every time they want to change the code. I've worked on and observed projects that practice code review very strictly and yet the code is still not great. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relying on a process of checking code before it is merged is not going to result in a healthy codebase alone.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;With this way of working I strongly encourage pair programming because people rightly assert that as a lone developer it is very easy to do something wrong if you don't gather feedback. Pair programming facilitates a constant feedback loop on what you are writing.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if someone commits something wrong/broken?
&lt;/h3&gt;

&lt;p&gt;First of all, no process in the world can prevent this. Stuff does go wrong, and you would be better asking yourself: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How can we detect and recover from problems easier?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Secondly, this approach does require a healthy and collaborative team that talk to each other regularly about what they are working on. They should be talking to each other when they start a bit of work about what they are going to do, how they will release it safely, what kind of tests, etc. Couple that with working on small things iteratively the risk of pushing something catastrophic are very low.&lt;/p&gt;

&lt;p&gt;If someone does push some code that maybe works (so the tests pass, monitoring is all good, etc) but is actually "bad". Well so what? We can refactor it if we don't like it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if I, a tech lead want to check every change before merging
&lt;/h3&gt;

&lt;p&gt;I don't want to work with gatekeepers. &lt;/p&gt;

&lt;p&gt;I want to work on a team that trusts one-another. &lt;/p&gt;

&lt;p&gt;Perfect is the enemy of good.&lt;/p&gt;

&lt;h3&gt;
  
  
  So is a system of pull requests bad?
&lt;/h3&gt;

&lt;p&gt;Not at all, they're perfect for open source projects where you want to welcome contributions from other people but dont have implicit trust. In that case you will want to review changes that go into your precious project.&lt;/p&gt;

&lt;p&gt;For a team where you trust the developers all it adds is overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Liberation
&lt;/h2&gt;

&lt;p&gt;We should be &lt;em&gt;removing&lt;/em&gt; the barriers to changing software, not adding walls and walls of bureaucracy. &lt;/p&gt;

&lt;p&gt;In this kind of environment people fix code when they see it needs fixing. &lt;/p&gt;

&lt;p&gt;This way of working tightens feedback loops and increases actual meaningful agility.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI is not just about the code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It's important to integrate knowledge of domain, work etc. (so important not to have silos of work with just the BAs/UXD etc)&lt;/li&gt;
&lt;li&gt;Who is working on what (standups, kick-offs, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Gaming it
&lt;/h2&gt;

&lt;p&gt;I feel very strongly about working this way over a pull request approach when you are working on a team you trust. &lt;/p&gt;

&lt;p&gt;Most of my team until recently were very unfamiliar with this way of working so I made a silly dashboard on one of the TVs which showed who committed to master most over a given week. It penalises you points if you push a change which breaks the build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zxabac3v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/5gG7OMf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zxabac3v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/5gG7OMf.png" alt="ci-league dashboard"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;After just a few weeks this slight nudging has improved the team's approach to CI, we've had significantly less merge conflicts, people are refactoring more often and the number of failed builds has also dropped.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/quii/ci-league"&gt;The code for it is on github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you have docker, you can run it with&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker run -p 8000:8000 quii/ci-league&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want it to look at a private repo you'll need to supply a &lt;a href="https://github.com/settings/tokens"&gt;github personal access token&lt;/a&gt; as an environment variable&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker run -p 8000:8000 -e GITHUB_TOKEN=supersecret quii/ci-league&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It doesn't do any fancy auto-refreshing but most browsers have extensions to auto refresh a tab, we set it to update every 10 minutes here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;As usual in software, we seem to suffer as an industry of remembering the &lt;em&gt;why&lt;/em&gt; of all of these fancy terms. &lt;/p&gt;

&lt;p&gt;If you appreciate the why of CI you may not fall in to the trap of blinding applying best practices that work in a different context to the one you are working in. As I said pull-requests in an open source project make total sense and work great. In a different context it adds overhead.&lt;/p&gt;

&lt;p&gt;You should instead focus on what your environment your team is working in, the constraints you have and use principles like CI to guide what process best fits.&lt;/p&gt;

</description>
      <category>ci</category>
      <category>agile</category>
      <category>devops</category>
    </item>
    <item>
      <title>The carbon footprint of your website</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Wed, 13 Nov 2019 07:29:03 +0000</pubDate>
      <link>https://forem.com/quii/the-carbon-footprint-of-your-website-2bb1</link>
      <guid>https://forem.com/quii/the-carbon-footprint-of-your-website-2bb1</guid>
      <description>&lt;p&gt;Stumbled across this website &lt;a href="https://www.websitecarbon.com/"&gt;https://www.websitecarbon.com/&lt;/a&gt; which measures the carbon footprint of your website. &lt;/p&gt;

&lt;p&gt;I've always believed in lightweight, efficient websites to deliver content. I firmly believe in not using client-side JS unless absolutely necessary because not everyone has an Internet Telephone Professional Maximum on a 4g connection.&lt;/p&gt;

&lt;p&gt;I ranted about this and riled up the community about this subject here&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/quii" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZRhXJ2vf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--aZebwKmx--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/61881/0c870cae-d5c4-4603-ac34-8d6eb02ab1fa.png" alt="quii image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/quii/the-web-i-want-43o" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;The Web I Want&lt;/h2&gt;
      &lt;h3&gt;Chris James ・ Aug 20 '18 ・ 6 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#web&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#html&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#performance&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#a11y&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Here's how my website scores&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qUSWVUWi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/R4z2WDh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qUSWVUWi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/R4z2WDh.png" alt="quii.dev is 96% cleaner than other websites tested"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's your score?&lt;/p&gt;

&lt;p&gt;Given the huge amount of evidence pointing to how website performance effects users &lt;em&gt;and&lt;/em&gt; the environment, what are you going to do about it?&lt;/p&gt;

&lt;p&gt;For more on this check out the slides of this excellent talk &lt;a href="https://twitter.com/hanopcan/status/1187675166236643329"&gt;https://twitter.com/hanopcan/status/1187675166236643329&lt;/a&gt;&lt;/p&gt;

</description>
      <category>performance</category>
      <category>green</category>
    </item>
    <item>
      <title>The ghost of Henry Ford is ruining your development team</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Thu, 31 Oct 2019 15:05:52 +0000</pubDate>
      <link>https://forem.com/quii/the-ghost-of-henry-ford-is-ruining-your-development-team-5f6l</link>
      <guid>https://forem.com/quii/the-ghost-of-henry-ford-is-ruining-your-development-team-5f6l</guid>
      <description>&lt;p&gt;People talk a lot about "lean". Maybe they've read &lt;a href="https://en.wikipedia.org/wiki/The_Machine_That_Changed_the_World_(book)"&gt;The Machine That Changed The World&lt;/a&gt; and were inspired by how lean manufacturing transformed the motor industry. They read how Japanese companies became incredibly efficient and blew the competition out of the water and then they take that to their software development team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UO5ki7Qj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgflip.com/3evf0h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UO5ki7Qj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgflip.com/3evf0h.jpg" alt="You keep saying lean, i do not think it means what you think it means"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sounds good but too often I feel like people miss the real genius of lean manufacturing and continue to run their organisation with a top-heavy, command and control structure; the only difference is a constant message of&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Be more efficient! Stop being wasteful! LEEEEEAN&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Agile, Devops and other buzzwords clearly get a lot of their inspiration from lean manufacturing and these ways of working gain their efficiencies (and other, bigger benefits) broadly by &lt;strong&gt;empowering development teams and giving them responsibility&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A primer on mass production
&lt;/h2&gt;

&lt;p&gt;Before Henry Ford’s assembly line, cars were made to order by craftsmen. It took a long time to make them and were reserved for the wealthy.&lt;/p&gt;

&lt;p&gt;The assembly line made it possible to make cars cheaply which made them accessible to a far broader market. &lt;/p&gt;

&lt;h3&gt;
  
  
  How?
&lt;/h3&gt;

&lt;p&gt;It’s a big subject, but here are some pithy bullet points&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In order to reduce cost he needed to produce cars at high volume with low-skilled workers, not craftsmen.&lt;/li&gt;
&lt;li&gt;The assembly line was a collection of expensive, inflexible machinery that scaled to volume and could be operated by cheap labour doing very simple tasks.&lt;/li&gt;
&lt;li&gt;Emphasis on standardisation, being able to replace one worker with another cheaply and easily.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Problems
&lt;/h3&gt;

&lt;p&gt;The assembly line was very intolerant to disruption&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Had to add lots of buffers such as storing supplies, space and additional workers to smooth production&lt;/li&gt;
&lt;li&gt;Better to accept defects and fix them after the car was made than to stop the line&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The work was very dispiriting. Ford even passed on some of the savings and profits to his workers by heavily increasing their salaries but people just didn’t want to do the same boring task 100s of times a day.&lt;/p&gt;

&lt;p&gt;The assembly line being heavily optimised for volume with expensive, specific machines meant it is very inflexible so creating different cars was a very difficult and costly endeavour.&lt;/p&gt;

&lt;p&gt;When designing new cars it took what we would recognise as a very waterfall approach, of a project being passed around many departments and problems being unsurfaced way too late due to poor feedback loops and not a good structure of ownership.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lean manufacturing
&lt;/h2&gt;

&lt;p&gt;Japanese car makers studied the production line and tried a different way. When you hear about kanban and kaizen in agile circles, well it all came from here.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://en.wikipedia.org/wiki/Lean_manufacturing"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For many, lean is the set of "tools" that assist in the identification and steady elimination of waste. &lt;strong&gt;As waste is eliminated quality improves while production time and cost are reduced&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There isn't a canonical "lean" way of working, but the one that resonates strongest with me is "The Toyota Way"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Toyota Way, in which the focus is upon improving the "flow" or smoothness of work, thereby steadily eliminating mura ("unevenness") through the system and not upon 'waste reduction' per se... The implementation of smooth flow exposes quality problems that already existed, and thus waste reduction naturally happens as a consequence. The advantage claimed for this approach is that it naturally takes a system-wide perspective, whereas a waste focus sometimes wrongly assumes this perspective&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How does lean try to reduce waste?
&lt;/h3&gt;

&lt;p&gt;Another big subject and there are good resources on it with a google search. The main drive of it from my perspective is actively trying to identify waste and then fix it. Lean describes 3 types&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mura&lt;/strong&gt;: Waste due to changes in demand. Lean advocates a "pull" system rather than "push". So you only make a car if there is demand for it rather than trying to forecast demand which is often difficult and makes supply inconsistent. In software this would be akin to perhaps making a cheap prototype to prove an idea before committing to a bigger endeavour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muri&lt;/strong&gt;: Waste by trying to do too much stuff at once. This is why if you're doing Kanban and not observing work-in-progress limits you're not doing Kanban. It can sometimes feel counter-intuitive that you can go faster by doing less work but you've probably worked in a situation where a team is working really hard and everything feels chaotic and unreliable. This is also why smaller teams are generally preferable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muda&lt;/strong&gt;: Non-value adding work. A classic example in software would be developers constantly struggling with flaky builds and not addressing the underlying causes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lean emphasises the idea of "flow", optimising the processes for delivery and reducing interruptions in the production process. (think about trunk based development vs pull requests here)&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality
&lt;/h3&gt;

&lt;p&gt;For quality you adopt &lt;a href="https://en.wikipedia.org/wiki/Kaizen"&gt;Kaizen&lt;/a&gt;, striving for perfection and hunting down the root causes of issues and fixing them. You adopt a culture of quality across the value stream, not after the product is "finished".&lt;/p&gt;

&lt;h3&gt;
  
  
  Command and control vs autonomy and empowerment
&lt;/h3&gt;

&lt;p&gt;What I mainly took from the book "The Machine That Changed The World" was how it contrasted mass manufacturing and lean manufacturing in respect to management. &lt;/p&gt;

&lt;p&gt;Lean manufacturing acknowledges that it's impossible to heavily micro-manage the production of a complicated product like a car with thousands of people working on it. &lt;/p&gt;

&lt;p&gt;The best way for Kaizen to work is to coach and empower the do-ers to find the best ways to deliver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signs you're not in a lean company
&lt;/h2&gt;

&lt;h3&gt;
  
  
  People with job titles of "manager" or "leader" but are nothing more than coordinators
&lt;/h3&gt;

&lt;p&gt;When designing new cars there is the idea of the Shusa (not sushi!) who in short was &lt;em&gt;actually&lt;/em&gt; in charge of things. They could bring people to help and make decisions and were not worried about being overruled by the whims of upper management; they were empowered to make the project work. People would say that these people actually made their mark on a project "oh you can tell that's a Dan car because of X Y and Z".&lt;/p&gt;

&lt;p&gt;Contrast that to places I've worked where people have had very lofty job titles but no actual empowerment and were nothing more than a communication funnel between the people who actually make things and the people who could actually make decisions. &lt;/p&gt;

&lt;p&gt;How common is it in our industry for tech leads to be miserable simply because they're promoted into what they'll actually call a "shit shield". Seriously, can we stop saying that as if it's a good thing. It's a problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A leader should be able to lead&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The development team has no say on priorities
&lt;/h3&gt;

&lt;p&gt;Lean famously relies on Kaizen; the concept of continually striving for perfection. In lean plants workers can stop the plant if they find a problem and they work hard to make sure it doesn't happen again. &lt;/p&gt;

&lt;p&gt;If you see something that is technically really wrong and is slowing your team down, how empowered are you to fix it? Do you work with a scrum master who will humour you but probably thinks "technical stories" are "waste" ? &lt;/p&gt;

&lt;p&gt;Being lean and efficient is not simply done by only working on the most important feature at a given time. It's about the builders working hard to create a system and environment that can be worked on efficiently. That takes the form of the usual best practices; tightening and improving feedback loops, continuous delivery, easy to setup, simple delivery pipeline, excellent code, etc. &lt;/p&gt;

&lt;p&gt;The lean plants worked hard to reduce problems and defects and to give themselves flexibility. This only happened because the workers were given the autonomy to make it happen; not micromanagement from above. &lt;/p&gt;

&lt;p&gt;How does your team compare? Are you able to fix problems when you see them (which is the best time) or do you have to wait for the "technical debt sprint"?&lt;/p&gt;

&lt;h3&gt;
  
  
  All teams have a standard, immutable way of working
&lt;/h3&gt;

&lt;p&gt;Toyota didn't just make up lean and be successful, they had to practice and iterate at it to figure out how to be good. Your IT teams need to practice and work at being "lean"&lt;/p&gt;

&lt;p&gt;You also have to understand that we dont have teams of resources, they are individuals working on different problems. This means if you want to get the most out of people you need to give them autonomy to figure out how they can work together most effectively.&lt;/p&gt;

&lt;p&gt;How does a team get better at working together if they cant gather feedback by retrospecting and then improving the way they work? &lt;/p&gt;

&lt;p&gt;Larger organisations often talk about standardisation to allow developers to move between teams. That in itself isn't a bad thing but it's not important as autonomy. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want teams to be empowered enough to practice Kaizen and let them find how to work efficiently you have to accept that teams will work differently.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is fine and in my experience moving between teams is always a challenge even if everyone works the same way, because teams are more complicated than a set of tools and processes. &lt;/p&gt;

&lt;h3&gt;
  
  
  The people who write the software are not responsible for QA or running it in production
&lt;/h3&gt;

&lt;p&gt;In mass manufacturing the assembly line optimised itself for volume and would defer any kind of quality problems to the end of the line where another team would pick things up and fix them. The problem of this is the feedback loop just didn't exist and systemic problems would never get addressed, which brings waste.&lt;/p&gt;

&lt;p&gt;I consider a QA column in a kanban wall as a smell. QA in lean worlds is a part of the entire development process, not something tacked on at the end. QA is a responsibility and an inherent quality of a good team. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://continuousdelivery.com/principles/"&gt;From the continuous delivery website&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s much cheaper to fix problems and defects if we find them immediately—ideally before they are ever checked into version control, by running automated tests locally. Finding defects downstream through inspection (such as manual testing) is time-consuming, requiring significant triage. Then we must fix the defect, trying to recall what we were thinking when we introduced the problem days or perhaps even weeks ago.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're throwing your software over a wall to an ops team then how do you expect to write a good system?&lt;/p&gt;

&lt;h3&gt;
  
  
  Boredom
&lt;/h3&gt;

&lt;p&gt;If you're trying to turn your development team into a homogeneous assembly lines pumping out JIRA tickets at volume you might start to bore some people (and probably build some crappy products).&lt;/p&gt;

&lt;p&gt;You probably pay your engineers a lot of money because they're presumably quite clever, so why are you denying them the space to &lt;em&gt;think and take responsibility&lt;/em&gt;? &lt;/p&gt;

&lt;p&gt;I've worked on projects which should be to be honest quite boring but turned out to be great fun because I worked in an engaged, empowered and fun team who took pride in doing things the "right" way and practiced Kaizen. &lt;/p&gt;

&lt;p&gt;Not only was it great for us but we delivered the project which was initially seen as very risky and tricky with very little stress. Not only that but what we learned in respect to shipping software was adopted by other teams in the organisation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Kaizen is fun, rewarding and will improve your outcomes.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
   Too scared to release and get feedback
&lt;/h3&gt;

&lt;p&gt;In the book &lt;em&gt;Lean Thinking: Banish Waste and Create Wealth in Your Corporation&lt;/em&gt; it says&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Identify value from the customer's perspective&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Doing this with software products is notoriously difficult but it's made even more difficult if you dont have the courage to release your software to the world and gather feedback.&lt;/p&gt;

&lt;p&gt;Too often software is managed as a project which "ends" (this is nonsense, obviously) and no one takes any lessons from the customers. This is the ultimate form of waste that lean strives to fight against.&lt;/p&gt;

&lt;h2&gt;
  
  
  The transformational lean technologies and methodologies
&lt;/h2&gt;

&lt;p&gt;I think it’s interesting to think about the transformative technologies over the past few years and how they relate to lean. I think a lot of things appear big and transformative but are they solving real problems? Are they helping you be lean? &lt;/p&gt;

&lt;h3&gt;
  
  
  Docker
&lt;/h3&gt;

&lt;p&gt;Docker is an empowering technology allowing developers to use technology far more freely. Rather than asking for permission to use a technology and have it installed in production etc we can use whatever we like because we just ship containers&lt;/p&gt;

&lt;p&gt;The main benefit for me though is it has made the difference between a local computer and production much smaller, which allows developers to take more responsibility for the quality of their software. &lt;/p&gt;

&lt;p&gt;Synonymous with moving away from highly specialised, inflexible tooling in the mass manufacturing world&lt;/p&gt;

&lt;h3&gt;
  
  
  Devops
&lt;/h3&gt;

&lt;p&gt;Devops is lean. It is about tightening feedback loops, improving the quality of our tooling and processes and taking responsibility of our software. Read The Phoenix Project. Just do it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud computing (e.g AWS)
&lt;/h3&gt;

&lt;p&gt;Again this is another empowering development which lets the shop floor workers easily adapt the technology landscape to solve problems. Synonymous with having more flexible machinery in the lean car factories as opposed to highly specialised ones from mass manufacturing. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up - we're not building cars
&lt;/h2&gt;

&lt;p&gt;Agile and DevOps have clearly taken a lot of lessons from the lean manufacturing of cars. All of them are about building complicated things with lots of people which requires a different way of thinking vs mass manufacturing if you wish to do it efficiently with a happy workforce.&lt;/p&gt;

&lt;p&gt;But when you're reading about lean it's important to remember that we software developers have different goals&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We're not trying to build software at volume&lt;/li&gt;
&lt;li&gt;We're trying to deliver the promise of software, products that are malleable and can change to users needs quickly and cheaply.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A big thing about lean is trying to identify value from a customer's perspective and eliminating anything that doesn't contribute to it. People take this lesson in software to aggressively deprioritise anything that isn't obviously a feature. &lt;/p&gt;

&lt;p&gt;The thing is, this is just a very immature way of looking at what the stakeholders of software are. The "real" customer &lt;em&gt;does&lt;/em&gt; benefit from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making it more operable so it has less downtime&lt;/li&gt;
&lt;li&gt;Improving the test suite so the software can be changed easily to meet customer needs quickly&lt;/li&gt;
&lt;li&gt;etc etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think examining the "value stream" for waste is a great thing, there's nothing more dispiriting than working on something for months with no real evidence it'll bring any benefit to anyone.  &lt;/p&gt;

&lt;p&gt;Too often though this is led by "product" people with little collaboration from the technical side. The team is unable to practice Kaizen and instead wastes its time working around technical debt, slow builds, poor feedback loops, manual testing etc. This results in a product which eventually becomes too hard to change and cant react to what the user wants in the long-run. A far cry from the flexible, malleable and efficient development system we're all supposedly striving for. &lt;/p&gt;

&lt;p&gt;This comes back to what I wrote earlier, is your tech lead empowered to lead? Or is she just making sure you put estimates on JIRA tickets? Is she treated as an equal when deciding priorities for work? Does she have to argue constantly for scraps of time for the team to practice Kaizen whilst passive-aggressively being accused of being wasteful for even suggesting non-feature work?&lt;/p&gt;

&lt;h2&gt;
  
  
  Final final thought
&lt;/h2&gt;

&lt;p&gt;From Wikipedia again&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The cultural and managerial aspects of lean are arguably more important than the actual tools or methodologies of production itself. There are many examples of lean tool implementation without sustained benefit, and these are often blamed on weak understanding of lean throughout the whole organization.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Replace the word lean with "agile" and I think you'll have a lot of software developers nodding with knowing looks on their faces.&lt;/p&gt;

</description>
      <category>lean</category>
      <category>agile</category>
    </item>
    <item>
      <title>Go back to basics with MVC</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Thu, 25 Jul 2019 17:11:26 +0000</pubDate>
      <link>https://forem.com/quii/go-back-to-basics-with-mvc-4p6m</link>
      <guid>https://forem.com/quii/go-back-to-basics-with-mvc-4p6m</guid>
      <description>&lt;p&gt;This is another follow up post to an episode of &lt;a href="https://changelog.com/gotime/92"&gt;Go time&lt;/a&gt; I listened to the other day which seems to get my creative juices flowing. &lt;/p&gt;

&lt;p&gt;It talked about web development in Go and a few things stuck out to me&lt;/p&gt;

&lt;h2&gt;
  
  
  A cautionary tale of generating HTML
&lt;/h2&gt;

&lt;p&gt;Early on in the episode it was described how the built-in template library wasn't very expressive and described that the Go Buffalo framework uses &lt;a href="https://github.com/gobuffalo/plush"&gt;Plush&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Powerful, flexible, and extendable, Plush is there to make writing your templates that much easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Enter Jade
&lt;/h3&gt;

&lt;p&gt;8ish years ago I worked on a pretty major project which was written in Scala. We decided to use the Jade template engine to generate our HTML which, like Plush allows you to do a lot of clever coding inside your templates.&lt;/p&gt;

&lt;p&gt;This felt amazing at first but &lt;strong&gt;quickly became a nightmare&lt;/strong&gt;. With the flexibility Jade gave us we made a bit of a mess. Our templates became ugly, hard to understand and difficult to test as more and more business logic leaked into our templates &lt;/p&gt;

&lt;p&gt;In software I often see &lt;em&gt;flexibility&lt;/em&gt; as rope that a team can hang itself with and I tend to prefer very opinionated and constrained things (like Go!).&lt;/p&gt;

&lt;h3&gt;
  
  
  What did we learn?
&lt;/h3&gt;

&lt;p&gt;Software engineers are doomed to relearn things. We had forgotten about separation of concerns, in particular the guidance the Model-View-Controller design pattern prescribes.&lt;/p&gt;

&lt;h2&gt;
  
  
  MVC
&lt;/h2&gt;

&lt;p&gt;It's quite surprising how badly people misunderstand MVC. If you go on Reddit or Twitter you will hear people telling other developers that "MVC isn't suited to Go". &lt;/p&gt;

&lt;p&gt;Often people seem to think MVC is about folder structures, class names, or other fairly superficial concerns. So when developers from say a Rails background show their Go code with an array of folders they get derided and thrown to the lions. &lt;/p&gt;

&lt;p&gt;MVC does not prescribe folder structure and I worry a lot of people seem to miss the point of the principle. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller"&gt;Model–View–Controller (usually known as MVC) is an architectural pattern commonly used for developing user interfaces that divides an application into three interconnected parts.&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Controller
&lt;/h3&gt;

&lt;p&gt;Intercepts "requests" (such as HTTP), parses them and then calls the appropriate "Model", getting some kind of data as a result and then sends it to a "View". In the Go world, that's usually a &lt;code&gt;http.Handler&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Model
&lt;/h3&gt;

&lt;p&gt;Loosely, it's where your domain logic lives. I personally think it's quite poorly named but the important thing is the separation of concern. It must be decoupled from the Controller and View, so if you see anything HTTP related passed through from the controller it's likely you're violating that decoupling. They should also know nothing about views. &lt;/p&gt;

&lt;h3&gt;
  
  
  View
&lt;/h3&gt;

&lt;p&gt;It doesn't know anything about controllers or models. It should probably get passed to it some kind of &lt;code&gt;ViewModel&lt;/code&gt; which is just a collection of data it needs to render a view. A well designed view is simple and doesnt have domain logic; because templates are very hard to test cheaply.&lt;/p&gt;

&lt;h3&gt;
  
  
  What do these principles buy you?
&lt;/h3&gt;

&lt;p&gt;Your domain code is cleanly separated from the rest of the system so it is easy to test and can be "plugged in" to different uses beyond your web server; for example a CLI tool, or just as a package for others to use.&lt;/p&gt;

&lt;p&gt;It is trivial to create and edit views as they are merely mappings from a bundle of generic data into HTML (or whatever). It also makes them more accessible for frontend developers et al.&lt;/p&gt;

&lt;p&gt;Your controller has clear concerns and are also easy to test.&lt;/p&gt;

&lt;p&gt;Circling back to the start, I would be very cautious about something that allows me to write very expressive code for my view. These kind of tools trick developers with promises of convenience and power but often lead to leaky abstractions unless you are very disciplined.&lt;/p&gt;

&lt;p&gt;Now have a think about all the tutorials you may have read around HTTP servers and Go. The good ones will recommended all of these principles without perhaps just calling them out. Rather than the community dancing around the idea of MVC, just embrace it. It's a tried and tested pattern and most people advocate it anyway, just not explicitly. If we were explicit then maybe there wouldn't be a new post every week about how to structure a HTTP server!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to structure your web app
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Understand &lt;em&gt;the idea&lt;/em&gt; of MVC.&lt;/li&gt;
&lt;li&gt;Your &lt;code&gt;http.Handler&lt;/code&gt;s are your controllers, make sure they only do things controllers do according to above.&lt;/li&gt;
&lt;li&gt;All your other business logic (Model) lives elsewhere, in packages centered around real things. If it's a bank i'd maybe have packages for &lt;code&gt;Account&lt;/code&gt;, &lt;code&gt;Currency&lt;/code&gt;, &lt;code&gt;Customer&lt;/code&gt; e.t.c. Your controller will call things in your packages to do useful stuff.&lt;/li&gt;
&lt;li&gt;Depending on what you're building you can just use the encoding packages to spit out XML or JSON, or if it's HTML just use &lt;code&gt;template/html&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>go</category>
      <category>mvc</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Learn Go with tests - Roman Numerals and Property Based Tests</title>
      <dc:creator>Chris James</dc:creator>
      <pubDate>Wed, 10 Jul 2019 12:28:40 +0000</pubDate>
      <link>https://forem.com/quii/learn-go-with-tests-roman-numerals-and-property-based-tests-3mh6</link>
      <guid>https://forem.com/quii/learn-go-with-tests-roman-numerals-and-property-based-tests-3mh6</guid>
      <description>&lt;p&gt;This is a post taken from a project called &lt;a href="https://github.com/quii/learn-go-with-tests"&gt;Learn Go with tests&lt;/a&gt; the aim of which is to get a familiarity with Go and learn techniques around TDD&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/quii/learn-go-with-tests/tree/master/roman-numerals"&gt;You can find all the code for this chapter here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some companies will ask you to do the &lt;a href="http://codingdojo.org/kata/RomanNumerals/"&gt;Roman Numeral Kata&lt;/a&gt; as part of the interview process. This chapter will show how you can tackle it with TDD.&lt;/p&gt;

&lt;p&gt;We are going to write a function which converts an &lt;a href="https://en.wikipedia.org/wiki/Arabic_numerals"&gt;Arabic number&lt;/a&gt; (numbers 0 to 9) to a Roman Numeral.&lt;/p&gt;

&lt;p&gt;If you haven't heard of &lt;a href="https://en.wikipedia.org/wiki/Roman_numerals"&gt;Roman Numerals&lt;/a&gt; they are how the Romans wrote down numbers.&lt;/p&gt;

&lt;p&gt;You build them by sticking symbols together and those symbols represent numbers&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;I&lt;/code&gt; is "one". &lt;code&gt;III&lt;/code&gt; is three. &lt;/p&gt;

&lt;p&gt;Seems easy but there's a few interesting rules. &lt;code&gt;V&lt;/code&gt; means five, but &lt;code&gt;IV&lt;/code&gt; is 4 (not &lt;code&gt;IIII&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;&lt;code&gt;MCMLXXXIV&lt;/code&gt; is 1984. That looks complicated and it's hard to imagine how we can write code to figure this out right from the start.&lt;/p&gt;

&lt;p&gt;As this book stresses, a key skill for software developers is to try and identify "thin vertical slices" of &lt;em&gt;useful&lt;/em&gt; functionality and then &lt;strong&gt;iterating&lt;/strong&gt;. The TDD workflow helps facilitate iterative development.&lt;/p&gt;

&lt;p&gt;So rather than 1984, let's start with 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&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;TestRomanNumerals&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;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToRoman&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="n"&gt;want&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"I"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;want&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;"got '%s', want '%s'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&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;If you've got this far in the book this is hopefully feeling very boring and routine to you. That's a good thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try to run the test
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;./numeral_test.go:6:9: undefined: ConvertToRoman&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let the compiler guide the way&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the minimal amount of code for the test to run and check the failing test output
&lt;/h2&gt;

&lt;p&gt;Create our function but don't make the test pass yet, always make sure the tests fails how you expect&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&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;It should run now&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="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt;   &lt;span class="n"&gt;TestRomanNumerals&lt;/span&gt;
&lt;span class="o"&gt;--------&lt;/span&gt; &lt;span class="n"&gt;FAIL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TestRomanNumerals&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.00&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;numeral_test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="err"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="sc"&gt;'I'&lt;/span&gt;
&lt;span class="n"&gt;FAIL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"I"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;Not much to refactor yet. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;I know&lt;/em&gt; it feels weird just to hard-code the result but with TDD we want to stay out of "red" for as long as possible. It may &lt;em&gt;feel&lt;/em&gt; like we haven't accomplished much but we've defined our API and got a test capturing one of our rules; even if the "real" code is pretty dumb. &lt;/p&gt;

&lt;p&gt;Now use that uneasy feeling to write a new test to force us to write slightly less dumb code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&gt;

&lt;p&gt;We can use subtests to nicely group our tests&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;TestRomanNumerals&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;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&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;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1 gets converted to I"&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToRoman&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="n"&gt;want&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"I"&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;want&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;"got '%s', want '%s'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2 gets converted to II"&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"II"&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;want&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;"got '%s', want '%s'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&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;h2&gt;
  
  
  Try to run the test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestRomanNumerals/2_gets_converted_to_II
    --- FAIL: TestRomanNumerals/2_gets_converted_to_II (0.00s)
        numeral_test.go:20: got 'I', want 'II'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not much surprise there&lt;/p&gt;

&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;arabic&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"II"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"I"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yup, it still feels like we're not actually tackling the problem. So we need to write more tests to drive us forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;We have some repetition in our tests. When you're testing something which feels like it's a matter of "given input X, we expect Y" you should probably use table based tests.&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;TestRomanNumerals&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;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cases&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;Arabic&lt;/span&gt;      &lt;span class="kt"&gt;int&lt;/span&gt;
        &lt;span class="n"&gt;Want&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"1 gets converted to I"&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="s"&gt;"I"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"2 gets converted to II"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"II"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;cases&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;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Arabic&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;got&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Want&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;"got '%s', want '%s'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Want&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now easily add more cases without having to write any more test boilerplate.&lt;/p&gt;

&lt;p&gt;Let's push on and go for 3&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&gt;

&lt;p&gt;Add the following to our cases&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="s"&gt;"3 gets converted to III"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"III"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try to run the test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestRomanNumerals/3_gets_converted_to_III
    --- FAIL: TestRomanNumerals/3_gets_converted_to_III (0.00s)
        numeral_test.go:20: got 'I', want 'III'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;arabic&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"III"&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;arabic&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"II"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"I"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;OK so I'm starting to not enjoy these if statements and if you look at the code hard enough you can see that we're building a string of &lt;code&gt;I&lt;/code&gt; based on the size of &lt;code&gt;arabic&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We "know" that for more complicated numbers we will be doing some kind of arithmetic and string concatenation.  &lt;/p&gt;

&lt;p&gt;Let's try a refactor with these thoughts in mind, it &lt;em&gt;might not&lt;/em&gt; be suitable for the end solution but that's OK. We can always throw our code away and start afresh with the tests we have to guide us.&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;result&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&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;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;arabic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I"&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;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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;You may not have used &lt;a href="https://golang.org/pkg/strings/#Builder"&gt;&lt;code&gt;strings.Builder&lt;/code&gt;&lt;/a&gt; before&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Builder is used to efficiently build a string using Write methods. It minimizes memory copying.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Normally I wouldn't bother with such optimisations until I have an actual performance problem but the amount of code is not much larger than a "manual" appending on a string so we may as well use the faster approach.&lt;/p&gt;

&lt;p&gt;The code looks better to me and describes the domain &lt;em&gt;as we know it right now&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Romans were into DRY too...
&lt;/h3&gt;

&lt;p&gt;Things start getting more complicated now. The Romans in their wisdom thought repeating characters would become hard to read and count. So a rule with Roman Numerals is you cant have the same character repeated more than 3 times in a row. &lt;/p&gt;

&lt;p&gt;Instead you take the next highest symbol and then "subtract" by putting a symbol to the left of it. Not all symbols can be used as subtractors; only (1), X (10), C (100) and M (1,000).&lt;/p&gt;

&lt;p&gt;For example &lt;code&gt;5&lt;/code&gt; in Roman Numerals is &lt;code&gt;V&lt;/code&gt;. To create 4 you do not do &lt;code&gt;IIII&lt;/code&gt;, instead you do &lt;code&gt;IV&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&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="s"&gt;"4 gets converted to IV (cant repeat more than 3 times)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IV"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try to run the test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestRomanNumerals/4_gets_converted_to_IV_(cant_repeat_more_than_3_times)
    --- FAIL: TestRomanNumerals/4_gets_converted_to_IV_(cant_repeat_more_than_3_times) (0.00s)
        numeral_test.go:24: got 'IIII', want 'IV'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;arabic&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"IV"&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;result&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&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;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;arabic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I"&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;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;I dont "like" that we have broken our string building pattern and I want to carry on with it.&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;result&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;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;i&lt;/span&gt;&lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IV"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I"&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;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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 order for 4 to "fit" with my current thinking I now count down from the Arabic number, adding symbols to our string as we progress. Not sure if this will work in the long run but let's see!&lt;/p&gt;

&lt;p&gt;Let's make 5 work&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&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="s"&gt;"5 gets converted to V"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try to run the test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestRomanNumerals/5_gets_converted_to_V
    --- FAIL: TestRomanNumerals/5_gets_converted_to_V (0.00s)
        numeral_test.go:25: got 'IIV', want 'V'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&gt;

&lt;p&gt;Just copy the approach we did for 4&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;result&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;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;i&lt;/span&gt;&lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&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="k"&gt;break&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;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IV"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I"&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;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;Repetition in loops like this are usually a sign of an abstraction waiting to be called out. Short-circuiting loops can be an effective tool for reabability but it could also be telling you something else.&lt;/p&gt;

&lt;p&gt;We are looping over our Arabic number and if we hit certain symbols we are calling &lt;code&gt;break&lt;/code&gt; but what we are &lt;em&gt;really&lt;/em&gt; doing is subtracting over &lt;code&gt;i&lt;/code&gt; in a ham-fisted manner.&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;result&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&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;switch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&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="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IV"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;arabic&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;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;arabic&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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;ul&gt;
&lt;li&gt;Given the signals I'm reading from our code, driven from our tests of some very basic scenarios I can see that to build a Roman Numeral I need to subtract from &lt;code&gt;arabic&lt;/code&gt; as I apply symbols&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;for&lt;/code&gt; loop no longer relies on an &lt;code&gt;i&lt;/code&gt; and instead we will keep building our string until we have subtracted enough symbols away from &lt;code&gt;arabic&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm pretty sure this approach will be valid for 6 (VI), 7 (VII) and 8 (VIII) too. Nonetheless add the cases in to our test suite and check (I wont include the code for brevity, check the github for samples if you're unsure).&lt;/p&gt;

&lt;p&gt;9 follows the same rule as 4 in that we should subtract &lt;code&gt;I&lt;/code&gt; from the representation of the following number. 10 is represented in Roman Numerals with &lt;code&gt;X&lt;/code&gt;; so therefore 9 should be &lt;code&gt;IX&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&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="s"&gt;"9 gets converted to IX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IX"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try to run the test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestRomanNumerals/9_gets_converted_to_IX
    --- FAIL: TestRomanNumerals/9_gets_converted_to_IX (0.00s)
        numeral_test.go:29: got 'VIV', want 'IX'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&gt;

&lt;p&gt;We should be able to adopt the same approach as before&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;case&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IX"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;It &lt;em&gt;feels&lt;/em&gt; like the code is still telling us there's a refactor somewhere but it's not totally obvious to me, so let's keep going. &lt;/p&gt;

&lt;p&gt;I'll skip the code for this too, but add to your test cases a test for &lt;code&gt;10&lt;/code&gt; which should be &lt;code&gt;X&lt;/code&gt; and make it pass before reading on.&lt;/p&gt;

&lt;p&gt;Here are a few tests I added as I'm confident up to 39 our code should work&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="s"&gt;"10 gets converted to X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"14 gets converted to XIV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XIV"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"18 gets converted to XVIII"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XVIII"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"20 gets converted to XX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"39 gets converted to XXXIX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XXXIX"&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've ever done OO programming, you'll know that you should view &lt;code&gt;switch&lt;/code&gt; statements with a bit of suspicion. Usually you are capturing a concept or data inside some imperative code when in fact it could be captured in a class structure instead. &lt;/p&gt;

&lt;p&gt;Go isn't strictly OO but that doesn't mean we ignore the lessons OO offers entirely (as much as some would like to tell you). &lt;/p&gt;

&lt;p&gt;Our switch statement is describing some truths about Roman Numerals along with behaviour. &lt;/p&gt;

&lt;p&gt;We can refactor this by decoupling the data from the behaviour.&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;RomanNumeral&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt;  &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;Symbol&lt;/span&gt; &lt;span class="kt"&gt;string&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;RomanNumerals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;RomanNumeral&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;5&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="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IV"&lt;/span&gt;&lt;span class="p"&gt;},&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="s"&gt;"I"&lt;/span&gt;&lt;span class="p"&gt;},&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;result&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numeral&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;RomanNumerals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;numeral&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numeral&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;numeral&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&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;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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 feels much better. We've declared some rules around the numerals as data rather than hidden in an algorithm and we can see how we just work through the Arabic number, trying to add symbols to our result if they fit. &lt;/p&gt;

&lt;p&gt;Does this abstraction work for bigger numbers? Extend the test suite so it works for the Roman number for 50 which is &lt;code&gt;L&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Here are some test cases, try and make them pass.&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="s"&gt;"40 gets converted to XL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XL"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"47 gets converted to XLVII"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XLVII"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"49 gets converted to XLIX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XLIX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"50 gets converted to L"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"L"&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 a cheater, all you needed to add to the &lt;code&gt;RomanNumerals&lt;/code&gt; array is&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="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XL"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  And the rest!
&lt;/h2&gt;

&lt;p&gt;Here are the remaining symbols&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Arabic&lt;/th&gt;
&lt;th&gt;Roman&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Take the same approach for the remaining symbols, it should just be a matter of adding data to both the tests and our array of symbols.&lt;/p&gt;

&lt;p&gt;Does your code work for &lt;code&gt;1984&lt;/code&gt;: &lt;code&gt;MCMLXXXIV&lt;/code&gt; ?&lt;/p&gt;

&lt;p&gt;Here is my final test suite&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;TestRomanNumerals&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;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cases&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Arabic&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
        &lt;span class="n"&gt;Roman&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"I"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"II"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"III"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"IV"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&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="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"VI"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"VII"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"VIII"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"IX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"XIV"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"XVIII"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"XX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"XXXIX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"XL"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"XLVII"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"XLIX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"XC"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"CD"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"CM"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"M"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1984&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MCMLXXXIV"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MMMCMXCIX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2014&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MMXIV"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1006&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MVI"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;798&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"DCCXCVIII"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;cases&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;Run&lt;/span&gt;&lt;span class="p"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d gets converted to '%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Arabic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Roman&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Arabic&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;got&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Roman&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;"got '%s', want '%s'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Roman&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I removed &lt;code&gt;description&lt;/code&gt; as I felt the &lt;em&gt;data&lt;/em&gt; described enough of the information.&lt;/li&gt;
&lt;li&gt;I added a few other edge cases I found just to give me a little more confidence. With table based tests this is very cheap to do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn't change the algorithm, all I had to do was update the &lt;code&gt;RomanNumerals&lt;/code&gt; array.&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;RomanNumerals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;RomanNumeral&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"M"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"CM"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"CD"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XC"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XL"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;5&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="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IV"&lt;/span&gt;&lt;span class="p"&gt;},&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="s"&gt;"I"&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;
  
  
  Parsing Roman Numerals
&lt;/h2&gt;

&lt;p&gt;We're not done yet. Next we're going to write a function that converts &lt;em&gt;from&lt;/em&gt; a Roman Numeral to an &lt;code&gt;int&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&gt;

&lt;p&gt;We can re-use our test cases here with a little refactoring&lt;/p&gt;

&lt;p&gt;Move the &lt;code&gt;cases&lt;/code&gt; variable outside of the test as a package variable in a &lt;code&gt;var&lt;/code&gt; block.&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;TestConvertingToArabic&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;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;cases&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;1&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;Run&lt;/span&gt;&lt;span class="p"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"'%s' gets converted to %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Roman&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Arabic&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Roman&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;got&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Arabic&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;"got %d, want %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Arabic&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice I am using the slice functionality to just run one of the tests for now (&lt;code&gt;cases[:1]&lt;/code&gt;) as trying to make all of those tests pass all at once is too big a leap&lt;/p&gt;

&lt;h2&gt;
  
  
  Try to run the test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./numeral_test.go:60:11: undefined: ConvertToArabic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write the minimal amount of code for the test to run and check the failing test output
&lt;/h2&gt;

&lt;p&gt;Add our new function definition&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;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&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="m"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test should now run and fail&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-------- FAIL: TestConvertingToArabic (0.00s)
    --- FAIL: TestConvertingToArabic/'I'_gets_converted_to_1 (0.00s)
        numeral_test.go:62: got 0, want 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&gt;

&lt;p&gt;You know what to 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;func&lt;/span&gt; &lt;span class="n"&gt;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&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="m"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, change the slice index in our test to move to the next test case (e.g. &lt;code&gt;cases[:2]&lt;/code&gt;). Make it pass yourself with the dumbest code you can think of, continue writing dumb code (best book ever right?) for the third case too. Here's my dumb code.&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;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&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;roman&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"III"&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;3&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;roman&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"II"&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;2&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;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Through the dumbness of &lt;em&gt;real code that works&lt;/em&gt; we can start to see a pattern like before. We need to iterate through the input and build &lt;em&gt;something&lt;/em&gt;, in this case a total.&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;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&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;total&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&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;total&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&gt;

&lt;p&gt;Next we move to &lt;code&gt;cases[:4]&lt;/code&gt; (&lt;code&gt;IV&lt;/code&gt;) which now fails because it gets 2 back as that's the length of the string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// earlier..&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;RomanNumerals&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;RomanNumeral&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;r&lt;/span&gt; &lt;span class="n"&gt;RomanNumerals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="kt"&gt;string&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;for&lt;/span&gt; &lt;span class="n"&gt;_&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="k"&gt;range&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;symbol&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&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="m"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// later..&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&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;total&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c"&gt;// look ahead to next symbol if we can and, the current symbol is base 10 (only valid subtractors)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'I'&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;nextSymbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="c"&gt;// build the two character string&lt;/span&gt;
            &lt;span class="n"&gt;potentialNumber&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nextSymbol&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="c"&gt;// get the value of the two character string&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;potentialNumber&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;value&lt;/span&gt; &lt;span class="o"&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;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
                &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// move past this character too for the next loop&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;total&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;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;total&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&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 horrible but it does work. It's so bad I felt the need to add comments. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I wanted to be able to look up an integer value for a given roman numeral so I made a type from our array of &lt;code&gt;RomanNumeral&lt;/code&gt;s and then added a method to it, &lt;code&gt;ValueOf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Next in our loop we need to look ahead &lt;em&gt;if&lt;/em&gt; the string is big enough &lt;em&gt;and the current symbol is a valid subtractor&lt;/em&gt;. At the moment it's just &lt;code&gt;I&lt;/code&gt; (1) but can also be &lt;code&gt;X&lt;/code&gt; (10) or &lt;code&gt;C&lt;/code&gt; (100).

&lt;ul&gt;
&lt;li&gt;If it satisfies both of these conditions we need to lookup the value and add it to the total &lt;em&gt;if&lt;/em&gt; it is one of the special subtractors, otherwise ignore it&lt;/li&gt;
&lt;li&gt;Then we need to further increment &lt;code&gt;i&lt;/code&gt; so we dont count this symbol twice&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;I'm not entirely convinced this will be the long-term approach and there's potentially some interesting refactors we could do, but I'll resist that in case our approach is totally wrong. I'd rather make a few more tests pass first and see. For the meantime I made the first &lt;code&gt;if&lt;/code&gt; statement slightly less horrible.&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;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&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;total&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&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;couldBeSubtractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;nextSymbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="c"&gt;// build the two character string&lt;/span&gt;
            &lt;span class="n"&gt;potentialNumber&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nextSymbol&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="c"&gt;// get the value of the two character string&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;potentialNumber&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;value&lt;/span&gt; &lt;span class="o"&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;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
                &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// move past this character too for the next loop&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;total&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;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;total&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&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;couldBeSubtractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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;currentSymbol&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&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;index&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;currentSymbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'I'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write the test first
&lt;/h2&gt;

&lt;p&gt;Let's move on to &lt;code&gt;cases[:5]&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestConvertingToArabic/'V'_gets_converted_to_5
    --- FAIL: TestConvertingToArabic/'V'_gets_converted_to_5 (0.00s)
        numeral_test.go:62: got 1, want 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write enough code to make it pass
&lt;/h2&gt;

&lt;p&gt;Apart from when it is subtractive our code assumes that every character is a &lt;code&gt;I&lt;/code&gt; which is why the value is 1. We should be able to re-use our &lt;code&gt;ValueOf&lt;/code&gt; method to fix 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;func&lt;/span&gt; &lt;span class="n"&gt;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&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;total&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c"&gt;// look ahead to next symbol if we can and, the current symbol is base 10 (only valid subtractors)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;couldBeSubtractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;nextSymbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="c"&gt;// build the two character string&lt;/span&gt;
            &lt;span class="n"&gt;potentialNumber&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nextSymbol&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;value&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;potentialNumber&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&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;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
                &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// move past this character too for the next loop&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;total&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// this is fishy...&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;total&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&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;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;symbol&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;total&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;When you index strings in Go, you get a &lt;code&gt;byte&lt;/code&gt;. This is why when we build up the string again we have to do stuff like &lt;code&gt;string([]byte{symbol})&lt;/code&gt;. It's repeated a couple of times, let's just move that functionality so that &lt;code&gt;ValueOf&lt;/code&gt; takes some bytes instead.&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;r&lt;/span&gt; &lt;span class="n"&gt;RomanNumerals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="kt"&gt;byte&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;symbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&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="k"&gt;range&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;symbol&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&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="m"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can just pass in the bytes as is, to our function&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;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&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;total&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&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;couldBeSubtractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;roman&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;value&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&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;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
                &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// move past this character too for the next loop&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;total&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// this is fishy...&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;total&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&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;total&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's still pretty nasty, but it's getting there.&lt;/p&gt;

&lt;p&gt;If you start moving our &lt;code&gt;cases[:xx]&lt;/code&gt; number through you'll see that quite a few are passing now. Remove the slice operator entirely and see which ones fail, here's some examples from my suite&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestConvertingToArabic/'XL'_gets_converted_to_40
    --- FAIL: TestConvertingToArabic/'XL'_gets_converted_to_40 (0.00s)
        numeral_test.go:62: got 60, want 40
=== RUN   TestConvertingToArabic/'XLVII'_gets_converted_to_47
    --- FAIL: TestConvertingToArabic/'XLVII'_gets_converted_to_47 (0.00s)
        numeral_test.go:62: got 67, want 47
=== RUN   TestConvertingToArabic/'XLIX'_gets_converted_to_49
    --- FAIL: TestConvertingToArabic/'XLIX'_gets_converted_to_49 (0.00s)
        numeral_test.go:62: got 69, want 49
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think all we're missing is an update to &lt;code&gt;couldBeSubtractive&lt;/code&gt; so that it accounts for the other kinds of subtractive symbols&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;couldBeSubtractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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;currentSymbol&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;isSubtractiveSymbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;currentSymbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'I'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;currentSymbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'X'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;currentSymbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="sc"&gt;'C'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isSubtractiveSymbol&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try again, they still fail. However we left a comment earlier...&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;total&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// this is fishy...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should never be just increment total as that implies every symbol is a &lt;code&gt;I&lt;/code&gt;. Replace it with&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;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And all the tests pass! Now that we have fully working software we can indulge ourselves in some refactoring, with confidence&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactor
&lt;/h2&gt;

&lt;p&gt;Here is all the code I finished up with. I had a few failed attempts but as I keep emphasising, that's fine and the tests help me play around with the code freely.&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;"strings"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbols&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;windowedRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Symbols&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;allRomanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&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;span class="k"&gt;return&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;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;string&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;result&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numeral&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;allRomanNumerals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;numeral&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numeral&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;numeral&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&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;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;romanNumeral&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt;  &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;Symbol&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;romanNumeral&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;r&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="kt"&gt;byte&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;symbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&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="k"&gt;range&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;symbol&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&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="m"&gt;0&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;r&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&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="k"&gt;range&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;symbol&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;true&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;false&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;allRomanNumerals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;romanNumerals&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"M"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"CM"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"D"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"CD"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XC"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"L"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"XL"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IX"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;5&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="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IV"&lt;/span&gt;&lt;span class="p"&gt;},&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="s"&gt;"I"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;windowedRoman&lt;/span&gt; &lt;span class="kt"&gt;string&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;windowedRoman&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Symbols&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt; &lt;span class="p"&gt;[][]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&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;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;notAtEnd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;notAtEnd&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isSubtractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;allRomanNumerals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&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;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;symbols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;byte&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;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])})&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&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;symbols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;isSubtractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&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;symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'I'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'X'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'C'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My main problem with the previous code is similar to our refactor from earlier. We had too many concerns coupled together. We wrote an algorithm which was trying to extract Roman Numerals from a string &lt;em&gt;and&lt;/em&gt; then find their values. &lt;/p&gt;

&lt;p&gt;So I created a new type &lt;code&gt;windowedRoman&lt;/code&gt; which took care of extracting the numerals, offering a &lt;code&gt;Symbols&lt;/code&gt; method to retrieve them as a slice. This meant out &lt;code&gt;ConvertToArabic&lt;/code&gt; function could simply iterate over the symbols and total them.&lt;/p&gt;

&lt;p&gt;I broke the code down a bit by extracting some functions, especially around the wonky if statement to figure out if the symbol we are currently dealing with is a two character subtractive symbol.&lt;/p&gt;

&lt;p&gt;There's probably a more elegant way but I'm not going to sweat it. The code is there and it works and it is tested. If I (or anyone else) finds a better way they can safely change it - the hard work is done.&lt;/p&gt;

&lt;h2&gt;
  
  
  An intro to property based tests
&lt;/h2&gt;

&lt;p&gt;There have been a few rules in the domain of Roman Numerals that we have worked with in this chapter&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cant have more than 3 consecutive symbols&lt;/li&gt;
&lt;li&gt;Only (1), X (10), C (100) and M (1,000) can be "subtractors"&lt;/li&gt;
&lt;li&gt;Taking the result of &lt;code&gt;ConvertToRoman(N)&lt;/code&gt; and passing it to &lt;code&gt;ConvertToArabic&lt;/code&gt; should return us &lt;code&gt;N&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tests we have written so far can be described as "example" based tests where we provide the tooling some examples around our code to verify.&lt;/p&gt;

&lt;p&gt;What if we could take these rules that we know about our domain and somehow exercise them against our code?&lt;/p&gt;

&lt;p&gt;Property based tests help you do this by throwing random data at your code and verifying the rules you describe always hold true. A lot of people think property based tests are mainly about random data but they would be mistaken. The real challenge about property based tests is having a &lt;em&gt;good&lt;/em&gt; understanding of your domain so you can write these properties. &lt;/p&gt;

&lt;p&gt;Enough words, let's see some code&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;TestPropertiesOfConversion&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;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;assertion&lt;/span&gt; &lt;span class="o"&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;arabic&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;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fromRoman&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&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;fromRoman&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;arabic&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;quick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assertion&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;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;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;"failed checks"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rationale of property
&lt;/h3&gt;

&lt;p&gt;Our first test will check that if we transform a number into Roman, when we use our other function to convert it back to a number that we get what we originally had.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given random number (e.g &lt;code&gt;4&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;ConvertToRoman&lt;/code&gt; with random number (should return &lt;code&gt;IV&lt;/code&gt; if &lt;code&gt;4&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Take the result of above and pass it to &lt;code&gt;ConvertToArabic&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The above should give us our original input (&lt;code&gt;4&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This feels like a good test to build us confidence because it should break if there's a bug in either. The only way it could pass is if they have the same kind of bug; which isn't impossible but feels unlikely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical explanation
&lt;/h3&gt;

&lt;p&gt;We're using the &lt;a href="https://golang.org/pkg/testing/quick/"&gt;testing/quick&lt;/a&gt; package from the standard library&lt;/p&gt;

&lt;p&gt;Reading from the bottom, we provide &lt;code&gt;quick.Check&lt;/code&gt; a function that it will run against a number of random inputs, if the function returns &lt;code&gt;false&lt;/code&gt; it will be seen as failing the check. &lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;assertion&lt;/code&gt; function above takes a random number and runs our functions to test the property.&lt;/p&gt;

&lt;p&gt;### Run our test&lt;/p&gt;

&lt;p&gt;Try running it; your computer may hang for a while, so kill it when you're bored :) &lt;/p&gt;

&lt;p&gt;What's going on? Try adding the following to the assertion code.&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;assertion&lt;/span&gt; &lt;span class="o"&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;arabic&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;bool&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;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;3999&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&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;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fromRoman&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&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;fromRoman&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== RUN   TestPropertiesOfConversion
2019/07/09 14:41:27 6849766357708982977
2019/07/09 14:41:27 -7028152357875163913
2019/07/09 14:41:27 -6752532134903680693
2019/07/09 14:41:27 4051793897228170080
2019/07/09 14:41:27 -1111868396280600429
2019/07/09 14:41:27 8851967058300421387
2019/07/09 14:41:27 562755830018219185
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just running this very simple property has exposed a flaw in our implementation. We used &lt;code&gt;int&lt;/code&gt; as our input but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You cant do negative numbers with Roman Numerals&lt;/li&gt;
&lt;li&gt;Given our rule of a max of 3 consecutive symbols we cant represent a value greater than 3999 (&lt;a href="https://www.quora.com/Which-is-the-maximum-number-in-Roman-numerals"&gt;well, kinda&lt;/a&gt;) and &lt;code&gt;int&lt;/code&gt; has a much higher maximum value than 3999.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is great! We've been forced to think more deeply about our domain which is a real strength of property based tests. &lt;/p&gt;

&lt;p&gt;Clearly &lt;code&gt;int&lt;/code&gt; is not a great type. What if we tried something a little more appropriate?&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://golang.org/pkg/builtin/#uint16"&gt;&lt;code&gt;uint16&lt;/code&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Go has types for &lt;em&gt;unsigned integers&lt;/em&gt;, which means they cannot be negative; so that rules out one class of bug in our code immediately. By adding 16, it means it is a 16 bit integer which can store a max of &lt;code&gt;65535&lt;/code&gt;, which is still too big but gets us closer to what we need. &lt;/p&gt;

&lt;p&gt;Try updating the code to use &lt;code&gt;uint16&lt;/code&gt; rather than &lt;code&gt;int&lt;/code&gt;. I updated &lt;code&gt;assertion&lt;/code&gt; in the test to give a bit more visibility.&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;assertion&lt;/span&gt; &lt;span class="o"&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;arabic&lt;/span&gt; &lt;span class="kt"&gt;uint16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&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;arabic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;3999&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;true&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;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"testing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arabic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;roman&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToRoman&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arabic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fromRoman&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConvertToArabic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roman&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;fromRoman&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;arabic&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 run the test they now actually run and you can see what is being tested. You can run multiple times to see our code stands up well to the various values! This gives me a lot of confidence that our code is working how we want. &lt;/p&gt;

&lt;p&gt;The default number of runs &lt;code&gt;quick.Check&lt;/code&gt; performs is 100 but you can change that with a config.&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;quick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assertion&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;quick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;MaxCount&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;1000&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="no"&gt;nil&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;"failed checks"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Further work
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Can you write property tests that check the other properties we described?&lt;/li&gt;
&lt;li&gt;Can you think of a way of making it so it's impossible for someone to call our code with a number greater than 3999?

&lt;ul&gt;
&lt;li&gt;You could return an error&lt;/li&gt;
&lt;li&gt;Or create a new type that cannot represent &amp;gt; 3999

&lt;ul&gt;
&lt;li&gt;What do you think is best?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  More TDD practice with iterative development
&lt;/h3&gt;

&lt;p&gt;Did the thought of writing code that converts 1984 into MCMLXXXIV feel intimidating to you at first? It did to me and I've been writing software for quite a long time. &lt;/p&gt;

&lt;p&gt;The trick, as always, is to &lt;strong&gt;get started with something simple&lt;/strong&gt; and take &lt;strong&gt;small steps&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;At no point in this process did we make any large leaps, do any huge refactorings, or get in a mess.&lt;/p&gt;

&lt;p&gt;I can hear someone cynically saying "this is just a kata". I cant argue with that, but I still take this same approach for every project I work on. I never ship a big distributed system in my first step, I find the simplest thing the team could ship (usually a "Hello world" website) and then iterate on small bits of functionality in manageable chunks, just like how we did here.&lt;/p&gt;

&lt;p&gt;The skill is knowing &lt;em&gt;how&lt;/em&gt; to split work up, and that comes with practice and with some lovely TDD to help you on your way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Property based tests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Built into the standard library&lt;/li&gt;
&lt;li&gt;If you can think of ways to describe your domain rules in code, they are an excellent tool for giving you more confidence&lt;/li&gt;
&lt;li&gt;Force you to think about your domain deeply&lt;/li&gt;
&lt;li&gt;Potentially a nice complement to your test suite&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>kata</category>
      <category>tdd</category>
    </item>
  </channel>
</rss>
