<?xml version="1.0" encoding="UTF-8"?>
<rss version='2.0' xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Daniel Hall</title>
    <description></description>
    <link>https://danielhall.io/feed</link>
    <atom:link href="https://danielhall.io/feed" rel="self" type="application/rss+xml"/>
    <category domain="danielhall.io">Content Management/Blog</category>
    <language>en-us</language>
      <pubDate>Mon, 24 Oct 2022 23:45:53 -0600</pubDate>
    <managingEditor>daniel_hall@icloud.com (Daniel Hall)</managingEditor>
      <item>
        <guid>http://danielhall.io/model-defined-interfaces#54215</guid>
          <pubDate>Mon, 24 Oct 2022 23:45:53 -0600</pubDate>
        <link>http://danielhall.io/model-defined-interfaces</link>
        <title>Model-Defined Interfaces</title>
        <description>A Pattern for Better, Safer, and More Explicit API</description>
        <content:encoded><![CDATA[<p><img alt="Silvrback blog image" class="sb_float_center" src="https://silvrback.s3.amazonaws.com/uploads/3c9a4a7a-72c6-41c4-a0fa-f7798c8467c8/interface.jpg" /></p>

<p>Most iOS architectural patterns rely on protocols to define what data and behaviors (i.e. interfaces) will be available to client code. This is a perfectly workable approach, but it adds quite a bit of overhead in terms of creating the protocol and multiple conforming types.</p>

<p>For example:</p>
<div class="highlight"><pre><span></span><span class="kd">protocol</span> <span class="nc">AuthenticationProvider</span> <span class="p">{</span> 
  <span class="kd">var</span> <span class="nv">isAuthenticated</span><span class="p">:</span> <span class="nb">Bool</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span> 
  <span class="kd">var</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span><span class="p">?</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span> 
  <span class="kd">var</span> <span class="nv">authError</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span> 
  <span class="kd">func</span> <span class="nf">logInWithCredentials</span><span class="p">(</span><span class="kc">_</span> <span class="n">credentials</span><span class="p">:</span> <span class="n">Credentials</span><span class="p">)</span> 
  <span class="kd">func</span> <span class="nf">logOut</span><span class="p">()</span>
<span class="p">}</span>
</pre></div>
<p>This protocol minimally needs to be adopted two times: once for the actual production functionality, and once by a mock type for testing:</p>
<div class="highlight"><pre><span></span><span class="kd">class</span> <span class="nc">AuthenticationManager</span><span class="p">:</span> <span class="n">AuthenticationProvider</span> <span class="p">{</span> 
  <span class="kd">var</span> <span class="nv">isAuthenticated</span><span class="p">:</span> <span class="nb">Bool</span> 
  <span class="kd">var</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span><span class="p">?</span> 
  <span class="kd">var</span> <span class="nv">authError</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span>

  <span class="kd">func</span> <span class="nf">logInWithCredentials</span><span class="p">(</span><span class="kc">_</span> <span class="n">credentials</span><span class="p">:</span> <span class="n">Credentials</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Add _production_ implementation </span>
  <span class="p">}</span>

  <span class="kd">func</span> <span class="nf">logOut</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// Add _production_ implementation </span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">MockAuthenticationManager</span><span class="p">:</span> <span class="n">AuthenticationProvider</span> <span class="p">{</span> 
  <span class="kd">var</span> <span class="nv">isAuthenticated</span><span class="p">:</span> <span class="nb">Bool</span> 
  <span class="kd">var</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span><span class="p">?</span> 
  <span class="kd">var</span> <span class="nv">authError</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span>

  <span class="kd">func</span> <span class="nf">logInWithCredentials</span><span class="p">(</span><span class="kc">_</span> <span class="n">credentials</span><span class="p">:</span> <span class="n">Credentials</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Add _mock_ implementation </span>
  <span class="p">}</span>

  <span class="kd">func</span> <span class="nf">logOut</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// Add _mock_ implementation </span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>So at a bare minimum, this approach requires the creation of three significantly redundant types in order to use.</p>

<p>Now let’s contrast with a model-defined interface approach. Instead of declaring a protocol that must be conformed to, we declare the same data and behaviors as a model struct. Instead of having protocol methods, the struct contains closures that can be invoked:</p>
<div class="highlight"><pre><span></span><span class="kd">struct</span> <span class="nc">AuthenticationModel</span> <span class="p">{</span> 
  <span class="kd">let</span> <span class="nv">isAuthenticated</span><span class="p">:</span> <span class="nb">Bool</span>
  <span class="kd">let</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span><span class="p">?</span>
  <span class="kd">let</span> <span class="nv">authError</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span>
  <span class="kd">let</span> <span class="nv">logInWithCredentials</span><span class="p">:</span> <span class="p">(</span><span class="n">Credentials</span><span class="p">)</span> <span class="p">-&gt;</span> <span class="nb">Void</span> 
  <span class="kd">let</span> <span class="nv">logOut</span><span class="p">:</span> <span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
<span class="p">}</span>
</pre></div>
<p>Here there is no need to conform to a protocol or define redundant concrete types. Instead for a screen or class that depends on this model, the production code can pass in an instance with “real” closures and values, while test code can simply initialize the struct with mock values and closures like this:</p>
<div class="highlight"><pre><span></span><span class="kd">let</span> <span class="nv">mockAuthenticationModel</span><span class="p">:</span> <span class="n">AuthenticationModel</span> <span class="p">=</span>
  <span class="p">.</span><span class="kd">init</span><span class="p">(</span><span class="n">isAuthenticated</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
        <span class="n">authToken</span><span class="p">:</span> <span class="kc">nil</span><span class="p">,</span>
        <span class="n">authError</span><span class="p">:</span> <span class="kc">nil</span><span class="p">,</span>
        <span class="n">logInWithCredentials</span><span class="p">:</span> <span class="p">{</span> <span class="n">loginExpectation</span><span class="p">.</span><span class="n">fulfill</span><span class="p">()</span> <span class="p">},</span>
        <span class="n">logOut</span><span class="p">:</span> <span class="p">{</span> <span class="n">XCTFail</span><span class="p">(</span><span class="s">&quot;Incorrectly called logOut&quot;</span><span class="p">)</span> <span class="p">})</span>

<span class="n">testSubject</span> <span class="p">=</span> <span class="p">.</span><span class="kd">init</span><span class="p">(</span><span class="n">authmodel</span><span class="p">:</span> <span class="n">mockAuthenticationModel</span><span class="p">)</span>
</pre></div>
<p>So we can see that model-defined interfaces immediately reduce redundancy and the number of types which must be defined. However, this is just the beginning and a relatively minor benefit. The most important benefits of model-defined interfaces are compiler-enforced safety, reduction in test cases and defensive code, and self-documenting API.</p>

<hr>

<h2 id="compiler-enforced-safety">Compiler-Enforced Safety</h2>

<hr>

<p>Looking at the <code>AuthenticationModel</code> example above, you might notice some potential for misuse or undefined behavior. Specifically: </p>

<ul>
<li>What happens if you call <code>logOut()</code> when the user is already logged out?</li>
<li>What happens if you call <code>logInWithCredentials()</code> when the user is already logged in?</li>
</ul>

<p>In fact, when it comes to authentication functionality, we don’t want to allow either of these possibilities to even happen at all!</p>

<p>And these sorts of cases are where model-defined interfaces really shine. Here is how we can adjust our model to more accurately represent the safe usage of this API:</p>
<div class="highlight"><pre><span></span><span class="kd">enum</span> <span class="nc">AuthenticationModel</span> <span class="p">{</span> 
  <span class="k">case</span> <span class="n">authenticated</span><span class="p">(</span><span class="n">Authenticated</span><span class="p">)</span> 
  <span class="k">case</span> <span class="n">notAuthenticated</span><span class="p">(</span><span class="n">NotAuthenticated</span><span class="p">)</span>  

  <span class="kd">struct</span> <span class="nc">Authenticated</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">logOut</span><span class="p">:</span> <span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
  <span class="p">}</span>

  <span class="kd">struct</span> <span class="nc">NotAuthenticated</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">logInWithCredentials</span><span class="p">:</span> <span class="p">(</span><span class="n">Credentials</span><span class="p">)</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>We have now made <code>AuthenticationModel</code> an enum with two distinct states or cases: <code>.authenticated</code> and <code>.notAuthenticated</code>. Note that the <code>logOut</code> closure only exists in the <code>.authenticated</code> state, and the <code>logInWithCredentials</code> closure only exists in the <code>.notAuthenticated</code> state. Because of this definition, it is now impossible for a developer to mistakenly invoke a closure in the wrong state because the compiler itself won’t allow it!</p>

<p><strong><em>This kind of contextual API surface is simply not possible to express using protocols!</em></strong></p>

<hr>

<h2 id="reduction-in-test-cases-and-defensive-code">Reduction in Test Cases and Defensive Code</h2>

<hr>

<p>Beyond the potentially unsafe behaviors we were able to clean up above by limiting their existence only to the correct state, there are more potential issues you may have noticed with our original protocol:</p>
<div class="highlight"><pre><span></span><span class="kd">protocol</span> <span class="nc">AuthenticationProvider</span> <span class="p">{</span> 
  <span class="kd">var</span> <span class="nv">isAuthenticated</span><span class="p">:</span> <span class="nb">Bool</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span> 
  <span class="kd">var</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span><span class="p">?</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span> 
  <span class="kd">var</span> <span class="nv">authError</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span> 
  <span class="kd">func</span> <span class="nf">logInWithCredentials</span><span class="p">(</span><span class="kc">_</span> <span class="n">credentials</span><span class="p">:</span> <span class="n">Credentials</span><span class="p">)</span> 
  <span class="kd">func</span> <span class="nf">logOut</span><span class="p">()</span>
<span class="p">}</span>
</pre></div>
<p>Specifically, we have a few properties that suggest implicit but not documented rules. For example:</p>

<ul>
<li>There is an optional <code>authToken</code> property, which should probably be <code>nil</code> when <code>isAuthenticated == false</code> and should probably <em>never</em> be <code>nil</code> when <code>isAuthenticated == true</code>.</li>
<li>There is an <code>authError</code> property, which should conversely never be <code>nil</code> when<code>isAuthenticated == true</code>, since authentication was successful and so shouldn&#39;t have resulted in an error!</li>
</ul>

<p>These are in addition to the already noted implicit rules that</p>

<ul>
<li>If <code>isAuthenticated == true</code> the <code>logInWithCredentials()</code> method should be ignored</li>
<li>If <code>isAuthenticated == false</code> the <code>logOut()</code> method should be ignored.</li>
</ul>

<p>In a typical protocol-based approach, these implicit rules would need to be enforced through test cases and defensive code. For example, defensive code would look something like this:</p>
<div class="highlight"><pre><span></span><span class="kd">class</span> <span class="nc">AuthenticationManager</span><span class="p">:</span> <span class="n">AuthenticationProvider</span> <span class="p">{</span> 
  <span class="kd">var</span> <span class="nv">isAuthenticated</span><span class="p">:</span> <span class="nb">Bool</span> 
  <span class="kd">var</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span><span class="p">?</span> 
  <span class="kd">var</span> <span class="nv">authError</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span>

  <span class="kd">func</span> <span class="nf">logInWithCredentials</span><span class="p">(</span><span class="kc">_</span> <span class="n">credentials</span><span class="p">:</span> <span class="n">Credentials</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">guard</span> <span class="o">!</span><span class="n">isAuthenticated</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span> <span class="c1">// &lt;-- Defensive code to early exit if called in wrong context</span>
    <span class="c1">// Perform actual log in here</span>
  <span class="p">}</span>

  <span class="kd">func</span> <span class="nf">logOut</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">guard</span> <span class="n">isAuthenticated</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span> <span class="c1">// &lt;-- Defensive code to early exit if called in wrong context</span>
    <span class="c1">// Perform actual log out here</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>and example test cases might look something like this:</p>
<div class="highlight"><pre><span></span><span class="c1">// If we log in with valid credentials we should be authenticated and should have a token</span>
<span class="kd">func</span> <span class="nf">testAuthTokenIsNotNil</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">let</span> <span class="nv">authentication</span> <span class="p">=</span> <span class="n">AuthenticationManager</span><span class="p">()</span>
  <span class="n">authentication</span><span class="p">.</span><span class="n">logInWithCredentials</span><span class="p">(.</span><span class="n">validTestCredentials</span><span class="p">)</span> <span class="c1">// We pass in valid credentials</span>
  <span class="n">XCTAssertTrue</span><span class="p">(</span><span class="n">authentication</span><span class="p">.</span><span class="n">isAuthenticated</span><span class="p">)</span> <span class="c1">// We expect authentication to succeed</span>
  <span class="n">XCTAssertNotNil</span><span class="p">(</span><span class="n">authentication</span><span class="p">.</span><span class="n">authToken</span><span class="p">)</span> <span class="c1">// If authentication succeeded the token must not be nil</span>
<span class="p">}</span>

<span class="c1">// If we attempt login with invalid credentials we should not be authenticated and should NOT have a token</span>
<span class="kd">func</span> <span class="nf">testAuthTokenIsNil</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">let</span> <span class="nv">authentication</span> <span class="p">=</span> <span class="n">AuthenticationManager</span><span class="p">()</span>
  <span class="n">authentication</span><span class="p">.</span><span class="n">logInWithCredentials</span><span class="p">(.</span><span class="n">invalidTestCredentials</span><span class="p">)</span> <span class="c1">// We pass in invalid credentials</span>
  <span class="n">XCTAssertFalse</span><span class="p">(</span><span class="n">authentication</span><span class="p">.</span><span class="n">isAuthenticated</span><span class="p">)</span> <span class="c1">// We expect authentication to fail</span>
  <span class="n">XCTAssertNil</span><span class="p">(</span><span class="n">authentication</span><span class="p">.</span><span class="n">authToken</span><span class="p">)</span> <span class="c1">// If authentication didn&#39;t succeed the token MUST be nil</span>
<span class="p">}</span>

<span class="c1">// If we log in with valid credentials there should not be any error</span>
<span class="kd">func</span> <span class="nf">testErrorIsNil</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">let</span> <span class="nv">authentication</span> <span class="p">=</span> <span class="n">AuthenticationManager</span><span class="p">()</span>
  <span class="n">authentication</span><span class="p">.</span><span class="n">logInWithCredentials</span><span class="p">(.</span><span class="n">validTestCredentials</span><span class="p">)</span>
  <span class="n">XCTAssertTrue</span><span class="p">(</span><span class="n">authentication</span><span class="p">.</span><span class="n">isAuthenticated</span><span class="p">)</span> <span class="c1">// We expect authentication to succeed</span>
  <span class="n">XCTAssertNil</span><span class="p">(</span><span class="n">authentication</span><span class="p">.</span><span class="n">error</span><span class="p">)</span> <span class="c1">// If authentication succeeded the error property should be nil</span>
<span class="p">}</span>
</pre></div>
<p>It&#39;s worth pointing out that the defensive coding and test cases needed to validate these implicit rules would need to be implemented for <strong><em>every type</em></strong> that conforms to the protocol!</p>

<p>Let&#39;s finish converting this protocol-defined interface to a model-defined interface and see what happens:</p>
<div class="highlight"><pre><span></span><span class="kd">enum</span> <span class="nc">AuthenticationModel</span> <span class="p">{</span> 
  <span class="k">case</span> <span class="n">authenticated</span><span class="p">(</span><span class="n">Authenticated</span><span class="p">)</span> 
  <span class="k">case</span> <span class="n">notAuthenticated</span><span class="p">(</span><span class="n">NotAuthenticated</span><span class="p">)</span>  

  <span class="kd">struct</span> <span class="nc">Authenticated</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span>
    <span class="kd">let</span> <span class="nv">logOut</span><span class="p">:</span> <span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
  <span class="p">}</span>

  <span class="kd">struct</span> <span class="nc">NotAuthenticated</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">error</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span>
    <span class="kd">let</span> <span class="nv">logInWithCredentials</span><span class="p">:</span> <span class="p">(</span><span class="n">Credentials</span><span class="p">)</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>Note how we have added the <code>error</code> and <code>authToken</code> properties to only the appropriate context. And the <code>isAuthenticated</code> property is itself replaced by the enum cases of <code>.notAuthenticated</code> and <code>.authenticated</code>. What does this achieve? Well since it is no longer possible to even attempt to access the <code>authToken</code> or call <code>logOut()</code> in a <code>.notAuthenticated</code> state, we can remove all defensive coding associated with validating the implicit rules. The same goes for accessing <code>error</code> or calling <code>logInWithCredentials()</code> in an <code>.authenticated</code> state. And beyond removing any defensive code, we can also remove the test cases that validated these implicit rules as well, since invalid combinations of property values and states are now impossible.</p>

<p><em>In essence, we have moved <em>implicit</em> rules that had to be tested and checked in defensive code into <em>explicit</em> rules defined in the types themselves. Which again allows the compiler to enforce them rather than requiring humans to remember and correctly handle these rules manually.</em> </p>

<p>For just this simple example converting the protocol-defined interface into a model-defined interface with two distinct cases would allow us to remove at least 8 units tests and associated defensive code:</p>

<ul>
<li>When <code>authToken</code> should / should not be nil</li>
<li>When <code>error</code> should / should not be nil</li>
<li>When <code>logOut</code> can / can&#39;t be called</li>
<li>When <code>logInWithCredentials</code> can / can&#39;t be called</li>
</ul>

<p>For readers who are familiar with <em>Algebraic Data Types</em>, it is mathematically demonstrable that these kinds of enum-based models require fewer test cases. Here&#39;s a brief explanation of how:</p>

<p>A struct is called a <em>Product Type</em>. This means that the total number of distinct values or variations of a struct type can be calculated by <em>multiplying</em> the possible values of its properties (the product of all its properties). So, for a struct like this:</p>
<div class="highlight"><pre><span></span><span class="kd">struct</span> <span class="nc">AuthenticationModel</span> <span class="p">{</span>
  <span class="kd">let</span> <span class="nv">isAuthenticated</span><span class="p">:</span> <span class="nb">Bool</span> <span class="c1">// &lt;-- Bool has 2 possible values</span>
  <span class="kd">let</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span><span class="p">?</span> <span class="c1">// &lt;-- String? has two possible values: .none or .some (not counting associated values)</span>
  <span class="kd">let</span> <span class="nv">error</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span> <span class="c1">// &lt;-- Error? has two possible values: .none or .some (not counting associated values)</span>
<span class="p">}</span>

<span class="c1">// Multiply the possible distinct values of each property and you get 2 x 2 x 2 = 8 *minimum* possible variations of AuthenticationModel (again, not counting the associated String and Error values themselves)</span>
</pre></div>
<p>With a <strong><em>minimum</em></strong> of 8 distinct combinations of properties, you would need to write a <strong><em>minimum</em></strong> of 8 unit tests to validate the proper combinations.</p>

<p>Now let&#39;s look at the enum version.  An enum is called a <em>Sum Type</em>. This means that the total number of distinct values of that type can be calculated by <em>adding</em> together its cases (the sum of all its cases).  So for the enum version:</p>
<div class="highlight"><pre><span></span><span class="kd">enum</span> <span class="nc">AuthenticationModel</span> <span class="p">{</span> 
  <span class="k">case</span> <span class="n">authenticated</span><span class="p">(</span><span class="n">Authenticated</span><span class="p">)</span> <span class="c1">// 1 case</span>
  <span class="k">case</span> <span class="n">notAuthenticated</span><span class="p">(</span><span class="n">NotAuthenticated</span><span class="p">)</span> <span class="c1">//  1 case</span>

  <span class="kd">struct</span> <span class="nc">Authenticated</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">authToken</span><span class="p">:</span> <span class="nb">String</span>
    <span class="kd">let</span> <span class="nv">logOut</span><span class="p">:</span> <span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
  <span class="p">}</span>

  <span class="kd">struct</span> <span class="nc">NotAuthenticated</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">error</span><span class="p">:</span> <span class="n">Error</span><span class="p">?</span>
    <span class="kd">let</span> <span class="nv">logInWithCredentials</span><span class="p">:</span> <span class="p">(</span><span class="n">Credentials</span><span class="p">)</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// Add the cases and you find that there are 1 + 1 = 2 *minimum* possible variations of AuthenticationModel. Because we have removed optionality from authToken, even if we count the 2 possible values for error in the NotAuthenticated associated value struct, we still have a *minimum* of only 1(.authenticated) + 1(.notAuthenticated) * 2 (possible values for .notAuthenticated: 1 with .some error and 1 with .none error) = 3 distinct cases to test.</span>
</pre></div>
<p>This is oversimplified and a little hand-wavy in the interest of simplicity and brevity,  but hopefully you can see the mathematical pattern at play which suggests that simply by removing possible combinations of different properties in a struct and replacing them with fewer properties in distinct enum cases we are in fact provably reducing the <em>minimum</em> number of test cases which should be written for our model!</p>

<p>But wait, there&#39;s more — a final important benefit of enum-based models that simply cannot be matched by protocol-defined interfaces...</p>

<hr>

<h2 id="self-documenting-api">Self-Documenting API</h2>

<hr>

<p>If you&#39;ve been coding for iOS for a few years, you know how painful certain APIs can be due to implicit, often unknown rules about what methods can be called at what time and in what order. Some classic examples:</p>

<ul>
<li><code>UIViewPropertyAnimator</code> is a perfect example of the unsafe APIs we&#39;ve been addressing. Its <code>state</code> property has three possible values (<code>.active</code>, <code>.inactive</code>, and <code>.stopped</code>) and depending on which is current, the different methods you call on the animator will either work correctly or crash the app. For example, you should not call <code>startAnimation()</code> if the state is <code>.stopped</code> and if you do the app will crash. Unfortunately, if you&#39;ve used this API before you know that the only way to fully discover all the implicit &quot;rules&quot; is through trial and error or trying to find good 3rd party blog posts about it.</li>
<li><code>UITableView</code> can be triggered into a variety of crashes if you call <code>insertRows()</code>, <code>deleteRows()</code>, etc. without first calling <code>beginUpdates()</code> and without finishing with <code>endUpdates()</code>.  But there is no self-documenting aspect to the code which suggests at all that <code>beginUpdates()</code> should be called first and that <code>endUpdates()</code> should be called at the end.</li>
</ul>

<p>Ultimately in both of the above examples (and many many more in both Apple and non-Apple APIs), what the developer is faced with is a long list of methods which will be suggested by autocomplete and can be called at any time. It&#39;s very difficult to understand which methods are <em>safe</em> or <em>appropriate</em> to call at a given time. Similarly, there are many properties which may be irrelevant or unpopulated in the the current context of an API, yet they are still all listed by autocompletion and accessible to call, which creates a higher amount of noise to signal and can cause confusion.</p>

<p>Enter once again model-defined interfaces and enum models!  </p>

<p>We&#39;ve already covered how this pattern increases safety and reduces the need for defensive coding and the number of required test cases. But as a last note, we will also examine how it takes self-documenting code to a whole new level and makes things much easier and clearer for developers.</p>

<p>Let&#39;s start with a simplified representation of the API for Apple&#39;s <code>UIViewPropertyAnimator</code>:</p>
<div class="highlight"><pre><span></span><span class="kd">enum</span> <span class="nc">AnimationState</span> <span class="p">{</span>
  <span class="k">case</span> <span class="n">inactive</span>
  <span class="k">case</span> <span class="n">active</span>
  <span class="k">case</span> <span class="n">stopped</span>
<span class="p">}</span>

<span class="kd">protocol</span> <span class="nc">UIViewAnimating</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nv">state</span><span class="p">:</span> <span class="n">AnimationState</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span>
  <span class="kd">var</span> <span class="nv">isInterruptible</span><span class="p">:</span> <span class="nb">Bool</span> <span class="p">{</span> <span class="kr">get</span> <span class="kr">set</span> <span class="p">}</span>
  <span class="kd">func</span> <span class="nf">startAnimation</span><span class="p">()</span>
  <span class="kd">func</span> <span class="nf">stopAnimation</span><span class="p">()</span>
<span class="p">}</span>
</pre></div>
<p>And here are some of the implicit rules:</p>

