<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Philosophy on Cameron Little's Website</title><link>https://camlittle.com/tags/philosophy/</link><description>Recent philosophy on Cameron Little's Website</description><image><title>Philosophy on Cameron Little's Website</title><url>https://camlittle.com/profile.jpg?s=144</url><link>https://camlittle.com/tags/philosophy/</link><width>144</width></image><language>en-us</language><managingEditor>cameron@camlittle.com (Cameron Little)</managingEditor><webMaster>cameron@camlittle.com (Cameron Little)</webMaster><lastBuildDate>Sat, 24 Jul 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://camlittle.com/tags/philosophy/index.xml" rel="self" type="application/rss+xml"/><item><title>Don't merge that TODO</title><link>https://camlittle.com/posts/2021-07-24-dont-merge-todos/</link><pubDate>Sat, 24 Jul 2021 00:00:00 +0000</pubDate><guid isPermaLink="true">https://camlittle.com/posts/2021-07-24-dont-merge-todos/</guid><enclosure url="https://camlittle.com/posts/2021-07-24-dont-merge-todos/thumbnail.png" length="2279" type="image/png"/><description>&lt;p>One of my standard code review comments is, &amp;ldquo;Why is this a TODO&amp;rdquo;? I believe you should always avoid TODO comments in your code. They&amp;rsquo;re a familiar pattern, but they defer responsibility and make problems harder to solve.&lt;/p>
&lt;p>In most cases, the TODO should be filed in your team&amp;rsquo;s issue tracker immediately and cross-linked with the pull request. Some people have processes that track issues using TODOs, but I don&amp;rsquo;t believe source code works well for issue tracking. Source code represents the current state of your product. Reviewing historical context, though possible with version control, is not the primary interface. Issue tracking systems are built for prioritization, tracking context, linking related issues, and assigning responsibility.&lt;/p></description><content:encoded><![CDATA[
  
<p>One of my standard code review comments is, &ldquo;Why is this a TODO&rdquo;? I believe you should always avoid TODO comments in your code. They&rsquo;re a familiar pattern, but they defer responsibility and make problems harder to solve.</p>
<p>In most cases, the TODO should be filed in your team&rsquo;s issue tracker immediately and cross-linked with the pull request. Some people have processes that track issues using TODOs, but I don&rsquo;t believe source code works well for issue tracking. Source code represents the current state of your product. Reviewing historical context, though possible with version control, is not the primary interface. Issue tracking systems are built for prioritization, tracking context, linking related issues, and assigning responsibility.</p>
<p>TODOs are usually used to defer technical debt. Moving them to your issue tracker&rsquo;s backlog allows prioritization against feature work by putting them in the same playing field and can be used as a metric to understand the depth of technical debt.</p>
<p>TODOs often describe an expected future change. It&rsquo;s tough to predict the future, so the TODO might not make sense when the next person reads them. I still encourage using comments to describe the problem and the reasons for not addressing it, but not to prescribe action. In the future, you&rsquo;ll have much better context when deciding how to fix the issue, or you might be able to just delete it.</p>
<p>Even though I don&rsquo;t like seeing TODOs in a codebase, I often use them in my feature branches and scan through the diff once I&rsquo;ve opened my draft PR to decide if it&rsquo;s ready for review. They&rsquo;re lighter weight than an issue tracker and can act as a checklist for a single task. Generally, though, they&rsquo;re an indicator of poor quality and have more responsible alternatives.</p>


  
  ]]></content:encoded></item><item><title>Why this slack channel shouldn't be private</title><link>https://camlittle.com/posts/slack-private-channels/</link><pubDate>Fri, 06 Nov 2020 18:56:00 +0200</pubDate><guid isPermaLink="true">https://camlittle.com/posts/slack-private-channels/</guid><enclosure url="https://camlittle.com/posts/slack-private-channels/thumbnail.png" length="9591" type="image/png"/><description>&lt;p>Here&amp;rsquo;s why you shouldn&amp;rsquo;t use a private Slack channel:&lt;/p>
&lt;ol>
&lt;li>Messages are not &lt;a href="https://slack.com/intl/en-pl/help/articles/202528808-Search-in-Slack">searchable&lt;/a> once you leave&lt;/li>
&lt;li>Messages are not &lt;a href="https://slack.com/intl/en-pl/help/articles/203274767-Share-messages-in-Slack">sharable&lt;/a>&lt;/li>
&lt;li>People can&amp;rsquo;t easily jump in and out&lt;/li>
&lt;li>You can&amp;rsquo;t notify someone when you &lt;a href="https://slack.com/intl/en-pl/help/articles/205240127-Use-mentions-in-Slack">mention them&lt;/a>&lt;/li>
&lt;li>Workspace apps and bots aren&amp;rsquo;t present&lt;/li>
&lt;li>They cultivate an &lt;a href="https://www.forbes.com/sites/duenablomstrom1/2019/02/06/why-a-culture-of-us-vs-them-is-deadly/">&amp;ldquo;Us vs. them&amp;rdquo; culture&lt;/a>&lt;/li>
&lt;li>They foster unconscious biases by making it easy to exclude people&lt;/li>
&lt;li>You can&amp;rsquo;t change your mind and make a private channel public&lt;/li>
&lt;/ol>
&lt;p>While there are uses for private channels, they hinder communication and transparency. Please make public channels your default.&lt;/p></description><content:encoded><![CDATA[
  
<p>Here&rsquo;s why you shouldn&rsquo;t use a private Slack channel:</p>
<ol>
<li>Messages are not <a href="https://slack.com/intl/en-pl/help/articles/202528808-Search-in-Slack">searchable</a> once you leave</li>
<li>Messages are not <a href="https://slack.com/intl/en-pl/help/articles/203274767-Share-messages-in-Slack">sharable</a></li>
<li>People can&rsquo;t easily jump in and out</li>
<li>You can&rsquo;t notify someone when you <a href="https://slack.com/intl/en-pl/help/articles/205240127-Use-mentions-in-Slack">mention them</a></li>
<li>Workspace apps and bots aren&rsquo;t present</li>
<li>They cultivate an <a href="https://www.forbes.com/sites/duenablomstrom1/2019/02/06/why-a-culture-of-us-vs-them-is-deadly/">&ldquo;Us vs. them&rdquo; culture</a></li>
<li>They foster unconscious biases by making it easy to exclude people</li>
<li>You can&rsquo;t change your mind and make a private channel public</li>
</ol>
<p>While there are uses for private channels, they hinder communication and transparency. Please make public channels your default.</p>


  
  ]]></content:encoded></item><item><title>Coding is the easy part</title><link>https://camlittle.com/posts/2020-05-04-coding-is-the-easy-part/</link><pubDate>Mon, 04 May 2020 19:57:07 +0200</pubDate><guid isPermaLink="true">https://camlittle.com/posts/2020-05-04-coding-is-the-easy-part/</guid><enclosure url="https://camlittle.com/posts/2020-05-04-coding-is-the-easy-part/thumbnail.png" length="77515" type="image/png"/><description>&lt;p>Coding is the easy part about writing software.&lt;/p>
