<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Francesco Bedussi</title>
    <description>The latest articles on DEV Community by Francesco Bedussi (@fbedussi).</description>
    <link>https://dev.to/fbedussi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F575845%2F6e1f9cf4-41d6-46a7-9adc-6845c85b4f76.jpeg</url>
      <title>DEV Community: Francesco Bedussi</title>
      <link>https://dev.to/fbedussi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fbedussi"/>
    <language>en</language>
    <item>
      <title>Make impossible states impossibile, an example</title>
      <dc:creator>Francesco Bedussi</dc:creator>
      <pubDate>Mon, 08 Feb 2021 15:07:28 +0000</pubDate>
      <link>https://dev.to/fbedussi/make-impossible-states-impossibile-an-example-1ia0</link>
      <guid>https://dev.to/fbedussi/make-impossible-states-impossibile-an-example-1ia0</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yDGx3-wu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ei7ceckwdf274r74ph0z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yDGx3-wu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ei7ceckwdf274r74ph0z.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
(image by &lt;a href="https://www.flickr.com/photos/50826080@N00/8314718882/in/photolist-dEK7f7-K8PbhA-pRXkbV-RhDM4n-Kf99FQ-2kzezZk-JS5jAd-5bLrQ6-6qEW5u-NgAcjp-TY51Sn-23TdezF-KXjjbA-2hKr9sV-CQLfm-MdLj2w-e9NLA-3f4HV2-EMBrJJ-6YKM-HyweEL-3dJsTs-whwhv8-bknenS-6eQZ66-7u55mz-GQSjmH-FUBuLq-cf55Qs-9mNuAu-bn379C-2hv84K2-e5TQ7n-Cov8zP-KKtWH6-F8w7m6-xUP5xo-EEAqMU-h271Ep-r5iH31-26AXWXP-V4w2iw-dVKXpX-4ipi9-G3MhaP-2jbpC5H-GkCxdS-GhQfRE-UBuZHo-AY5KVj"&gt;Stephen Bowler&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I was really inspired by &lt;a href="https://www.youtube.com/watch?v=IcgmSRJHu_8"&gt;this talk by Richard Feldman&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;TL;DR;&lt;br&gt;
It says that the data model should be designed in order to make impossible states impossible to represent. This is important in order to avoid from the beginning all the possible misbehaviour depending on wrong data.&lt;/p&gt;

&lt;p&gt;I recently had a chance to apply this concept at work. &lt;/p&gt;

&lt;p&gt;My team is building an application to handle eye exams. The core data  is the measure of some eye parameters, performed by a dedicated instrument, the phoropter. &lt;/p&gt;

&lt;p&gt;The data arrives from an external service, handled by another team. &lt;/p&gt;

&lt;p&gt;We started with this data model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterEyeMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// some parameters&lt;/span&gt;
        &lt;span class="nl"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
        &lt;span class="nx"&gt;cylinder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
     &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Phoropter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;L&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This model was actually born as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Phoropter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;L&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then L(eft) and R(ight) became optional at a later time, when it became clear that there are several edge cases where only one eye has to be measured.&lt;/p&gt;

&lt;p&gt;But having both of them as optional allow the model to represent an impossible state, the one where both eyes are missing. But we will return on that later. &lt;/p&gt;

&lt;p&gt;Then two change requests arrived:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The phoropter measure will always include “day” data (basically, the data it has now), but it can also include an optional “night” data series, with the same structure of the “day” one. If night data is included, a day-night delta is also included.&lt;/li&gt;
&lt;li&gt;Both day and night data can include measures with one or two different precisions, depending on the phoropter’s vendor. Some vendors provide only a standard decimal precision, while others also provide an hi-res mode with centesimal precision. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we went back to the design table and we came up with this updated model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Precision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decimals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;centesimal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasureWithPrecision&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;precision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Precision&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;L&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasureWithPrecision&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasureWithPrecision&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Phoropter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;night&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This model can indeed respond to the new requests. The problem is it can represent also states that are impossible by design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There could be a night data without a delta or vice versa&lt;/li&gt;
&lt;li&gt;L and R could be both missing (as we already said)&lt;/li&gt;
&lt;li&gt;L and R could be just an empty array&lt;/li&gt;
&lt;li&gt;L and R could each include multiple data with the same precision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, if we had to use this model we would risk application unintended behaviors, non dependent on code bugs, but on malformed data. This is bad, and even worse since our team is not responsible for data collecting and sending, so we want to draw a clear boundary here, to be able to route future issues to the right team. &lt;/p&gt;

&lt;p&gt;We could implement some data check routine, but this means more code and then more work and more room for bugs. Granpa used to say “best code is no code”. &lt;/p&gt;

&lt;p&gt;Let’s get back to the model design. To solve the first issue we can include the delta into the night data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasureNight&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Phoropter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;night&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterMeasureNight&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good. Now, to solve the other 2 issues we could use this model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;centesimal&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterDataNight&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;PhoropterData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Phoropter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhoropterData&lt;/span&gt;
      &lt;span class="nx"&gt;night&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterDataNight&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean, but are we really sure that the low-res decimal precision will always be there, even in the future? Maybe we’d better leave some room for flexibility here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;centesimal&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;Both&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But now we are once again risking that both decimal and centesimal data could be missing. We could treat them as we did with day and night:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasureWithPrecision&lt;/span&gt;
      &lt;span class="nx"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasureWithPrecision&lt;/span&gt;
      &lt;span class="nx"&gt;Both&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But now there is the chance of both main and secondary having the same precision. We can prevent that with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;mainPrecision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Precision&lt;/span&gt;
      &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;Both&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bingo. The same logic can be applied to solve the initial problem with L and R both optional. This:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Phoropter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;L&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;Both&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can be refactored like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;firstEyeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;L&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;R&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="nx"&gt;firstEye&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;secondEye&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhoropterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, the final version of the model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterEyeMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
      &lt;span class="nx"&gt;cylinder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Eye&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;L&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;R&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterMeasure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;firstEyeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Eye&lt;/span&gt;
      &lt;span class="nx"&gt;firstEye&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;secondEye&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhoropterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Precision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decimals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;centesimal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;mainPrecision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Precision&lt;/span&gt;
      &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterEyeMeasure&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PhoropterDataNight&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;PhoropterData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Phoropter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PhoropterData&lt;/span&gt;
      &lt;span class="nx"&gt;night&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PhotopterDataNight&lt;/span&gt;
      &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this model, just by turning on the validation on input data (with (fastify)[&lt;a href="https://www.fastify.io/docs/latest/Validation-and-Serialization"&gt;https://www.fastify.io/docs/latest/Validation-and-Serialization&lt;/a&gt;] or with (IO-TS)[&lt;a href="https://gcanti.github.io/io-ts"&gt;https://gcanti.github.io/io-ts&lt;/a&gt;], for instance) we can prevent bad data from sneaking into our application, and we don’t need to implement any manual check.&lt;/p&gt;

&lt;p&gt;Furthermore, since data came from an external service, if they are bad it is the external service call that fails, and not our application :-)&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>database</category>
    </item>
  </channel>
</rss>