<table><thead>
<tr>
<th></th>
<th>.inactive</th>
<th>.active</th>
<th>.stopped</th>
</tr>
</thead><tbody>
<tr>
<td>startAnimation()</td>
<td>works</td>
<td>works if isRunning == false otherwise does nothing</td>
<td>does nothing</td>
</tr>
<tr>
<td>stopAnimation()</td>
<td>does nothing</td>
<td>works</td>
<td>CRASHES</td>
</tr>
<tr>
<td>isInterruptible</td>
<td>works</td>
<td>CRASHES if set</td>
<td>CRASHES if set</td>
</tr>
</tbody></table>

<p>Unfortunately, these rules have only spotty documentation and require research or trial-and-error to discover. And the code / API itself is not at all self-documenting in regards to these rules.</p>

<p>So as an experiment let&#39;s conceive of a refactor to this API to make it an enum model:</p>
<div class="highlight"><pre><span></span><span class="kd">enum</span> <span class="nc">UIViewPropertyAnimator</span> <span class="p">{</span>
  <span class="k">case</span> <span class="n">inactive</span><span class="p">(</span><span class="n">Inactive</span><span class="p">)</span>
  <span class="k">case</span> <span class="n">active</span><span class="p">(</span><span class="n">Active</span><span class="p">)</span>
  <span class="k">case</span> <span class="n">stopped</span><span class="p">(</span><span class="n">Stopped</span><span class="p">)</span>

  <span class="kd">struct</span> <span class="nc">Inactive</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">startAnimation</span><span class="p">:</span> <span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
    <span class="kd">var</span> <span class="nv">isInterruptible</span><span class="p">:</span> <span class="nb">Bool</span> <span class="c1">// Gettable and settable</span>
  <span class="p">}</span>

  <span class="kd">struct</span> <span class="nc">Active</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">isInterruptible</span><span class="p">:</span> <span class="nb">Bool</span> <span class="c1">// Gettable / read-only so never crashes</span>
    <span class="kd">let</span> <span class="nv">startAnimation</span><span class="p">:</span> <span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
    <span class="kd">let</span> <span class="nv">stopAnimation</span><span class="p">:</span> <span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">Void</span>
  <span class="p">}</span>

  <span class="kd">struct</span> <span class="nc">Stopped</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nv">isInterruptible</span><span class="p">:</span> <span class="nb">Bool</span> <span class="c1">// Gettable / read-only so never crashes</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>By converting this API into an enum with explicit states, we have managed to make most of these rules self-documenting (what is valid or safe to call in each state is made clear by the types themselves), and autocomplete will never suggest or show an invalid or unsafe property or method for the current state of the animator!</p>