&lt;p>The IDE, the language, and the execution of the code itself all support and guide me as I write code. Especially when executing on a pre-designed plan or refactoring, I can rely on the compiler to let me know when I&amp;rsquo;ve made a mistake and I can look at the UI to see if I&amp;rsquo;ve done it right. Some tasks can even feel refreshing because they don&amp;rsquo;t require hard thinking while seeing a lot of output.&lt;/p></description><content:encoded><![CDATA[
  
<p>Coding is the easy part about writing software.</p>
<p>The IDE, the language, and the execution of the code itself all support and guide me as I write code. Especially when executing on a pre-designed plan or refactoring, I can rely on the compiler to let me know when I&rsquo;ve made a mistake and I can look at the UI to see if I&rsquo;ve done it right. Some tasks can even feel refreshing because they don&rsquo;t require hard thinking while seeing a lot of output.</p>
<p>Pure technical design is far harder. Without supporting tools, a higher percent of the cost comes from my brain. I can&rsquo;t lean on a program to tell me I&rsquo;m doing something wrong or tell me what to think about next.</p>
<p>To help, I try to prototype in parallel. Whatever code I produce I leave out of review to avoid sunk-cost bias and avoid <a href="https://www.quora.com/What-is-the-meaning-of-the-phrase-you-cant-see-the-forest-for-the-trees">&ldquo;can&rsquo;t see the forest for the trees&rdquo; effect</a>.</p>


  
  ]]></content:encoded></item><item><title>When should you add abstraction?</title><link>https://camlittle.com/posts/when-to-add-abstractions/</link><pubDate>Thu, 23 Apr 2020 17:44:00 +0200</pubDate><guid isPermaLink="true">https://camlittle.com/posts/when-to-add-abstractions/</guid><enclosure url="https://camlittle.com/posts/when-to-add-abstractions/thumbnail.jpeg" length="574139" type="image/jpeg"/><description>&lt;p>I&amp;rsquo;ve made the mistake of adding layers of abstraction too early several times
over my career as a software developer. It starts out like this: I&amp;rsquo;ve got a
really smart idea that will save me a bunch of time in the future. I&amp;rsquo;ll be able
to create a generic layer that I can build other features beneath without
needing to change consumer behavior.&lt;/p>
&lt;p>The issue is that I can&amp;rsquo;t see the future. It&amp;rsquo;s close to impossible to
understand the details of the future use cases I&amp;rsquo;m building for, and more often
then not I&amp;rsquo;m going to get it not quite right. Once that happens, the work I put
in building my abstraction layer is far less valuable and it often gets in the
way, making my job harder.&lt;/p></description><content:encoded><![CDATA[
  
<p>I&rsquo;ve made the mistake of adding layers of abstraction too early several times
over my career as a software developer. It starts out like this: I&rsquo;ve got a
really smart idea that will save me a bunch of time in the future. I&rsquo;ll be able
to create a generic layer that I can build other features beneath without
needing to change consumer behavior.</p>
<p>The issue is that I can&rsquo;t see the future. It&rsquo;s close to impossible to
understand the details of the future use cases I&rsquo;m building for, and more often
then not I&rsquo;m going to get it not quite right. Once that happens, the work I put
in building my abstraction layer is far less valuable and it often gets in the
way, making my job harder.</p>
<p>Working in a fast-growing company also means that a lot of the time the future
use case I&rsquo;m building for just never happens. We decide to go another
direction, or pause on that project, or it just doesn&rsquo;t get prioritized. Two
years later, the system has evolved to the point where what I built just
doesn&rsquo;t make sense.</p>
<h2 id="truth-is-relative"><a class="heading-link" href="#truth-is-relative"></a>Truth is relative</h2>
<p>Over time, my understanding of systems will always change, due to the complex
and changing environment I work in. Be it because of the tools we use, the
people we work with, or the size of the organization, decisions are never
binary or always correct. Choosing to use a statically typed language might be
more important if the scale of the project is larger, or if a coworker hasn&rsquo;t
developed the muscles to think dynamically. Building a massively scalable
microservice architecture might mean you can&rsquo;t deliver an MVP in time to get
the funding needed to start growing your start-up. Implementing a policy to
never force-upgrade an app version doesn&rsquo;t work once Brexit happens.</p>
<h2 id="build-defensively"><a class="heading-link" href="#build-defensively"></a>Build defensively</h2>
<p>What you can do is build defensively. In essence, this means building with the
understanding that it will be wrong in the future. Encapsulation helps a lot with
this, as it enables you to extract or split apart functionality with less pain.
Another simple defensive technique is to write less code and save the up-front
and maintenance cost.</p>
<h2 id="my-rule-of-thumb"><a class="heading-link" href="#my-rule-of-thumb"></a>My rule of thumb</h2>
<blockquote>
<p>Unless you have three <em>real</em> use cases to build against, don&rsquo;t spend extra time making the solution generic.</p>
</blockquote>
<p>The word &ldquo;real&rdquo; is intentional because of my comments on predicting the future.</p>
<p>The words &ldquo;extra time&rdquo; are also intentional. Generic abstractions can be useful
on their own, to hide complex logic or simplify a difficult to use API, or to
build a layer of defence; but if the main value in abstraction is for future
elegance <em>it&rsquo;s not worth it</em>.</p>
<p>Building an abstraction layer is the most problematic with only a single use
case, primarily because it usually adds more maintenance overhead which slows
iteration and maintenance. The &ldquo;abstract&rdquo; interface will often look very similar
to the internal one and refactoring is often not any easier than IDE assisted
renaming.</p>
<p>Building with two use cases is also problematic. It will be very tempting to
add <a href="https://martinfowler.com/bliki/FlagArgument.html">flag-based logic</a> into the
implementation, or worse, the external interface. When a third use case is
added, the most obvious method is to continue using flag-logic, which ends up
coupling the interface to the implementation. The value of the abstraction is
lower but maintenance cost isn&rsquo;t.</p>
<p>Three use cases, however, covers enough complexity that you&rsquo;re forced to
understand what the real value of the abstraction is and create it in a way that
makes it easier to work with.</p>


  
  ]]></content:encoded></item><item><title>Typing tricks to reduce ambiguity</title><link>https://camlittle.com/posts/2020-04-03-typing-tricks-to-reduce-ambiguity/</link><pubDate>Fri, 03 Apr 2020 08:11:00 +0200</pubDate><guid isPermaLink="true">https://camlittle.com/posts/2020-04-03-typing-tricks-to-reduce-ambiguity/</guid><enclosure url="https://camlittle.com/posts/2020-04-03-typing-tricks-to-reduce-ambiguity/thumbnail.png" length="19589" type="image/png"/><description>&lt;!--
A few notes on interactivity here
- no js, all toggling of language examples is done with css
- most of the controls text is set via css pseudo elements. this prevents
it from showing up in certain contexts, like copying and scraping
-->
&lt;p>One of the fundamentals of programming is defining interfaces, or contracts between parts of systems. Interfaces create layers of abstraction and allow scaling code beyond the complexity a single person can hold in their head. They appear at the level of function signatures, to dependency signatures, up to service-to-service network calls.&lt;/p></description><content:encoded><![CDATA[
  
<!--
A few notes on interactivity here
- no js, all toggling of language examples is done with css
- most of the controls text is set via css pseudo elements. this prevents
  it from showing up in certain contexts, like copying and scraping
-->
<p>One of the fundamentals of programming is defining interfaces, or contracts between parts of systems. Interfaces create layers of abstraction and allow scaling code beyond the complexity a single person can hold in their head. They appear at the level of function signatures, to dependency signatures, up to service-to-service network calls.</p>
<p>There are almost always grey areas within an individual interface; areas where behavior isn&rsquo;t explicitly defined. This causes a couple problems. Interpretations of behavior can differ between people or over time, leading to subtle bugs due to drifting behavior in different modules. It also requires overhead and more error handling in each consumer, as you&rsquo;ll see below.</p>
<p>In a strongly typed language there are some not-immediately-obvious techniques to reduce this ambiguity and create a more intuitive design.</p>
<p>I&rsquo;ll provide code examples throughout this post, available in several different languages.</p>
<!-- no <p> --> <input type="radio" name="lang" id="lang-ts" value="ts" /> <label for="lang-ts">Typescript</label><br />
<!-- no <p> --> <input type="radio" name="lang" id="lang-kt" value="kt" /> <label for="lang-kt">Kotlin</label><br />
<!-- no <p> --> <input type="radio" name="lang" id="lang-go" value="go" /> <label for="lang-go">Go</label><br />
<!-- no <p> --> <input type="radio" name="lang" id="lang-openapi" value="openapi" checked /> <label for="lang-openapi">OpenAPI Specification</label><br />
<!-- no <p> --> <input type="radio" name="lang" id="lang-all" value="all" /> <label for="lang-all">All of the above</label><br />
<h2 id="the-basics-comments"><a class="heading-link" href="#the-basics-comments"></a>The basics: Comments</h2>
<p>As the author, the easiest way to avoid ambiguity is through documenting your code.</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code full-width" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Foo</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">type</span><span class="o">:</span> <span class="kt">string</span><span class="p">;</span> <span class="c1">// describes how foo should be represented
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Bar</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">discount?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">discountApplied?</span>: <span class="kt">boolean</span><span class="p">;</span> <span class="c1">// indicates if `discount` is possible, or actually applied, not present if no discount
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="k">val</span> <span class="py">type</span><span class="p">:</span> <span class="n">String</span> <span class="c1">// describes how foo should be represented
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Bar</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="k">val</span> <span class="py">discount</span><span class="p">:</span> <span class="n">String</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">  <span class="k">val</span> <span class="py">discountApplied</span><span class="p">:</span> <span class="n">Boolean</span><span class="p">?</span> <span class="c1">// indicates if `discount` is possible, or actually applied, not present if no discount
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">)</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Foo</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Type</span> <span class="kt">string</span> <span class="c1">// describes how foo should be represented
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Bar</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Discount</span>        <span class="o">*</span><span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">DiscountApplied</span> <span class="o">*</span><span class="kt">bool</span> <span class="c1">// indicates if `discount` is possible, or actually applied, not present if no discount
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Foo</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">type</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="l">describes how foo should be represented</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Bar</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">discount</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">discountApplied</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">boolean</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="l">indicates if `discount` is possible, or actually applied, not present if no discount</span><span class="w">
</span></span></span></code></pre></div></div>
<p>This helps, but couples you to additional tooling within your editor to expose without reading the source. Comments don&rsquo;t protect against human issues, such as misinterpretation or plain laziness, and conformance can&rsquo;t automatically be verified by build tooling.</p>
<h2 id="taking-advantage-of-typing"><a class="heading-link" href="#taking-advantage-of-typing"></a>Taking advantage of typing</h2>
<h3 id="enums"><a class="heading-link" href="#enums"></a>Enums</h3>
<p>A simple pattern is to use enumeration values. Explicit enumerations can reduce the need for inline error handling and allows for self-documentation through good naming.
This sounds simple, but I see people forget about enums often. The key question to ask is:</p>
<blockquote>
<p>Do I care about how the consumer <em>uses</em> this value?</p>
</blockquote>
<p>If the answer is yes, a string type doesn&rsquo;t capture the correct nuance.</p>
<!--
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
-->
<div class="example-code full-width" data-lang="ts">
<div class="code-comparison">
<div>
<p><strong>Before</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Foo</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">type</span><span class="o">:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">convertFooTypeToX</span><span class="p">(</span><span class="nx">x</span>: <span class="kt">Foo</span><span class="p">)</span><span class="o">:</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">switch</span> <span class="p">(</span><span class="nx">x</span><span class="p">.</span><span class="kr">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="s2">&#34;a&#34;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="s2">&#34;1&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="s2">&#34;b&#34;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="s2">&#34;2&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="s2">&#34;c&#34;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="s2">&#34;3&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">      <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`unknown type: </span><span class="si">${</span><span class="nx">x</span><span class="p">.</span><span class="kr">type</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div>
<p><strong>After</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">enum</span> <span class="nx">FooType</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">a</span> <span class="o">=</span> <span class="s2">&#34;a&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">b</span> <span class="o">=</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">c</span> <span class="o">=</span> <span class="s2">&#34;c&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Foo</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">type</span><span class="o">:</span> <span class="nx">FooType</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">convertFooTypeToX</span><span class="p">(</span><span class="nx">x</span>: <span class="kt">Foo</span><span class="p">)</span><span class="o">:</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">switch</span> <span class="p">(</span><span class="nx">x</span><span class="p">.</span><span class="kr">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nx">FooType.a</span>:
</span></span><span class="line"><span class="cl">      <span class="kt">return</span> <span class="s2">&#34;1&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nx">FooType.b</span>:
</span></span><span class="line"><span class="cl">      <span class="kt">return</span> <span class="s2">&#34;2&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nx">FooType.c</span>:
</span></span><span class="line"><span class="cl">      <span class="kt">return</span> <span class="s2">&#34;3&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// no default is required to satisfy type checking
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
</div>
</div>
<div class="example-code full-width" data-lang="kt">
<div class="code-comparison">
<div>
<p><strong>Before</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">type</span><span class="p">:</span> <span class="n">String</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">convertFooTypeToX</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Foo</span><span class="p">):</span> <span class="n">String</span> <span class="p">=</span> <span class="k">when</span> <span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;a&#34;</span> <span class="o">-&gt;</span> <span class="s2">&#34;1&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;b&#34;</span> <span class="o">-&gt;</span> <span class="s2">&#34;2&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;c&#34;</span> <span class="o">-&gt;</span> <span class="s2">&#34;3&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="o">-&gt;</span> <span class="k">throw</span> <span class="n">Exception</span><span class="p">(</span><span class="s2">&#34;unknown type: </span><span class="si">${x.type}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div>
<p><strong>After</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">FooType</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">a</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">b</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">c</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">type</span><span class="p">:</span> <span class="n">FooType</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">convertFooTypeToX</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Foo</span><span class="p">):</span> <span class="n">String</span> <span class="p">=</span> <span class="k">when</span> <span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nc">FooType</span><span class="p">.</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="s2">&#34;1&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nc">FooType</span><span class="p">.</span><span class="n">b</span> <span class="o">-&gt;</span> <span class="s2">&#34;2&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nc">FooType</span><span class="p">.</span><span class="n">c</span> <span class="o">-&gt;</span> <span class="s2">&#34;3&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// no else is required to satisfy type checking
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div></div>
</div>
</div>
<div class="example-code full-width" data-lang="go">
<div class="code-comparison">
<div>
<p><strong>Before</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Foo</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Type</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">ConvertFooTypeToX</span><span class="p">(</span><span class="nx">x</span> <span class="nx">Foo</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">switch</span> <span class="nx">x</span><span class="p">.</span><span class="nx">Type</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="s">&#34;a&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="s">&#34;1&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="s">&#34;b&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="s">&#34;2&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="s">&#34;c&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="s">&#34;3&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nb">panic</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;unknown type: %s&#34;</span><span class="p">,</span> <span class="nx">x</span><span class="p">.</span><span class="nx">Type</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><!-- [Playground](https://play.golang.org/p/LPKcE9TPvvT) -->
</div>
<div>
<p><strong>After</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">FooType</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="nx">FooTypeA</span> <span class="nx">FooType</span> <span class="p">=</span> <span class="s">&#34;a&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">FooTypeB</span>         <span class="p">=</span> <span class="s">&#34;b&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">FooTypeC</span>         <span class="p">=</span> <span class="s">&#34;c&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Foo</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Type</span> <span class="nx">FooType</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">ConvertFooTypeToX</span><span class="p">(</span><span class="nx">x</span> <span class="nx">Foo</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">switch</span> <span class="nx">x</span><span class="p">.</span><span class="nx">Type</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">FooTypeA</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="s">&#34;1&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">FooTypeB</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="s">&#34;2&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">FooTypeC</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="s">&#34;3&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// unfortunately, without real enums in go, we still need this
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nb">panic</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;unknown type: %s&#34;</span><span class="p">,</span> <span class="nx">x</span><span class="p">.</span><span class="nx">Type</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><!-- [Playground](https://play.golang.org/p/W6Zrdrp4OQt) -->
</div>
</div>
</div>
<div class="example-code full-width" data-lang="openapi">
<div class="code-comparison">
<div>
<p><strong>Before</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Foo</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">schema</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span></code></pre></div></div>
<div>
<p><strong>After</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Foo</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">schema</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">enum</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">a, b, c]</span><span class="w">
</span></span></span></code></pre></div></div>
</div>
</div>
<h3 id="string-formats"><a class="heading-link" href="#string-formats"></a>String formats</h3>
<p>Enums work well, but only work for explicit sets of values&mdash;they can&rsquo;t be applied if I don&rsquo;t know the full set of values. If I do know, adding anything new breaks backwards compatibility.</p>
<p>To get around this, I can use a type alias to provide more semantic information.</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">HtmlType</span> <span class="o">=</span> <span class="kt">string</span><span class="p">;</span>
</span></span></code></pre></div></div>
<div class="example-code" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">typealias</span> <span class="n">HtmlType</span> <span class="p">=</span> <span class="n">String</span>
</span></span></code></pre></div></div>
<div class="example-code" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">HtmlType</span> <span class="kt">string</span>
</span></span></code></pre></div></div>
<div class="example-code" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Foo</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">schema</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">format</span><span class="p">:</span><span class="w"> </span><span class="l">html</span><span class="w">
</span></span></span></code></pre></div></div>
<p>There&rsquo;s a loophole: The consumer could create their own string and pass it in place of <code>HtmlType</code>. Depending on the serialization library and language, it can be possible to discourage this with custom deserialization of a non-constructable type.</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">HtmlType</span> <span class="o">=</span> <span class="kt">string</span> <span class="o">&amp;</span> <span class="p">{</span> <span class="nx">__t</span><span class="o">:</span> <span class="s2">&#34;html_type&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">read</span><span class="p">(</span><span class="nx">response</span>: <span class="kt">Response</span><span class="p">)</span><span class="o">:</span> <span class="nx">HtmlType</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">body</span> <span class="kr">as</span> <span class="nx">HtmlType</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">HtmlTypeDeserializer</span> <span class="n">extends</span> <span class="n">JsonDeserializer</span><span class="p">&lt;</span><span class="n">HtmlType</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nd">@Override</span>
</span></span><span class="line"><span class="cl">  <span class="k">fun</span> <span class="nf">deserialize</span><span class="p">(</span><span class="n">JsonParser</span> <span class="n">jp</span><span class="p">,</span> <span class="n">DeserializationContext</span> <span class="n">ctx</span><span class="p">)</span> <span class="n">throws</span> <span class="n">IOException</span><span class="p">,</span> <span class="n">JsonProcessingException</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// read contents of jp...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="n">HtmlType</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@JsonDeserialize</span><span class="p">(</span><span class="n">using</span> <span class="p">=</span> <span class="n">HtmlTypeDeserializer</span><span class="o">::</span><span class="k">class</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">HtmlType</span> <span class="k">private</span> <span class="k">constructor</span><span class="p">(</span><span class="k">private</span> <span class="k">val</span> <span class="py">content</span><span class="p">:</span> <span class="n">String</span><span class="p">)</span>
</span></span></code></pre></div></div>
<div class="example-code" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// no example in this language
</span></span></span></code></pre></div></div>
<div class="example-code" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="c"># no example in this language</span><span class="w">
</span></span></span></code></pre></div></div>
<p>In the real world, it&rsquo;s risky to migrate to a format from an existing enumeration. There&rsquo;s often logic in the client that depends on knowledge of a specific value, and all that logic needs to be transformed into an api driven model. It&rsquo;s tempting to keep it in the client, but that makes <em>removal</em> of the value not-backwards compatible and undocumented.</p>
<h3 id="nested-nullables"><a class="heading-link" href="#nested-nullables"></a>Nested nullables</h3>
<p>A common pattern I see when designing api responses is to use a flat structure like the following.</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code full-width" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Workout</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">swim_id</span>: <span class="kt">string</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">swim_miles</span>: <span class="kt">number</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">swim_time</span>: <span class="kt">Time</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bike_id</span>: <span class="kt">string</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bike_miles</span>: <span class="kt">number</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bike_time</span>: <span class="kt">Time</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">run_id</span>: <span class="kt">string</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">run_miles</span>: <span class="kt">number</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">run_time</span>: <span class="kt">Time</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">import</span> <span class="nn">kotlin.time.Duration;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Workout</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">swim</span><span class="n">_id</span><span class="p">:</span> <span class="n">String</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">swim</span><span class="n">_miles</span><span class="p">:</span> <span class="n">String</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">swim</span><span class="n">_time</span><span class="p">:</span> <span class="n">Duration</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">bike</span><span class="n">_id</span><span class="p">:</span> <span class="n">String</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">bike</span><span class="n">_miles</span><span class="p">:</span> <span class="n">Double</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">bike</span><span class="n">_time</span><span class="p">:</span> <span class="n">Duration</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">run</span><span class="n">_id</span><span class="p">:</span> <span class="n">String</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">run</span><span class="n">_miles</span><span class="p">:</span> <span class="n">Double</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">run</span><span class="n">_time</span><span class="p">:</span> <span class="n">Duration</span><span class="p">?</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Workout</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">SwimID</span>    <span class="o">*</span><span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">SwimMiles</span> <span class="o">*</span><span class="kt">float64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">SwimTime</span>  <span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span>
</span></span><span class="line"><span class="cl">	<span class="nx">BikeID</span>    <span class="o">*</span><span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">BikeMiles</span> <span class="o">*</span><span class="kt">float64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">BikeTime</span>  <span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span>
</span></span><span class="line"><span class="cl">	<span class="nx">RunID</span>     <span class="o">*</span><span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">RunMiles</span>  <span class="o">*</span><span class="kt">float64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">RunTime</span>   <span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Workout</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">swim_id</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">swim_miles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">swim_time</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">bike_id</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">bike_miles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">bike_time</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">run_id</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">run_miles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">run_time</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div></div>
<p>This leads to open questions: What happens a mix of <code>id</code>, <code>miles</code>, and <code>time</code> is present? Should I always expect <code>miles</code> to be present if <code>id</code> is present? How does <code>time</code> relate to <code>miles</code>?</p>
<p>By breaking up the flat structure these can be answered.</p>
<p>Here, it&rsquo;s clear that an <code>id</code> is always paired with <code>miles</code> and <code>time</code>, and each type of activity might be missing:</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code full-width" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Segment</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">id</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">miles</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">time</span>: <span class="kt">Time</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Workout</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">swim</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bike</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">run</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">import</span> <span class="nn">kotlin.time.Duration;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Segment</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">id</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">miles</span><span class="p">:</span> <span class="n">Double</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">time</span><span class="p">:</span> <span class="n">Duration</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Workout</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">swim</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">bike</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">run</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Segment</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">ID</span>    <span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Miles</span> <span class="kt">float64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Time</span>  <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Workout</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Swim</span> <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Bike</span> <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Run</span>  <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Segment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">id</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">miles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">time</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Workout</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">swim</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">bike</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div></div>
<p>With this alternate structure, I can see that the other fields might be missing:</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code full-width" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Segment</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">id</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">miles</span>: <span class="kt">number</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">time</span>: <span class="kt">Time</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Workout</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">swim</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bike</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">run</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">import</span> <span class="nn">kotlin.time.Duration;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Segment</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">id</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">miles</span><span class="p">:</span> <span class="n">Double</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">time</span><span class="p">:</span> <span class="n">Duration</span><span class="p">?</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Workout</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">swim</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">bike</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">run</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Segment</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">ID</span>    <span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Miles</span> <span class="o">*</span><span class="kt">float64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Time</span>  <span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Workout</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Swim</span> <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Bike</span> <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Run</span>  <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Segment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">id</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">miles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">time</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Workout</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">swim</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">bike</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div></div>
<p>And here, I understand that the statistics might be missing, but are tied together:</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code full-width" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Segment</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">id</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">stats</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">miles</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">time</span>: <span class="kt">Time</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Workout</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">swim</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bike</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">run</span>: <span class="kt">Segment</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">import</span> <span class="nn">kotlin.time.Duration;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Stats</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">miles</span><span class="p">:</span> <span class="n">Double</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">time</span><span class="p">:</span> <span class="n">Duration</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Segment</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">id</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">stats</span><span class="p">:</span> <span class="n">Stats</span><span class="p">?</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Workout</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">swim</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">bike</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">var</span> <span class="py">run</span><span class="p">:</span> <span class="n">Segment</span><span class="p">?</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Stats</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Miles</span> <span class="kt">float64</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Time</span>  <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Segment</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">ID</span>    <span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Stats</span> <span class="o">*</span><span class="nx">Stats</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Workout</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Swim</span> <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Bike</span> <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Run</span>  <span class="o">*</span><span class="nx">Segment</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Stats</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">miles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">time</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Segment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">id</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">stats</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Stats&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Workout</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">swim</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">bike</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Segment&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div></div>
<p>This avoids type asserations and null pointer errors<span class="example-code" data-lang="ts">: <code>workout.swim_id!</code></span><span class="example-code" data-lang="kt">: <code>workout.swim_id!!</code></span><span class="example-code" data-lang="go">: <code>panic: runtime error: invalid memory address or nil pointer dereference</code></span><span class="example-code" data-lang="openapi">.</span></p>
<h3 id="type-unions"><a class="heading-link" href="#type-unions"></a>Type unions</h3>
<p>Another type structure that can reduce ambiguity is a union type. Union types allow representing &ldquo;exclusive or&rdquo; in the interface and avoid locking in an inheritance structure. <span class="example-code full-width" data-lang="kt">Kotlin&rsquo;s <a href="https://kotlinlang.org/docs/reference/sealed-classes.html">sealed classes</a> are a good way to implement these.</span> <span class="example-code full-width" data-lang="ts">This is a <a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types">first class feature in Typescript</a>.</span></p>
<p>For example, say I want to represent a figure on my site.</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code full-width" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Figure</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">source</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">attr</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">height?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">width?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">data</span> <span class="k">class</span> <span class="nc">Figure</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">source</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">attr</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">height</span><span class="p">:</span> <span class="n">Int</span><span class="p">?,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">width</span><span class="p">:</span> <span class="n">Int</span><span class="p">?</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Figure</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Source</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Attr</span>   <span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Height</span> <span class="o">*</span><span class="kt">int</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Width</span>  <span class="o">*</span><span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Figure</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">source</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">attr</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">height</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">width</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">nullable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div></div>
<p>This works, but allows for accidentally distorting the image by specifying a height and width that doesn&rsquo;t match the aspect ratio. A type union can prevent this.</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code full-width" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Size</span> <span class="o">=</span> <span class="p">{}</span> <span class="o">|</span> <span class="p">{</span> <span class="nx">height</span>: <span class="kt">number</span> <span class="p">}</span> <span class="o">|</span> <span class="p">{</span> <span class="nx">width</span>: <span class="kt">number</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">UnsizedFigure</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">source</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">attr</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Figure</span> <span class="o">=</span> <span class="nx">UnsizedFigure</span> <span class="o">&amp;</span> <span class="nx">Size</span><span class="p">;</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">sealed</span> <span class="k">class</span> <span class="nc">Figure</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">open</span> <span class="k">val</span> <span class="py">source</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">open</span> <span class="k">val</span> <span class="py">attr</span><span class="p">:</span> <span class="n">String</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UnsizedFigure</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">val</span> <span class="py">source</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">val</span> <span class="py">attr</span><span class="p">:</span> <span class="n">String</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span> <span class="n">Figure</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">HeightSizedFigure</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">val</span> <span class="py">source</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">val</span> <span class="py">attr</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">height</span><span class="p">:</span> <span class="n">Int</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span> <span class="n">Figure</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">WidthSizedFigure</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">val</span> <span class="py">source</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">override</span> <span class="k">val</span> <span class="py">attr</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">width</span><span class="p">:</span> <span class="n">Int</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span> <span class="n">Figure</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">UnsizedFigure</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Source</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Attr</span>   <span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">HeightSizedFigure</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">UnsizedFigure</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Height</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">WidthSizedFigure</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">UnsizedFigure</span>
</span></span><span class="line"><span class="cl">	<span class="nx">Width</span> <span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">Figure</span> <span class="kd">interface</span><span class="p">{}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">UnsizedFigure</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">source</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">attr</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Size</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">oneOf</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">height</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">width</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">number</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">SizedFigure</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">allOf</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/UnsizedFigure&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/Size&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">Figure</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">oneOf</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/UnsizedFigure&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;#/components/schemas/SizedFigure&#34;</span><span class="w">
</span></span></span></code></pre></div></div>
<p>Type unions force explicit checking of which type is used. They&rsquo;re possible in many languages, but not all.</p>
<nav class="lang-controls">
<label for="lang-ts"></label>
<label for="lang-kt"></label>
<label for="lang-go"></label>
<label for="lang-openapi"></label>
</nav>
<div class="example-code full-width" data-lang="ts">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">isHeightSized</span><span class="p">(</span><span class="nx">x</span>: <span class="kt">Size</span><span class="p">)</span><span class="o">:</span> <span class="nx">x</span> <span class="k">is</span> <span class="p">{</span> <span class="nx">height</span>: <span class="kt">number</span> <span class="p">}</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span><span class="nx">x</span> <span class="kr">as</span> <span class="p">{</span> <span class="nx">height?</span>: <span class="kt">number</span> <span class="p">}).</span><span class="nx">height</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">isWidthSized</span><span class="p">(</span><span class="nx">x</span>: <span class="kt">Size</span><span class="p">)</span><span class="o">:</span> <span class="nx">x</span> <span class="k">is</span> <span class="p">{</span> <span class="nx">width</span>: <span class="kt">number</span> <span class="p">}</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span><span class="nx">x</span> <span class="kr">as</span> <span class="p">{</span> <span class="nx">width?</span>: <span class="kt">number</span> <span class="p">}).</span><span class="nx">width</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="kt">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-kt" data-lang="kt"><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">eval</span><span class="p">(</span><span class="n">figure</span><span class="p">:</span> <span class="n">Figure</span><span class="p">):</span> <span class="n">Int</span> <span class="p">=</span> <span class="k">when</span> <span class="p">(</span><span class="n">figure</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">is</span> <span class="n">UnsizedFigure</span> <span class="o">-&gt;</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">is</span> <span class="n">HeightSizedFigure</span> <span class="o">-&gt;</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">is</span> <span class="n">WidthSizedFigure</span> <span class="o">-&gt;</span> <span class="m">2</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="go">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">eval</span><span class="p">(</span><span class="nx">figure</span> <span class="nx">Figure</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">switch</span> <span class="nx">t</span> <span class="o">:=</span> <span class="nx">figure</span><span class="p">.(</span><span class="kd">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">UnsizedFigure</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">HeightSizedFigure</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">WidthSizedFigure</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">	<span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="nb">panic</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;Unknown type: %v&#34;</span><span class="p">,</span> <span class="nx">t</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></div>
<div class="example-code full-width" data-lang="openapi">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="c"># See other languages for reference implementations.</span><span class="w">
</span></span></span></code></pre></div></div>
<h2 id="in-the-real-world"><a class="heading-link" href="#in-the-real-world"></a>In the real world</h2>
<p>These techniques can give great build-time safety when applied within a single codebase, but it&rsquo;s harder to apply that safety across different codebases (e.g. calling an api, or using a typescript dependency in a javascript codebase). Responsibility for conforming to the contract has been absolved from the consumer and has been shifted explicitly to the producer. Since there&rsquo;s less incentive for explicit protection through validation in client code, errors caused by backwards incompatibility are harder to track down. Documenting changes through the use of techniques like semver make this easy to avoid.</p>
<h3 id="introducing-into-an-existing-system"><a class="heading-link" href="#introducing-into-an-existing-system"></a>Introducing into an existing system</h3>
<p>In a well-established environment it&rsquo;s sometimes not possible to apply these patterns in the producer; especially when dealing with legacy systems or other teams. In these cases these patterns can be introduced in the middle of the stack, either within a fronting service or a module within the consuming client. This gives an explicit place to add validation and audit that the contract is being followed.</p>
<p>&nbsp;</p>
<p>To summarize: Introducing more complexity into your interface; be it a function call, library, or api; makes it harder for consumers to make the wrong assumptions without asking them to think about logic outside of their business domain.</p>


  
  ]]></content:encoded></item><item><title>Levels of understanding</title><link>https://camlittle.com/posts/levels-of-understanding/</link><pubDate>Thu, 26 Mar 2020 20:56:07 +0100</pubDate><guid isPermaLink="true">https://camlittle.com/posts/levels-of-understanding/</guid><enclosure url="https://camlittle.com/posts/levels-of-understanding/thumbnail.jpeg" length="14136" type="image/jpeg"/><description>&lt;p>Over my time working in the real world I&amp;rsquo;ve learned a lot about what it means to actually understand something. Naturally, this includes realizing that I don&amp;rsquo;t understand everything as well as I&amp;rsquo;d like to. I&amp;rsquo;ve also learned a lot about the process of learning, which has given me insights that have helped me grow faster along the way.&lt;/p>
&lt;p>To start, what does understanding actually mean?
To &lt;a href="https://www.goodreads.com/quotes/243913-in-general-i-feel-if-you-can-t-say-it-clearly">paraphrase&lt;/a> &lt;a href="https://www.goodreads.com/quotes/19421-if-you-can-t-explain-it-to-a-six-year-old">others&lt;/a>:&lt;/p>
&lt;blockquote>
&lt;p>To fully understand something you should be able to explain it to someone else.&lt;/p></description><content:encoded><![CDATA[
  
<p>Over my time working in the real world I&rsquo;ve learned a lot about what it means to actually understand something. Naturally, this includes realizing that I don&rsquo;t understand everything as well as I&rsquo;d like to. I&rsquo;ve also learned a lot about the process of learning, which has given me insights that have helped me grow faster along the way.</p>
<p>To start, what does understanding actually mean?
To <a href="https://www.goodreads.com/quotes/243913-in-general-i-feel-if-you-can-t-say-it-clearly">paraphrase</a> <a href="https://www.goodreads.com/quotes/19421-if-you-can-t-explain-it-to-a-six-year-old">others</a>:</p>
<blockquote>
<p>To fully understand something you should be able to explain it to someone else.</p>
</blockquote>
<p>Getting there takes time. In my experience there are a number of stages along the way, and I&rsquo;ve found that recognizing where I&rsquo;m at helps me avoid mistakes and accelerates the learning process understanding faster.</p>
<p>In this post, I&rsquo;m going to describe these stages as I understand them and how I use them.</p>
<div class="levels">
<ol>
<li>I don&rsquo;t understand</li>
<li>I can copy and extend</li>
<li>I know enough to be dangerous</li>
<li>I&rsquo;ve got a bad feeling about this</li>
<li>I can explain what I know</li>
</ol>
</div>
<h3 id="i-dont-understand"><a class="heading-link" href="#i-dont-understand"></a>I don&rsquo;t understand</h3>
<p>At this point I&rsquo;m aware that I don&rsquo;t understand. I&rsquo;ve moved past the Peak of &ldquo;Mount Stupid&rdquo; and I&rsquo;m in the &ldquo;Valley of Despair&rdquo; in the <a href="https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect">Dunning–Kruger</a> curve. This is a safe place to be, since the though that I might be doing things wrong is top of mind. When I&rsquo;m writing code, I pay much more attention to what I&rsquo;m doing and try to communicate my questions to other reviewers, so they also take a closer look. I also take more time to build safeguards into my code during this phase because the likelyhood of future change is higher.</p>
<h3 id="i-can-copy-and-extend"><a class="heading-link" href="#i-can-copy-and-extend"></a>I can copy and extend</h3>
<p>At this stage, I can build upon existing patterns, and I&rsquo;m starting to see the shape of those patterns. This is where I generally learn the fastest, but only if I&rsquo;m paying attention. It&rsquo;s key here to avoid <a href="https://en.wikipedia.org/wiki/Cargo_cult_programming">cargo culting</a> while recognizing the cost&mdash;it takes time and mental energy.</p>
<p>When I&rsquo;m working with someone else who&rsquo;s at this level I trust them to work independently, given they have patterns to copy and their code is well-reviewed.</p>
<h3 id="i-know-enough-to-be-dangerous"><a class="heading-link" href="#i-know-enough-to-be-dangerous"></a>I know enough to be dangerous</h3>
<p>This is the riskiest level, and the best way to get through it quickly is to take personal responsibility. At this stage I know a few patterns, but not how to apply them. A specific example is when I first learned about <a href="https://blog.golang.org/using-go-modules">go modules</a> and <a href="https://golang.org/ref/spec#Packages">packages</a>. I knew how to set up my project to use packages from external dependencies, but not how to apply the package organization structure to my own project. In order to get stuff done my project grew to have have excessively long files and code duplication. Since I knew I wasn&rsquo;t following the right pattern, I was able to separate responsibility within my code to allow it to be extracted in the future.</p>
<p>A specific technique I use here is to read each line in my change and spot check if I have a basic understanding of why I had to change it. If I don&rsquo;t, I revert it and see what happens.</p>
<p>Double check all your assumptions and pay attention. Automated tooling and testing (e.g. automated tests and linting, good gitignore files) will help a lot here and reduce the need for hand-holding.</p>
<h3 id="ive-got-a-bad-feeling-about-this"><a class="heading-link" href="#ive-got-a-bad-feeling-about-this"></a>I&rsquo;ve got a bad feeling about this</h3>
<p>At this point I&rsquo;m able to, both with my own work and when reviewing others&rsquo;, instinctively recognize bad patterns and can sometimes suggestion better replacements. However, I struggle to adequately explain <em>why</em>, or to fully internalize my logic.</p>
<p>With a healthy team, this is a good place to be in. If your team has trust issues, this is a bad place to be. Without being able to explain change requests, the original author won&rsquo;t see the value. You&rsquo;ll either need to accept what you feel isn&rsquo;t quality code or risk breeding resentment.</p>
<p>I often feel stuck in this stage for a long time&mdash;sometimes years. I think this is normal. Systems are complex, but recognizing I&rsquo;m starting to see patterns allows me to be more intentional and introspective, which lets me grow faster.</p>
<h3 id="i-can-explain-what-i-know"><a class="heading-link" href="#i-can-explain-what-i-know"></a>I can explain what I know</h3>
<p>Finally, I&rsquo;m able to explain clearly. I should be able to simplify the concepts in a way that reduces complexity&mdash;such as drawing a systems diagram, creating an analogy, or writing a blog post.</p>
<p>In order to communicate concepts, especially to someone who&rsquo;s still learning, some nuance will be lost. At any given point I&rsquo;m missing some depth of detail simply because there are limits to the amount of complexity I can hold in my head at a single point in time.</p>
<p>It&rsquo;s also important to recognize that complete understanding is unobtainable. There are always differences in opinion and changes over time, and it&rsquo;s worth reconsidering your assumptions if something doesn&rsquo;t feel right.</p>


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