<p>This makes it much easier and clearer for developers to understand and use. Comparing for example, an animator in the <code>.stopped</code> state, the protocol-defined version of the API would expose 2 properties (<code>state</code> and <code>isInterruptible</code>) and 2 methods in the list of members provided by autocomplete,  and the compiler would allow a developer to invoke any of them. However, one method would do nothing in this state, the other method will cause a crash, and 1 property would cause a crash if set!  Therefore 75% percent of the exposed API is non-functional or downright unsafe to use.</p>

<p>Looking at the enum model version of the same API, the <code>.stopped</code> case only exposes a single <code>isInterruptible</code> property in a read-only form which is safe. The unsafe methods and the ability to attempt to set the <code>isInterruptible</code> property don&#39;t even exist, will not show up in autocomplete and will not compile if called. So the developer clearly sees the <em>only</em> available information in this state, and the code self-documents the unsafe or non-functional members by removing them entirely in this context!</p>

<hr>

<h2 id="implementation-details">Implementation Details</h2>

<hr>

<p>Some readers may have wondered &quot;if all of these model behaviors return <code>Void</code>, how are changes to the model received?&quot; This is a key implementation detail for the model-defined interface approach: it is ideally suited specifically to <strong>reactive</strong> code with <strong>unidirectional data flow</strong>.  In practice, consumers of the API would depend on a publisher of instances of the model, for example:</p>
<div class="highlight"><pre><span></span><span class="kd">struct</span> <span class="nc">AuthenticationView</span><span class="p">:</span> <span class="n">View</span> <span class="p">{</span>
  <span class="p">@</span><span class="n">State</span> <span class="kd">var</span> <span class="nv">model</span><span class="p">:</span> <span class="n">AuthenticationModel</span>
  <span class="kd">let</span> <span class="nv">modelPublisher</span><span class="p">:</span> <span class="n">AnyPublisher</span><span class="p">&lt;</span><span class="n">AuthenticationModel</span><span class="p">,</span> <span class="n">Never</span><span class="p">&gt;</span>
  <span class="kd">var</span> <span class="nv">body</span><span class="p">:</span> <span class="n">some</span> <span class="n">View</span> <span class="p">{</span>
    <span class="n">VStack</span> <span class="p">{</span>
      <span class="k">switch</span> <span class="n">model</span> <span class="p">{</span>
        <span class="k">case</span> <span class="p">.</span><span class="n">authenticated</span><span class="p">(</span><span class="kd">let</span> <span class="nv">authenticated</span><span class="p">):</span>
          <span class="n">Text</span><span class="p">(</span><span class="s">&quot;Authentication token: </span><span class="si">\(</span><span class="n">model</span><span class="p">.</span><span class="n">authToken</span><span class="si">)</span><span class="s">&quot;</span><span class="p">)</span>
          <span class="n">Button</span><span class="p">(</span><span class="s">&quot;Log Out&quot;</span><span class="p">,</span> <span class="n">action</span><span class="p">:</span> <span class="p">{</span> <span class="n">model</span><span class="p">.</span><span class="n">logOut</span><span class="p">()</span> <span class="p">})</span>
        <span class="k">case</span> <span class="p">.</span><span class="n">notAuthenticated</span><span class="p">(</span><span class="kd">let</span> <span class="nv">notAuthenticated</span><span class="p">):</span>
          <span class="k">if</span> <span class="kd">let</span> <span class="nv">error</span> <span class="p">=</span> <span class="n">notAuthenticated</span><span class="p">.</span><span class="n">error</span> <span class="p">{</span>
            <span class="n">Text</span><span class="p">(</span><span class="s">&quot;Error: </span><span class="si">\(</span><span class="n">error</span><span class="si">)</span><span class="s">&quot;</span><span class="p">)</span>
          <span class="p">}</span>
          <span class="n">Button</span><span class="p">(</span><span class="s">&quot;Log In&quot;</span><span class="p">,</span> <span class="n">action</span><span class="p">:</span> <span class="p">{</span> <span class="n">notAuthenticated</span><span class="p">.</span><span class="n">logInWithCredentials</span><span class="p">(.</span><span class="n">valid</span><span class="p">)</span> <span class="p">})</span>
      <span class="p">}</span>
    <span class="p">}.</span><span class="n">onReceive</span><span class="p">(</span><span class="n">modelPublisher</span><span class="p">)</span> <span class="p">{</span> <span class="n">model</span> <span class="p">=</span> <span class="nv">$0</span> <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>So it is up to some external code to publish a stream of the <code>AuthenticationModel</code> which can be consumed by the view.  That same external code would populate the different behavior closures within each instance of <code>AuthenticationModel</code> (like the <code>logOut</code> closure). Those closures would perform some logic and then result in a new value of <code>AuthenticationModel</code> being published to the stream.</p>

<hr>

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

<hr>

<p>So in summary, model-defined interfaces are a reactive, unidirectional pattern for building safe, self-documenting and less redundant APIs. And they reduce the number of test cases and amount of defensive coding required as well! When compared to a tradition protocol-defined interface approach, they provide more benefits and less drawbacks across the board!</p>

<table><thead>
<tr>
<th></th>
<th></th>
<th>Protocol-Defined Interfaces</th>
<th></th>
<th>Model-Defined Interfaces</th>
</tr>
</thead><tbody>
<tr>
<td>Boilerplate and redundant code</td>
<td>⚠️</td>
<td>Moderate: requires conforming multiple types to the same protocol and declaring the same protocol properties and methods in each conforming type</td>
<td>✅</td>
<td>No boilerplate or redundant code required</td>
</tr>
<tr>
<td>Safety</td>
<td>⛔️</td>
<td>No safety guarantees — all methods and properties are visible and accessible even in unsafe or invalid contexts</td>
<td>✅</td>
<td>Compiler-enforced safety by limiting properties and methods to only those which are valid and safe for the current state</td>
</tr>
<tr>
<td>Test cases and defensive code</td>
<td>⛔️</td>
<td>Require test cases to ensure all possible combinations of property values are valid, and that methods called in the wrong context fail gracefully. Similarly, requires defensive code to avoid executing methods in the wrong context</td>
<td>✅</td>
<td>Greatly reduce the required number of test cases and the need for defensive coding</td>
</tr>
<tr>
<td>Self-documenting code</td>
<td>⚠️</td>
<td>Code can only be self-documenting for API that isn&#39;t stateful and has no context which can affect the availability or behavior of properties or methods</td>
<td>✅</td>
<td>Fully self-documenting for all kinds of API, enabling even contextual or stateful API to be clearly understood through autocomplete and the existence or omission of properties and methods / closures</td>
</tr>
</tbody></table>

<h3 id="further-exploration">Further Exploration</h3>

<p>If you&#39;re interested in seeing concrete example applications using model-defined interfaces and an architecture built from the ground up around this paradigm, <a href="https://github.com/daniel-hall/SourceArchitecture">check out Source Architecture on Github!</a>  And as always feel free to contact me with your questions or comments (or leave them below)</p>
]]></content:encoded>
      </item>
      <item>
        <guid>http://danielhall.io/creating-a-sustainable-software-cycle#53461</guid>
          <pubDate>Sun, 10 Apr 2022 20:54:00 -0600</pubDate>
        <link>http://danielhall.io/creating-a-sustainable-software-cycle</link>
        <title>Creating a Sustainable Software Cycle</title>
        <description>Breaking the perpetual deadlock of legacy code, lack of testing, and missing documentation</description>
        <content:encoded><![CDATA[<p><img alt="Silvrback blog image" class="sb_float_center" src="https://silvrback.s3.amazonaws.com/uploads/bdfe014d-cb39-4ca5-8eaa-8ca121f8132d/pexels-tom-fisk-5441306.jpg" /></p>

<p>Having been an iOS developer at quite a few tech companies, from small to large, I’ve found that they all mostly share the same painful reality of software development:</p>

<ul>
<li>Lots of fragile legacy code that is risky to refactor or update because it is untested</li>
<li>Tests can’t be written for legacy code because what it even does (and why) is unknown. Plus, since it doesn’t have tests in the first place it is usually not written to easily allow for testability at a later date.</li>
<li>Tests (usually unit tests) written for new / recent code rarely or never catch actual bugs. Emphasis is placed on writing these tests, but the return on investment is questionable since even with thousands of tests run continuously, roughly the same volume of bugs occur in production as existed before the thousands of tests.</li>
<li>When refactors or changes to recent code are needed, the unit tests usually end up having to be modified, rewritten, or simply turned off, since they are usually too tightly coupled to a specific implementation. </li>
<li>Eventually this recent code, with its disabled, short-circuited or reduced-coverage tests turns into legacy untested code that is fragile and risky to refactor, starting the cycle again.</li>
</ul>

<p>Typically, software teams to solve this vicious cycle with the “enforcement of testing” approach, which looks something like: </p>

<p>a. All PRs must have tests with them , and / or<br>
b. Code coverage percentage must not be lowered with any new PRs. </p>

<p>This seems reasonable on the surface, except that this sort of mandate doesn’t really ensure good or meaningful testing. It’s easy to write a test that technically results in “coverage” but will never catch any bugs. This ends up just perpetuating the cycle above and does nothing to address legacy code either.</p>

<h2 id="the-underlying-problem">The underlying problem</h2>

<p>The reason why this cycle is so hard to break is because the <em>apparent</em> problem (lack of tests) is not the <em>real</em> problem, but is merely a symptom of the real problem. Additionally, merely increasing the <em>quantity</em> of tests does not result in a well-tested codebase.</p>

<p>So what is the real underlying problem? It’s <strong>a lack of clear, documented, testable requirements for everything in the codebase</strong>. </p>

<p>Keep in mind that <em>programming is a one-way hashing algorithm that turns requirements into source code</em>. It is not possible to unhash source code back into the requirements that resulted in that code. Comments can be very helpful in illuminating motivations, but they are informal and prone to rot. Therefore, the process of programming is a <strong><em>lossy</em></strong> process that loses intent and context along the way, unless the intent and context (i.e. requirements) are explicitly persisted and maintained somehow.</p>

<p>Typically how this underlying problem manifests is when some individual developer is expected to:</p>

<ol>
<li>Receive some vague, incomplete description of what to implement </li>
<li>Create a (hopefully) working implementation (and if it doesn’t work, hopefully it will be caught before it is released by QA or other internal testing) </li>
<li>Then invent their own tests to “provide code coverage” for the code they wrote. </li>
</ol>

<p>Six months later, <strong>no one</strong> knows exactly how the code that developer wrote works or why it was written that way (including the developer themself!) and the best you could do is maybe try to search through JIRA looking for the ticket that described what the original request was (which doesn&#39;t include all the conversations, etc. that happened during development). </p>

<p>Or, maybe your team is really good and wrote out some sort of technical design doc in Google Docs or Confluence in advance. That&#39;s better, but not only is it decoupled and separate from the code itself (so may not be easy to find), but it starts becoming obsolete as soon as development starts due to workarounds, bug fixes, edge cases and more being discovered and implemented during development. Not to mention the iterative process of change that comes immediately afterwards which causes the code to change without the documentation itself being updated.</p>

<p>So to solve this whole mess, the missing ingredient of explicit, testable requirements needs to be introduced at every stage of development (grooming, iteration, bug fixes). And those requirements must be constantly in sync with the actual reality of the code, not maintained in a separate universe somewhere.</p>

<h2 id="what-is-a-good-requirement">What is a good requirement?</h2>

<p>First, let me be clear that I’m not advocating for long rambling requirements documents that are worked on for weeks before any code can be written. While that has many advantages over <em>no</em> requirements, it&#39;s a slow process that is just as prone to rapid obsolescence. </p>

<p>A good requirement is a <strong><em>conceptual rule or intent coupled with specific examples to demonstrate how it is expected to behave</em></strong>. The number of examples included for a rule  should be <strong><em>as many as needed to capture every unique behavior of the rule</em></strong>. Examples are what makes a requirement testable. Requirements without examples are not testable.</p>

<p>Example of a bad requirement:</p>

<blockquote>
<p>Debit card users shouldn&#39;t be able to overdraft</p>
</blockquote>

<p>👆 This requirement is missing context and has no clarifying or testable examples</p>

<p>So let’s try to make it better:</p>

<blockquote>
<p>Debit card charges should be denied if the amount of the charge is greater than the user’s available balance</p>
</blockquote>

<p>👆 Much better context! But not yet testable as there are no examples, and we could ask many questions about edge cases that are not answered by this single statement.</p>

<blockquote>
<p>Rule: Debit card charges should be denied if the amount of the charge is greater than the user’s available balance<br>
        - Example: Given the user has a $50 available balance, when a $51 charge is requested then the transaction should be declined.<br>
        - Example: Given the user has a $50 available balance, when a $49 charge is requested then the transaction should be approved</p>
</blockquote>

<p>👆 This is the first implementable, testable requirement!  It has the rule and specific examples that can be easily tested. To illustrate, look how straightforward it would be to write tests for this requirement:  </p>
<div class="highlight"><pre><span></span><span class="kd">func</span> <span class="nf">testOverdraftDeclined</span><span class="p">()</span> <span class="p">{</span>
   <span class="kd">let</span> <span class="nv">mockAccount</span> <span class="p">=</span> <span class="n">MockAccount</span><span class="p">()</span>
   <span class="n">mockAccount</span><span class="p">.</span><span class="n">balance</span> <span class="p">=</span> <span class="mf">50.00</span>
   <span class="kd">let</span> <span class="nv">testTransaction</span> <span class="p">=</span> <span class="n">Transaction</span><span class="p">(</span><span class="n">account</span><span class="p">:</span> <span class="n">mockAccount</span><span class="p">)</span>
   <span class="kd">let</span> <span class="nv">result</span> <span class="p">=</span> <span class="n">testTransaction</span><span class="p">.</span><span class="n">charge</span><span class="p">(</span><span class="mf">51.00</span><span class="p">)</span>
   <span class="n">XCTAssertEqual</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="p">.</span><span class="n">declined</span><span class="p">)</span>
<span class="p">}</span>
</pre></div>
<p>Note that at this point, this probably isn’t a truly complete requirement, but it’s defined enough to start coding, testing and moving ahead incrementally.</p>

<p>During development or perhaps QA, someone might notice a scenario that was not accounted for in the original requirement: if the user’s account has a <em>pending</em> charge, it is possible for the a new charge to use money that should be been reserved for the pending charge, resulting in an eventual overdraft.</p>

<p>Therefore, the requirement gets updated to:</p>

<blockquote>
<p>Rule: Debit card charges should be denied if the amount of the charge is greater than the user’s available balance <strong>minus any pending transactions</strong><br>
    - Example: Given the user has a $50 available balance, when a $51 charge is requested then the transaction should be declined.<br>
    - Example: Given the user has a $50 available balance, when a $49 charge is requested then the transaction should be approved<br>
    - <strong>Example: Given the user the user has a $50 available balance and there is a $25 pending charge on the user’s account, when a $49 charge is requested then the transaction should be declined</strong></p>
</blockquote>

<p>Notice how requirements get more specific and comprehensive over time, iteratively. Also note that a developer, product manager, or QA analyst coming back to this code years later can see exactly how the code is supposed to work.</p>

<h2 id="keeping-requirements-in-sync-with-code">Keeping requirements in sync with code</h2>

<p>Now that we’ve looked at what good implementable requirements look like the next questions are:</p>

<ul>
<li>Where do we keep them?</li>
<li>How do we test them?</li>
<li>How do we ensure they don’t grow stale and out of sync with the actual state of code?</li>
</ul>

<p>There can be different answers to these questions, but I strongly advocate for one answer that addresses all three:  Requirements should be kept in inside the repo alongside the code and <em>automatically</em> tested on every commit using a test framework like Cucumber or (shameless plug) my own <a href="https://github.com/daniel-hall/TestKit">TestKit</a>.</p>

<p>Let’s break this down a bit: the requirements given above as examples are all written in the “Given, When , Then” format for describing a behavior. This loose structure for expressing requirements has been formalized into a standard called <a href="https://cucumber.io/docs/gherkin/reference/">Gherkin</a>. Gherkin is just a set of keywords and conventions for writing these kinds of example-based requirements. Because of the “standardized” nature of Gherkin, it can be parsed and fed into testing frameworks, which can then attempt to validate every statement in the requirements</p>

<p>The most common framework for testing Gherkin requirements is called Cucumber, but it isn’t particularly well maintained for iOS. However, Gherkin <em>is</em> a defined standard and so other frameworks can be written and maintained to test Gherkin requirements, such as my previously mentioned <a href="https://github.com/daniel-hall/TestKit">TestKit</a> and others. These frameworks all essentially work the same way:</p>

<ul>
<li><p>They provide a way for test code to register certain blocks of functionality in response to requirements that match specified RegEx patterns. For example this code registers test behaviors that will run in response to the requirement phrase &quot;Given the user has a $50 available balance&quot;:  </p>
<div class="highlight"><pre><span></span><span class="k">given</span>(“<span class="n">the</span> <span class="n">user</span> <span class="k">has</span> <span class="n">a</span> <span class="nv">$50</span> <span class="n">available</span> <span class="n">balance</span>”){
      <span class="n">testAccount</span> = <span class="n">MockAccount</span>()
      <span class="n">testAccount</span>.<span class="n">balance</span> = <span class="mf">50.00</span>
}
</pre></div>
<p>This is how developers hook into requirements and &quot;prove&quot; each line in their test code. Because it uses RegEx, the registered test functionality can also be dynamic, e.g.  </p>
<div class="highlight"><pre><span></span> <span class="k">given</span>(“<span class="n">the</span> <span class="n">user</span> <span class="k">has</span> <span class="n">a</span> $(<span class="s">&lt;balance&gt;</span>\<span class="n">d</span>?) <span class="n">available</span> <span class="n">balance</span>”) {  
    <span class="n">guard</span> <span class="k">let</span> <span class="n">balance</span> =<span class="nv">$0</span>[“<span class="n">balance</span>”].<span class="n">floatValue</span> <span class="k">else</span> { 
        <span class="n">XCTFail</span>(“<span class="n">Invalid</span> <span class="n">balance</span> <span class="n">in</span> <span class="n">requirement</span>”)
    }
    <span class="n">testAccount</span> = <span class="n">MockAccount</span>()
    <span class="n">testAccount</span>.<span class="n">balance</span> = <span class="n">balance</span>  
}
</pre></div>
<p>This dynamic version will read <em>any</em> specified amount for the available balance out of a requirement and configure the mock account appropriately.</p></li>
<li><p>They parse all requirements in a given file or folder</p></li>
<li><p>If a requirement doesn’t have any test functionality registered to handle it, the test fails</p></li>
<li><p>Each parsed line of every requirement has its associated test functionality invoked — in order — allowing tests to validate the requirements are true</p></li>
</ul>

<p>There are all sorts of strategies and conventions to make this process as effective as possible (which I’ll be talking about more in future posts), but just looking at this basic setup it gives us the following benefits:</p>

<ul>
<li>Simply <em>adding</em> or <em>changing</em> a requirement in the project without having associated test code to prove it will fail the tests. This ensures that <em>all requirements must be validated and tested at all times</em></li>
<li>The test suite is ultimately based on high-level requirements, not implementation details, so tests are always able to validate successful refactors. Note that there <em>may</em> be implementation details in the registered test functions (like how to set a balance on a mock account), but these details are updated separately from the actual requirements, which the suite validates and which don&#39;t change due to refactoring.</li>
<li>Any changes to the code which break a requirement will fail the tests. Any changes to the requirements which are not reflected in the code will cause the tests to fail as well.</li>
</ul>

<p>In short, this approach brings us to the ideal state of requirements which are never out of sync with the code, and code which is never undocumented or diverged from requirements!</p>

<h2 id="bringing-it-all-together">Bringing it all together</h2>

<p>By using this requirements-driven approach to software development, we can finally achieve the sustainable process that has been so elusive. Once a codebase has been set up with a testing framework like Cucumber or TestKit (and has usable test setups for both UI tests and API (or “unit”) tests) it only requires one simple rule in order to keep the entire process working: <em>“Requirements are always written before coding begins, and the first step to coding is updating the requirement”</em>. This single rule ensures that testing occurs, documentation exists, developers are implementing the right thing, and refactors in the future will be safe and validated.</p>

<p>Note that bugs and bug fixes must follow this pattern as well. When tested requirements exist, a bug becomes simply a requirement example that wasn’t captured earlier. A bug is fixed by: <br>
1. Adding the example to the requirements, including what <em>should</em> be the outcome of that example <br>
2. Writing or fixing the code to validate that new example (while also continuing to meet all previously captured requirements and examples). </p>

<p>And thus the sustainable software development cycle looks like this:</p>

<ul>
<li>Product or QA (in the case of bugs) identify rules and examples that the product should follow (backlog)</li>
<li>Product + Developers + QA ask questions and surface specific examples to identify how the rule should be followed for any possible scenario that is thought of (grooming). These examples are written as Gherkin requirements.</li>
<li>Developers are assigned specific requirements to implement. The requirements are already captured in the project, the Jira ticket holds no requirements itself, just notes which previously decided requirements will be implemented. The requirements to be implemented ARE the tests, so the developer works on the implementation until all the requirements tests pass, which is when the ticket is done. Note that PRs can’t pass CI or merge until the developer has hooked up test functionality to prove the requirements.</li>
<li>The cycle starts again and runs iteratively: based on user feedback or defects, product and / or QA provides new rules and examples which become requirements in the repo, and so on.</li>
<li>When it comes time to complete refactor a portion of the application (say, from UIKit to SwiftUI), this can be done confidently knowing that all the same requirements that were used to defined <em>all</em> the existing code must also be validated against the new code as well.</li>
</ul>

<h2 id="further-discussion">Further discussion</h2>

<p>While this basic arrangement really does provide a truly sustainable software development cycle, there are unsurprisingly devils in the details. I plan to address these in subsequent posts, but just to give proper acknowledgement to some of the key challenges:</p>

<ul>
<li>It requires a disciplined grooming process to translate all work into testable, example-based requirements. Ideally, this process would include product, QA and software engineers together in a discussion, asking questions and capturing rules and examples in Gherkin format (usually the best Gherkin-writer — often someone in QA or a developer — will translate the discussion into the actual Gherkin that everyone else give a thumbs up to). Similarly, it takes work with QA to translate bug reports into specific missing rules or examples.</li>
<li>Writing good Gherkin to be plainly understandable and not overly implementation-focused takes practice. Additionally, Gherkin has a few conveniences and features that should be learned as well in order to facilitate the process.  For example, tags can be used to limit requirements to certain platforms or OS versions, or to exclude new requirements from being tested until a ticket is in flight to implement those requirements, etc.</li>
<li>Requirements are either focused on <em>user experience</em> (what the user sees) or <em>API behaviors</em> (what responses calling code will receive following method calls with certain parameter values, etc.). Testing both kinds of requirements means that the project needs to have basic testability in place for both code (i.e. mocks for unit tests, etc.) and UI (the ability to launch the app with various mock preconditions in place for when the UI is interacted with by test code). </li>
</ul>

<p>I hope that the content in this article is nonetheless enough to get you started on the path to a well-tested, well-understood and sustainable project that can be maintained confidently without regressions!</p>
]]></content:encoded>
      </item>
      <item>
        <guid>http://danielhall.io/a-useful-and-practical-approach-to-testing#49088</guid>
          <pubDate>Thu, 27 Feb 2020 20:30:00 -0700</pubDate>
        <link>http://danielhall.io/a-useful-and-practical-approach-to-testing</link>
        <title>A Useful and Practical Approach to Testing</title>
        <description></description>
        <content:encoded><![CDATA[<p><a href="https://danielhall.io/what-is-testing-for-anyway">Having established what tests can actually be good for</a>, outlined <a href="https://danielhall.io/the-two-kinds-of-tests">the only two types of test that matter</a> and their value, and <a href="https://danielhall.io/what-about-unit-tests">having attempted to make the case against a narrow fixation on “unit tests”</a>, where does that leave us?</p>

<p>Well, it leaves us free to think about how we can write good tests that are useful and practical!  And the formula for that is very simple:</p>

<ul>
<li><p>Every feature, bug fix, coding task, etc. should have one or more clearly stated requirements.  Not <em>how</em> this code is to be written, but <em>what</em> does this code have to <em>do</em>?  Often, the requirement can be described from the perspective of the human who is using the app, e.g. “Tapping on the star should add this items to my list of favorites”. Requirements can also be described purely from a API perspective, e.g. “When there are already 100 favorites, adding an additional item to the favorites list should result in an error and no change to the existing favorites”.  </p></li>
<li><p>Each API requirement should be validated by an API test  </p></li>
<li><p>Each UI / user requirement should be validated by a UI test  </p></li>
<li><p>Every test should test the required <em>behavior</em>, not a specific implementation. If the implementation changes (whether the code underlying the API, or the layout or styling of elements in a UI), the tests should not need to change.  In fact, the tests exist largely to validate that a change to the implementation still meets the same required behavior.  So tests must only be concerned with the behavior, and not an implementation.    </p>

<p>For UI tests, this means validating and interacting with elements by identifier rather than looking them up by a specific screen or expecting a specific hierarchy.  For API tests, this means that writing code and tests that address protocols / interfaces and abstractions, which can be explicitly passed mockable inputs, and validate explicit outputs (via mock expectations or return types) rather than digging into properties and internal state.  </p></li>
</ul>

<p>And that’s the entire formula.  It’s kind of neat that the entire approach to testing (at a high level) can be boiled down to just these few points.  But you’ll notice that every test you write using these simple principles will have value and align with the project objective.  No time is spent writing tests that don’t validate an explicit requirement.  Any deviation from required behavior (whether through refactor or the addition of new code) will cause tests to fail, easily proving their value. And as you gradually capture more and more and more of what your application does and needs to do as explicit requirements (more on that in an upcoming article), your test suite is giving you direct confidence that your code is meeting those requirements on every run.</p>

<p>Of course there is a lot more in the details (which we will continue to dig into with additional articles), but those details largely boil down to how to write good requirements, how to make tests more abstract (test the behavior, not the implementation), and perhaps some specific techniques for providing inputs and validating outputs.  </p>

<p>There is a ton of room for creativity and mastery in these specific areas, and lots of work to do in capturing ALL the requirements of your app to test. Hopefully this starting point of a useful and practical approach to testing helps you focus on the parts that matter, and gets you the most bang for your testing buck!</p>

<hr>

<p>Next up: We dive into details of how requirements and testing are part of sustainable software development <a href="https://danielhall.io/creating-a-sustainable-software-cycle">“Creating a Sustainable ”</a></p>

<hr>
]]></content:encoded>
      </item>
  </channel>
</rss>