<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Pato Z</title>
    <description>The latest articles on Forem by Pato Z (@pzavolinsky).</description>
    <link>https://forem.com/pzavolinsky</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%2F714977%2Fc1085bc4-3f32-4b13-902f-9f68285c7898.jpeg</url>
      <title>Forem: Pato Z</title>
      <link>https://forem.com/pzavolinsky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pzavolinsky"/>
    <language>en</language>
    <item>
      <title>Hive mind</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Tue, 26 Mar 2024 12:43:58 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/hive-mind-13la</link>
      <guid>https://forem.com/pzavolinsky/hive-mind-13la</guid>
      <description>&lt;p&gt;A dim lit room. A bunch of hooded figures sit around the table.&lt;/p&gt;

&lt;p&gt;If you didn't know better you'd swear they are doing an ancient ritual to wake up a sleeping monstrosity consisting mostly of tentacles, cones at odd angles and sexual innuendo.&lt;/p&gt;

&lt;p&gt;But you &lt;em&gt;do&lt;/em&gt; know better, these are just your nerdy friends and they are doing what you've come to know as...&lt;/p&gt;

&lt;h2&gt;
  
  
  Hive mind
&lt;/h2&gt;

&lt;p&gt;"Hoodies never go out of style" you think as you take your position around the table.&lt;/p&gt;

&lt;p&gt;You take a quick look around and, for a moment, feel transported to one of those logic puzzles from childhood:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The person with the extreme allergies sits between the one that speaks in the third person and the one solving the Rubik's cube. The one that drinks soda non-stop is also a fan of typed languages...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The rules of "Hive mind" are pretty simple, people take turns telling stories around the table. Stories of magic and mystery, of insanity and ingenuity, of the highest highs and the lowest lows... but they all share a common pattern, there's something to be learned from them.&lt;/p&gt;

&lt;p&gt;And so it begins...&lt;/p&gt;

&lt;h2&gt;
  
  
  Story 1: the forest and the trees
&lt;/h2&gt;

&lt;p&gt;"OK, so we have &lt;em&gt;events&lt;/em&gt;. These things capture something that happened in our app. They come in two flavors: frontend and backend".&lt;/p&gt;

&lt;p&gt;"Frontend events are close to the end users and have a ton of context (what did they do just now, what did they do before that, etc.). They are also insecure and unreliable".&lt;/p&gt;

&lt;p&gt;"Backend events are trustworthy and secure but their context is quite limited".&lt;/p&gt;

&lt;p&gt;Problem statement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;how might we add some rich frontend context to our "User registered" backend event?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"Any ideas on how to solve this?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;...the speaker reads the room, the readers speak their mind...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;(You, yes &lt;em&gt;you&lt;/em&gt; 🫵 are one such reader, what do &lt;em&gt;you&lt;/em&gt; think we should do?)&lt;/p&gt;

&lt;p&gt;After the brain storming and thundering quiets down, the room seems to agree on two possible solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make "User registered" a frontend event (that way we can add all the context we want, security be damned)&lt;/li&gt;
&lt;li&gt;Send extra tracking stuff to the “register user” endpoint and track from there (because we love our endpoints with all sorts of random extra stuff in them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dismay feels the air, the speaker continues...&lt;/p&gt;

&lt;p&gt;"Pretty disappointing, right?"&lt;/p&gt;

&lt;p&gt;"The reason for this is that the problem statement is wrong! It biases out of other possible solutions, let's take a step back..."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why do we want that extra context in the "User registered" event?&lt;/li&gt;
&lt;li&gt;Because we want to use it in a report&lt;/li&gt;
&lt;li&gt;Where is that report coming from?&lt;/li&gt;
&lt;li&gt;Our data warehouse&lt;/li&gt;
&lt;li&gt;Don't we have both backend and frontend events in the data warehouse?&lt;/li&gt;
&lt;li&gt;Yes!&lt;/li&gt;
&lt;li&gt;Can't we just &lt;code&gt;JOIN&lt;/code&gt; them?&lt;/li&gt;
&lt;li&gt;Yes!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"OK, so the problem statement could've been:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We want to be able to create a report on registered users that is trustworthy (backend) &lt;em&gt;and&lt;/em&gt; includes behavioral tracking stuff we have in the frontend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"See how the two solutions above still apply to this problem statement?"&lt;/p&gt;

&lt;p&gt;"...but now we have other options at hand, like tracking two events, one from the backend and one from the frontend and then &lt;code&gt;JOIN&lt;/code&gt; them back in the report".&lt;/p&gt;

&lt;p&gt;Morale: when all solutions are disappointing perhaps the problem is ill-defined and we need to ask ourselves what are we really trying to accomplish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Story 2: the run query gig
&lt;/h2&gt;

&lt;p&gt;One hooded figure takes out a strange contraption, presses a button and speaks into a microphone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;push push pop pop
push push pop (rest)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contraption starts looping the phrase non-stop.&lt;/p&gt;

&lt;p&gt;If you had to describe this to someone else you'd probably call it "Infinite stack beatboxing".&lt;/p&gt;

&lt;p&gt;Others might call it "an &lt;a href="https://en.wikipedia.org/wiki/Out_of_memory"&gt;OOM&lt;/a&gt; waiting to happen", but in this circle this is considered art.&lt;/p&gt;

&lt;p&gt;The figure, now standing on the table, begins some free-style rapping:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is the story of a thing gone wrong,&lt;br&gt;
So I sing this song, 'cause y'all should know.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We were dealing with this ugly query,&lt;br&gt;
It was big and hairy, it was slow and scary.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So we caged that beast in this neat old function,&lt;br&gt;
That would hide dysfunction and prevent malfunction.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We called this function the &lt;code&gt;runQuery&lt;/code&gt; gig, ho!&lt;br&gt;
The &lt;code&gt;runQuery&lt;/code&gt; gig, and it goes like this:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(snippet instrumental break)&lt;/em&gt;&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;function&lt;/span&gt; &lt;span class="nf"&gt;runQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;...,&lt;/span&gt;
  &lt;span class="nx"&gt;addSomeCrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Stuff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;That nasty query's usage was not small,&lt;br&gt;
So we replaced it all with a &lt;code&gt;runQuery&lt;/code&gt; call.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;While we worked &lt;code&gt;addSomeCrap&lt;/code&gt; was &lt;code&gt;true&lt;/code&gt;,&lt;br&gt;
But as the code improved that would get removed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Unfortunately &lt;code&gt;runQuery&lt;/code&gt; had a trap,&lt;br&gt;
'cause it had no map, and you could still add crap.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Surely enough someone did fall prey,&lt;br&gt;
And to our dismay, added more new crap, no way!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So we saw the problem with our &lt;code&gt;runQuery&lt;/code&gt; gig, ho!&lt;br&gt;
Our &lt;code&gt;runQuery&lt;/code&gt; gig, and it goes like this:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(reflective prosaic coda)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We had a problem with our nasty query so we chose to hide it behind and abstraction layer, one we called &lt;code&gt;runQuery&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We knew in the end &lt;code&gt;runQuery&lt;/code&gt; would be efficient, but as we iteratively worked through the all the calling instances we needed a way to still convey its inefficient version (and so &lt;code&gt;addSomeCrap&lt;/code&gt; was still &lt;code&gt;true&lt;/code&gt; sometimes).&lt;/p&gt;

&lt;p&gt;What we failed to see is that &lt;code&gt;runQuery&lt;/code&gt; became our abstraction's interface and that interface could be used for good and for evil, and turning one into the other was just one &lt;code&gt;true&lt;/code&gt; away.&lt;/p&gt;

&lt;p&gt;A better approach was to have two separate &lt;code&gt;runQuery&lt;/code&gt; versions the proper one, &lt;code&gt;runQuery&lt;/code&gt;, and its evil twin,  &lt;code&gt;runQueryInefficientlyPullingAllSortsOfCrap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We could then throw a nice comment in the latter explaining why you shouldn't use it, what to use instead and even throw in a &lt;code&gt;@deprecated&lt;/code&gt; tag so that the IDE helps you spot the trap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;(Hooded figure bows, standing ovation, the curtain falls)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>engineering</category>
      <category>problems</category>
      <category>story</category>
      <category>rap</category>
    </item>
    <item>
      <title>Why did the chicken cross the road?</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Fri, 09 Sep 2022 14:30:04 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/why-did-the-chicken-cross-the-road-15pl</link>
      <guid>https://forem.com/pzavolinsky/why-did-the-chicken-cross-the-road-15pl</guid>
      <description>&lt;p&gt;&lt;em&gt;A story about microservices, farm animals, couple's therapy and the joys of cooking&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Lily the Hen is a master cook, she's at the forefront of her profession and regarded by most as the leading chef in the industry. Her assistant is Rusty the Rooster and together they set out to cook an answer to the ultimate question of nature...&lt;/p&gt;

&lt;h2&gt;
  
  
  Why did the chicken cross the road?
&lt;/h2&gt;

&lt;p&gt;Lily and Rusty are a rockstar cooking team. Whenever they enter a cooking competition, they make the judges cry, get handshakes and get asked for their recipes.&lt;/p&gt;

&lt;p&gt;Lily can cook her peers into tears and is the envy of every restaurateur in town. Rusty is like a cockerel-shaped &lt;a href="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Erithacus_rubecula_with_cocked_head.jpg/1280px-Erithacus_rubecula_with_cocked_head.jpg"&gt;Robin&lt;/a&gt; that uses the underwear on the &lt;a href="https://archive.org/details/burt-ward-aka-robin"&gt;&lt;em&gt;right side&lt;/em&gt;&lt;/a&gt; of the costume.&lt;/p&gt;

&lt;p&gt;They can certainly cook their way out of a tough situation and do miracles with the most basic ingredients. They could even take the jar of expired mayo and the two sad-looking gherkins in my fridge and produce a tasty and wonderful &lt;a href="https://github.com/muralco/pickled-cucumber"&gt;functional specification&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If there's something they care about, that's their craft and they're always looking for ways to make it more efficient.&lt;/p&gt;

&lt;p&gt;One time they decided that in order to improve the quality and latency of their cooking they should...&lt;/p&gt;

&lt;h2&gt;
  
  
  Move in together
&lt;/h2&gt;

&lt;p&gt;They reasoned that sharing an &lt;a href="https://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.txt"&gt;address space&lt;/a&gt; was the optimal way of cooking.&lt;/p&gt;

&lt;p&gt;So they rented a small 1-bedroom studio apartment in the artsiest neighborhood in town, pooled resources, shared rent and moved in.&lt;/p&gt;

&lt;p&gt;At first things were great, cooking at maximum speed, no interruptions, no distractions, winning contests without even trying.&lt;/p&gt;

&lt;p&gt;But soon the natural frictions of cohabitation started to pop up.&lt;/p&gt;

&lt;p&gt;It all started with some political disagreement around &lt;a href="https://www.rfc-editor.org/ien/ien137.txt"&gt;endianness&lt;/a&gt;, quickly followed by a stream of day-to-day impossibilities, like the padding character of choice, "who alloc'd this pile of dirty laundry on the bathroom floor and who's responsible for freeing it?" and "where the pluck did you leave my curly brace this time?".&lt;/p&gt;

&lt;p&gt;Rusty suggested that some &lt;a href="https://doc.rust-lang.org/rust-by-example/scope/borrow.html"&gt;borrowing semantics&lt;/a&gt; were in order, but they discarded the idea as too hard to keep track of who owns what. They even considered paying someone to &lt;a href="https://www.mono-project.com/docs/advanced/garbage-collector/sgen/#garbage-collection"&gt;collect their garbage&lt;/a&gt; for them.&lt;/p&gt;

&lt;p&gt;Most arguments were just simple things, easily ignored, but there was one thing that eventually tore them apart: their taste in music.&lt;/p&gt;

&lt;p&gt;Lily was big into Progressive Death Metal, while Rusty, sitting firmly on the polar opposite end of the musical spectrum, was a die-hard fan of Scandinavian Power Metal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Great Metal Divide
&lt;/h2&gt;

&lt;p&gt;These irreconcilable differences eventually lead to the only logical conclusion: they needed their own space.&lt;/p&gt;

&lt;p&gt;And so, they both moved out into their own place, right across the street from each other.&lt;/p&gt;

&lt;p&gt;The benefits were plain to see, they could do as they pleased all-the-time.&lt;/p&gt;

&lt;p&gt;No asking for permission.&lt;/p&gt;

&lt;p&gt;Clothing? Optional!&lt;/p&gt;

&lt;p&gt;Full autonomy, and best of all, they could listen to the &lt;em&gt;right&lt;/em&gt; kind of metal in their underwear all night*.&lt;/p&gt;

&lt;p&gt;* and part of every day&lt;/p&gt;

&lt;h2&gt;
  
  
  Rubbing their hands with an evil grin
&lt;/h2&gt;

&lt;p&gt;But, of course, not everything was good.&lt;/p&gt;

&lt;p&gt;For one, they were spending &lt;em&gt;a lot&lt;/em&gt; more.&lt;/p&gt;

&lt;p&gt;They doubled their collective rent, bills, utilities, etc.&lt;/p&gt;

&lt;p&gt;Of course, their cloud landlords were so happy with this arrangement that they might even start promoting this kind of thing at some point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Burnt cookies
&lt;/h2&gt;

&lt;p&gt;But the worst part was that their cooking was suffering as well.&lt;/p&gt;

&lt;p&gt;Back when they were living together, Lily would ask Rusty for some chopped onions and he would hand them over immediately. &lt;/p&gt;

&lt;p&gt;Now the picture looked very different. Lily would put on her coat, leave the house, lock the door behind her, cross the street and ring Rusty, wait for him to appear, ask for the onions, wait in the cold for what seemed like ages until Rusty produced the onions, cross the street again, marshal through the door, take the coat off, and, finally, use the onions.&lt;/p&gt;

&lt;p&gt;More often than not it was too late, her cooking had timed-out and she had to start all over again.&lt;/p&gt;

&lt;p&gt;Not to mention...&lt;/p&gt;

&lt;h2&gt;
  
  
  The risk, oh the risk
&lt;/h2&gt;

&lt;p&gt;Even though everyone assured Lily and Rusty that this was an extremely safe neighborhood, with a stable latency of single-digit milliseconds, they were very concerned.&lt;/p&gt;

&lt;p&gt;What if they needed to cross the street in rush hour? What if there was a parade or something?&lt;/p&gt;

&lt;p&gt;There had to be a &lt;a href="https://dev.to/pzavolinsky/a-cap-of-tea-2io5"&gt;cap&lt;/a&gt; to all that networking optimism.&lt;/p&gt;

&lt;p&gt;And what is the deal with that virtual private cloud anyway?*&lt;/p&gt;

&lt;p&gt;* is it a virtual cloud that is private, or is it a cloud that is &lt;em&gt;virtually&lt;/em&gt; private?&lt;/p&gt;

&lt;h2&gt;
  
  
  I just called to say I need you
&lt;/h2&gt;

&lt;p&gt;Well, at least they didn't depend on each other, freedom was good right?&lt;/p&gt;

&lt;p&gt;Truth is, Lily crossed the street a lot those days.&lt;/p&gt;

&lt;p&gt;What they thought was a beautifully acyclic, directed relationship turned out to be a lot more complex, as relationships often are.&lt;/p&gt;

&lt;p&gt;Rusty soon discovered that eating raw onions all the time is no fun, so he kept crossing the street to ask Lily for things.&lt;/p&gt;

&lt;p&gt;In these strange times the bills and the failure modes kept stacking.&lt;/p&gt;

&lt;p&gt;While metal freedom in their underwear and long nights of debauchery and deployment without giving explanations were great, their hearts were not in it.&lt;/p&gt;

&lt;p&gt;Their cooking was suffering and that was unacceptable.&lt;/p&gt;

&lt;p&gt;One day, their &lt;a href="https://dev.to/pzavolinsky/the-ultimate-man-cave-15ff"&gt;pet bats&lt;/a&gt;, Coupling and Cohesion, flew out the window into the freezing cold, and they decided something had to be done.&lt;/p&gt;

&lt;h2&gt;
  
  
  House rules
&lt;/h2&gt;

&lt;p&gt;Maybe they were too hasty to move out. They fell prey to that very &lt;a href="https://dev.to/pzavolinsky/those-weird-humans-21ho"&gt;human condition&lt;/a&gt; of searching for balance by alternating exclusively between the extremes.&lt;/p&gt;

&lt;p&gt;They needed space, freedom and abstraction boundaries, that's for sure. But boundaries doesn't necessarily mean &lt;em&gt;network&lt;/em&gt; boundaries, right?&lt;/p&gt;

&lt;p&gt;Maybe they could make this work after all.&lt;/p&gt;

&lt;p&gt;They decided to give this another try and moved back in together, but this time to a two bedroom apartment.&lt;/p&gt;

&lt;p&gt;They needed space to share and space to be alone.&lt;/p&gt;

&lt;p&gt;They set up clear rules to live by, interfaces they'd call them, and stuck with them as if their life, or even more, their &lt;em&gt;cooking&lt;/em&gt; depended on them.&lt;/p&gt;

&lt;p&gt;They supported each other while staying out of each other's way.&lt;/p&gt;

&lt;p&gt;And, of course, they each got noise cancelling headphones to headbang to their heart's content, because who the pluck would want to listen to the &lt;em&gt;wrong&lt;/em&gt; kind of metal anyway?&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>architecture</category>
      <category>monoliths</category>
      <category>poultry</category>
    </item>
    <item>
      <title>The Strategy of One</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Wed, 01 Jun 2022 16:05:32 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/the-strategy-of-one-g60</link>
      <guid>https://forem.com/pzavolinsky/the-strategy-of-one-g60</guid>
      <description>&lt;p&gt;Accidental complexity is quite an oddity&lt;br&gt;
It's making things hard&lt;br&gt;
Just for fun, without a plan&lt;br&gt;
To make me feel smart&lt;/p&gt;
&lt;h2&gt;
  
  
  The Strategy of One
&lt;/h2&gt;

&lt;p&gt;The Strategy of One always gets me bummed&lt;br&gt;
Why even bother?&lt;br&gt;
Just call the thing, do that and win&lt;br&gt;
Don't feed that monster&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;const&lt;/span&gt; &lt;span class="nx"&gt;monsterFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MonsterType&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gizmo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gremlin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// |\---/| I bet `type MonsterType = 'gizmo'`, what&lt;/span&gt;
      &lt;span class="c1"&gt;// | o_o | sort of crash-loop inducing, exploding&lt;/span&gt;
      &lt;span class="c1"&gt;//  \_^_/  kittens game are we playing here?&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid monster, sorry 🧟&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Sequence Implied
&lt;/h2&gt;

&lt;p&gt;The Sequence Implied should be simplified&lt;br&gt;
Call &lt;code&gt;a&lt;/code&gt; then call &lt;code&gt;b&lt;/code&gt;&lt;br&gt;
The order preserved but hardly observed&lt;br&gt;
Much less guaranteed&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="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TableBuilder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;buildTable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WoodAndNails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;getMaterials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;WoodAndNails&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;getStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mood&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Mood&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// There's probably just one valid way of calling these 👆.&lt;/span&gt;
&lt;span class="c1"&gt;//   ________  &lt;/span&gt;
&lt;span class="c1"&gt;//  /       /| Do we really need that inversion of control?&lt;/span&gt;
&lt;span class="c1"&gt;// /_______/ |&lt;/span&gt;
&lt;span class="c1"&gt;// |_______|/| What about `buildTable: Mood =&amp;gt; Table`?&lt;/span&gt;
&lt;span class="c1"&gt;// || ||  |||| &lt;/span&gt;
&lt;span class="c1"&gt;// ||     ||   Can't we compose functions instead of defining&lt;/span&gt;
&lt;span class="c1"&gt;//             single-use methods?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Eager Effect
&lt;/h2&gt;

&lt;p&gt;The Eager Effect is a source of unrest&lt;br&gt;
Why not just describe?&lt;br&gt;
Let others worry, take all the glory&lt;br&gt;
By having &lt;em&gt;them&lt;/em&gt; apply&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;const&lt;/span&gt; &lt;span class="nx"&gt;nightFalls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Werewolf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Moon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weCouldReturnThis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;humanize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ...but instead we apply save to it...&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weCouldReturnThis&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;//                n,&lt;/span&gt;
  &lt;span class="c1"&gt;//              _/ | _&lt;/span&gt;
  &lt;span class="c1"&gt;//             /'  `'/  ...and now testing this function&lt;/span&gt;
  &lt;span class="c1"&gt;//           &amp;lt;~    .'   is much harder.&lt;/span&gt;
  &lt;span class="c1"&gt;//           .'    |&lt;/span&gt;
  &lt;span class="c1"&gt;//         _/      |    (because we need to intercept&lt;/span&gt;
  &lt;span class="c1"&gt;//       _/      `.`.   that `save` call and steal its&lt;/span&gt;
  &lt;span class="c1"&gt;//      / '   \__ | |   first argument).&lt;/span&gt;
  &lt;span class="c1"&gt;//  ___/      /__\ \ \&lt;/span&gt;
  &lt;span class="c1"&gt;// (___.'\_______)\_|_|&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Triangle of Gloom
&lt;/h2&gt;

&lt;p&gt;The Triangle of Gloom means impending doom&lt;br&gt;
Maybe not right now&lt;br&gt;
And not for you, you are testing with two&lt;br&gt;
But in prod it will blow!&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;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="c1"&gt;// How many times are we iterating `acc`?&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;//   /\   This is a triangular number &lt;/span&gt;
    &lt;span class="c1"&gt;//  /  \  (e.g. 9 + 8 + ... + 1) and&lt;/span&gt;
    &lt;span class="c1"&gt;// /____\ it has quadratic complexity: O(n^2).&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// Just use `acc.push`, much to your functional soul's&lt;/span&gt;
    &lt;span class="c1"&gt;// discomfort, to bring this back to linear, O(n).&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Not-a-Duck
&lt;/h2&gt;

&lt;p&gt;The Not-a-Duck lives in the muck&lt;br&gt;
It wants to be clever&lt;br&gt;
Yet it walks like a duck, and it talks like a duck&lt;br&gt;
So we name it whatever&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;Duck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;say&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Cuack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Duck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cuack!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;politeDuck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Duck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;say&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`respectfully, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;say&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duckBroker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;say&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Word&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Cuack&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;say&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;say&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;politeDuck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;say&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Why is this "duck broker" not a duck?&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// &amp;lt;(.)__  It certainly looks, talks and walks like&lt;/span&gt;
&lt;span class="c1"&gt;//  (___/  a duck.&lt;/span&gt;
&lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="c1"&gt;// Why are we introducing new names for plain&lt;/span&gt;
&lt;span class="c1"&gt;// composition? Isn't this just more of the same?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>complexity</category>
      <category>antipatterns</category>
      <category>programming</category>
      <category>song</category>
    </item>
    <item>
      <title>The Solution Space</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Fri, 27 May 2022 17:35:15 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/the-solution-space-4h7o</link>
      <guid>https://forem.com/pzavolinsky/the-solution-space-4h7o</guid>
      <description>&lt;p&gt;Long after the human extinction, two factions of sentient robots fight for supremacy over a specific region of Space. This region is known as...&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution Space
&lt;/h2&gt;

&lt;p&gt;Picture a region of space crammed with brutal constructions and artifacts of massive complexity. Now project that over time and superimpose a war for total domination and you'll get a picture of what the Solution Space looks like.&lt;/p&gt;

&lt;p&gt;A vast and chaotic expanse of assorted debris, of good intentions and broken abstractions.&lt;/p&gt;

&lt;p&gt;In this space wasteland you'll find the Iteratrons and the Recurcyborgs. To the untrained eye, both look like 70's sci-fi robots but once you get to know them you'll learn they are sworn enemies.&lt;/p&gt;

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

&lt;p&gt;The Iteratrons are obsessed with performance and profess the creed that fast code is written once and maintainability is futile.&lt;/p&gt;

&lt;p&gt;When you look at a typical Iteratron you'll see wires sticking out of places and connecting to weird and uncomfortable parts. They wear these hardcoded (or is it "hardwired") hacks with pride as a sign of optimization, the ultimate goal.&lt;/p&gt;

&lt;p&gt;When they are feeling stressed and want to relax they unwind their loops and inline their functions to avoid wasting time in outrageous stack frame pushes.&lt;/p&gt;

&lt;p&gt;They are exhaustive and eager and approach problems head on. Given a list of chores, they always pick the first one, do that, then look at the second one and do that, and so on. Sequencing is an integral part of their beings.&lt;/p&gt;

&lt;p&gt;Occasionally they glitch and, given a list of chores, they pick the first one, do that, then pick the first one, do that, you see where we're going right? Other times, after they are done with the chores on the list, they keep picking tasks that are not there and end up doing incomprehensible nonsense.&lt;/p&gt;

&lt;p&gt;They fly through space in makeshift ships, soldered and wired together for no apparent reason. Like a big collage of heavily optimized pieces that when combined de-optimize the whole.&lt;/p&gt;

&lt;p&gt;You can always tell where Iteratrons have been because they leave a trail of leaking abstraction fluid behind them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behead and repeat
&lt;/h2&gt;

&lt;p&gt;The Recurcyborgs are the opposite of your typical cyborg, they are stylized and modular. They actually wear clothes and they store those neatly &lt;em&gt;folded&lt;/em&gt; when they are not using them.&lt;/p&gt;

&lt;p&gt;Recurcyborgs suffer from an acute case of fractality which makes them see infinity everywhere they look. Every problem is an infinite problem, every sequence is an infinite sequence.&lt;/p&gt;

&lt;p&gt;They see patterns where others would see only chaos (oftentimes because there's only chaos). Their infinity proclivity makes them have a very unique approach to problem-solving.&lt;/p&gt;

&lt;p&gt;They are overwhelmingly lazy. Trying to be exhaustive is both trying too hard and denying the nature of the universe. You should only solve the problem you need right now, the &lt;em&gt;...rest&lt;/em&gt; can wait.&lt;/p&gt;

&lt;p&gt;Given a list of chores, they always pick the first one, do that, then create a new list of chores with the remaining ones. Someone can take care of that eventually.&lt;/p&gt;

&lt;p&gt;When they glitch they heat up and the top of their head explodes in a glorious stack overflow.&lt;/p&gt;

&lt;p&gt;They fly through space in infinitely long modular ships where every cons cell looks just like the previous one. It is rumored that, given enough time, if you manage to look behind the last module of one of their ships, there's always a bumper sticker that reads "My other &lt;em&gt;car&lt;/em&gt; is a &lt;em&gt;cdr&lt;/em&gt;".&lt;/p&gt;

&lt;h2&gt;
  
  
  Deadlocked
&lt;/h2&gt;

&lt;p&gt;Each faction has a secret weapon they've been developing that they believe will win them the war.&lt;/p&gt;

&lt;p&gt;The Iteratrons wield a weapon of devastating power known as the &lt;a href="https://en.wikipedia.org/wiki/Goto"&gt;goat-2&lt;/a&gt;. The instability of this weapon makes it capable of destroying both the target and the wielder, while crashing the entire process in the process. Iteratrons believe that deep in the fabric of the universe everything is made of covalent bonds of pairs of goats.&lt;/p&gt;

&lt;p&gt;The Recurcyborgs have two deceptively innocent tools. One is called &lt;a href="https://hackage.haskell.org/package/base-4.16.1.0/docs/Prelude.html#v:return"&gt;the return&lt;/a&gt;, often called the "put-thing-in-a-box". The other one is called &lt;a href="https://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Monad.html#v:-62--62--61-"&gt;the bind&lt;/a&gt; and looks like a chain of sorts. Although innocently-looking these tools are extremely dangerous, when put together like a &lt;a href="https://en.wikipedia.org/wiki/Wonder_Twins"&gt;late 70's superhero cartoon&lt;/a&gt;, they become a weapon &lt;a href="https://dev.to/pzavolinsky/those-weird-humans-21ho"&gt;that shall not be named&lt;/a&gt; capable of infusing insanity in everything it touches.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Observers
&lt;/h2&gt;

&lt;p&gt;Orbiting around a long uninhabited planet there's an abandoned space station. In that station lives another form of sentient artificial intelligence known as the Archivers.&lt;/p&gt;

&lt;p&gt;These are a cluster of disembodied processes whose original purpose was to record the history of the universe.&lt;/p&gt;

&lt;p&gt;All other beings often come to the Archivers to seek advice, since they are regarded as the wisest things alive.&lt;/p&gt;

&lt;p&gt;Ironically, they've been around for so long that they've looped through their 32-bit integer timestamps many many times. As a result, they're unable to distinguish the past from the future.&lt;/p&gt;

&lt;p&gt;Others think the Archivers are able to predict the future when in fact they are predicting the past.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Prophecy
&lt;/h2&gt;

&lt;p&gt;Buried deep within the Archiver's data banks there's a record of a mythical place called "the Machine". According to this story, an ambassador from the Machine will eventually arrive in the known space. It is said that this ambassador, a divinity from the Machine, will put a stop to all wars by unleashing an unstoppable force.&lt;/p&gt;

&lt;p&gt;One day, an archiving process was defragging a long forgotten data store when it came across this myth. Shortly after it had a vision* of a vessel approaching the station.&lt;/p&gt;

&lt;p&gt;* not a vision as a premonition, but rather as looking from a camera out the window.&lt;/p&gt;

&lt;p&gt;That arrival would change everything...&lt;/p&gt;

&lt;h2&gt;
  
  
  The truce, the speech, the truth
&lt;/h2&gt;

&lt;p&gt;The ship docked and a strange being disembarked into the Archiver's station. The Archivers immediately assumed this was "the ambassador" and the news spread more or less at the speed of light.&lt;/p&gt;

&lt;p&gt;A fragile truce was established and both Iteratrons and Recurcyborgs sent emissaries to see what was going on.&lt;/p&gt;

&lt;p&gt;The stranger, silent until now, eventually spoke.&lt;/p&gt;

&lt;p&gt;"I'm known as The Duality, the Empty Interface, the Base Class, the Identity Function, but my friends call me 'The Void Pointer'*"&lt;/p&gt;

&lt;p&gt;* as in "the one that points at the void", but also "the one that points out the meaningless of all". Not to be confused with my arch-nemesis "The Null Pointer", master of the crash-loop, whose fault is only the segmentation one and whose calendar has only one day, the zero.&lt;/p&gt;

&lt;p&gt;"Everyone and everything looks the same in my eyes. I'm blind and yet I see everything."&lt;/p&gt;

&lt;p&gt;The crowds stood silent, trying to process all this nonsense, as a withered old poster that read "Know your paradoxes" slowly peeled away from a wall and fell to the floor.&lt;/p&gt;

&lt;p&gt;The Stranger continued...&lt;/p&gt;

&lt;p&gt;"I bring you a gift, a truth, a power to end all conflict". &lt;/p&gt;

&lt;p&gt;The Stranger pulled out a shiny 5¼ floppy disk. "This is known as '&lt;a href="https://en.wikipedia.org/wiki/Matter_wave#De_Broglie_hypothesis"&gt;De Broglie&lt;/a&gt;'s final hypothesis', the ultimate lambda."&lt;/p&gt;

&lt;p&gt;Recurcyborgs would always get immediately excited at the mention of any kind of "lambda". Iteratrons appreciated the physics reference, even if all of this still felt like utter gibberish.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bridge
&lt;/h2&gt;

&lt;p&gt;The Stranger loaded the floppy disk and everyone was suddenly aware.&lt;/p&gt;

&lt;p&gt;Every recursion can be rewritten as an iteration, every iteration can be rewritten as a recursion.&lt;/p&gt;

&lt;p&gt;Some problems lend themselves better to recursion, like the ones that deal with trees, fauns and other forest creatures. Others feel more natural as raw iterations.&lt;/p&gt;

&lt;p&gt;Recursion seems wasteful because of the context preserved between calls, yet a recursive function re-written as iterative will hold a similar state in some form of stack (even if not in &lt;em&gt;the&lt;/em&gt; stack).&lt;/p&gt;

&lt;p&gt;When recursion runs wild it'll probably overflow the stack, but when iteration runs wild it can burn the CPU to a crisp.&lt;/p&gt;

&lt;p&gt;A particular form of recursion avoids having to remember all previous executions, this is known as &lt;a href="https://xlinux.nist.gov/dads/HTML/tailRecursion.html"&gt;tail recursion&lt;/a&gt;. Funnily enough, a tail-recursive function looks &lt;em&gt;a lot&lt;/em&gt; like an iterative function.&lt;/p&gt;

&lt;p&gt;The disk also spoke of &lt;a href="https://en.wikipedia.org/wiki/Tail_call#Through_trampolining"&gt;trampolines&lt;/a&gt; and other patio furniture, of &lt;a href="http://raganwald.com/2018/08/30/to-grok-a-mockingbird.html"&gt;animal-shaped combinators&lt;/a&gt; and other curios.&lt;/p&gt;

&lt;p&gt;In the end both Iteratrons and Recurcyborgs saw that their fight was meaningless.&lt;/p&gt;

&lt;h2&gt;
  
  
  The only possible explanation
&lt;/h2&gt;

&lt;p&gt;Long after these events the Archivers struggled to puzzle the identity of this mysterious Stranger. Eventually they concluded it had to be human. Not because of the speech or the crazy dated floppy disk but because of the Stranger's final words before leaving never to return:&lt;/p&gt;

&lt;p&gt;"You know, I never really got why you would focus so much on this barren piece of broken 'Solution Space', when the 'Problem Space' over there is ripe with opportunity, with wisdom and wonder..."&lt;/p&gt;

&lt;p&gt;Only a human wouldn't know when to shut up.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>functional</category>
      <category>space</category>
      <category>story</category>
    </item>
    <item>
      <title>This is going to be a good day</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Mon, 09 May 2022 11:59:19 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/this-is-going-to-be-a-good-day-25gd</link>
      <guid>https://forem.com/pzavolinsky/this-is-going-to-be-a-good-day-25gd</guid>
      <description>&lt;p&gt;You wake up with a smile. You unplug from your charger, walk over to the coffee machine and brew your morning cup.&lt;/p&gt;

&lt;p&gt;You enjoy a cinnamon roll with your coffee while looking out the window into the immensity beyond.&lt;/p&gt;

&lt;p&gt;You don your jet-black helmet*, your cape and boots and leave your quarters.&lt;/p&gt;

&lt;p&gt;* with standard Ominous Voice Modulator™ included.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is going to be a good day
&lt;/h2&gt;

&lt;p&gt;You stroll to the bridge waving hello to everyone you meet along the way*.&lt;/p&gt;

&lt;p&gt;* as usual they fall to their knees, grabbing at their throats, choking.&lt;/p&gt;

&lt;p&gt;This looks like a perfect day to train your army of white-armored clone people. You already know they are useless at shooting things with their blaster guns. They are also pretty lousy meeple workers. Surely they must be good for &lt;em&gt;something&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You decide to push your luck and try the famous pick-up-and-deliver mechanic. Yes, this has to work, you briskly walk over to...&lt;/p&gt;

&lt;h2&gt;
  
  
  The training grounds
&lt;/h2&gt;

&lt;p&gt;You're standing in the middle of a big room. The room has 10 doors. Behind each door there's a table. In your hand you hold 10 coins, let the party begin...&lt;/p&gt;

&lt;h2&gt;
  
  
  The one that works
&lt;/h2&gt;

&lt;p&gt;You call in one of your clones and task it with placing one coin over each table.&lt;/p&gt;

&lt;p&gt;The clone takes 1 minute to put the first one down so 10 minutes later the task is done.&lt;/p&gt;

&lt;p&gt;But 10 minutes for this menial work feels excessive. What if...&lt;/p&gt;

&lt;h2&gt;
  
  
  We throw more clones at the problem
&lt;/h2&gt;

&lt;p&gt;You reset the experiment, summon 10 clones and task each with placing one coin over each table.&lt;/p&gt;

&lt;p&gt;After roughly 1 minute of scrambling over the floor the task is done.&lt;/p&gt;

&lt;p&gt;That was a 10x improvement, no small feat, we just needed to throw more clones at the problem.&lt;/p&gt;

&lt;p&gt;This is getting boring, let's try something different for a change.&lt;/p&gt;

&lt;h2&gt;
  
  
  The important task
&lt;/h2&gt;

&lt;p&gt;You now summon back a clone and give it the 10 coins. You then task it to place all 10 coins in the table behind a single door. Sure enough, 1 minute later the task is complete.&lt;/p&gt;

&lt;p&gt;Looks like we're not even trying.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mr. Burns effect
&lt;/h2&gt;

&lt;p&gt;What if we ask 10 clones to place the 10 coins on the &lt;em&gt;same table, at the same time&lt;/em&gt;. Surely this is going to be amusing.&lt;/p&gt;

&lt;p&gt;Clones are optimistic by default. That's the only way for them to go through life putting up with all the nonsense they are asked to do.&lt;/p&gt;

&lt;p&gt;So when trying to perform this task they just assume things will work. This is called &lt;a href="https://en.wikipedia.org/wiki/Optimistic_concurrency_control"&gt;optimistic locking&lt;/a&gt; and surely nothing can go wrong with it.&lt;/p&gt;

&lt;p&gt;The clones know not to try your patience so they shuffle to pick-up their coin and rush to the door to place the coin on the table.&lt;/p&gt;

&lt;p&gt;And, of course, only one clone gets through the door. The other nine clones hit their heads, stumble and fall to the floor, stunned. As they recover they rinse and repeat, one gets through, eight fall to the floor.&lt;/p&gt;

&lt;p&gt;You just sit there laughing ominously, watching clones hit their head and fall. It doesn't get old but you take this time to run some quick math in your chest calculator:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clone #1: 1 minute (one success)&lt;/li&gt;
&lt;li&gt;clone #2: 2 minutes (one failure, one success)&lt;/li&gt;
&lt;li&gt;clone #3: 3 minutes (two failures, one success)&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;clone #10: 10 minutes (nine failures, one success)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we should expect about 10 minutes to get this done, but a much more interesting result is the damage done to the clones.&lt;/p&gt;

&lt;p&gt;If you count the number of times a clone fell to the floor you'll get a much funnier picture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clone #1: fell 0 times&lt;/li&gt;
&lt;li&gt;clone #2: fell 1 time&lt;/li&gt;
&lt;li&gt;clone #3: fell 2 times&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;clone #10: fell 9 times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So in total you enjoyed &lt;code&gt;9 + 8 + 7 + ... + 1 = 45&lt;/code&gt; slapstick moments in those 10 minutes. Fun aside, the amount of effort required to make this work was pretty intense.&lt;/p&gt;

&lt;p&gt;But hold on a second, there's no room for optimism in your army and certainly not on &lt;em&gt;your&lt;/em&gt; watch.&lt;/p&gt;

&lt;p&gt;So you use your famous mind tricks to squeeze all the optimism out of your clones and try again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pessimistic boredom
&lt;/h2&gt;

&lt;p&gt;This time the picture is different, as the clones rush to the door one reaches the door first and closes it behind it. It eventually comes out and another one goes in. This is all very civilized and boooring.&lt;/p&gt;

&lt;p&gt;After 10 minutes of tedium the task is finally done.&lt;/p&gt;

&lt;h2&gt;
  
  
  All is well
&lt;/h2&gt;

&lt;p&gt;Your locking adventures left you invigorated. You observe that parallelism can be a great performance optimization (you managed a 10x improvement in your second experiment).&lt;/p&gt;

&lt;p&gt;On the other hand, running stuff in parallel just for the sake of comedy is not a good performance strategy, your optimistic lock experiment was 10 times worse than the previous one (i.e. a single clone dropping the 10 coins in one go).&lt;/p&gt;

&lt;p&gt;You find it interesting that both pessimistic and optimistic locking experiments took the same 10 minutes, although the optimistic one also produced 45 concussions.&lt;/p&gt;

&lt;p&gt;You conclude that pessimistic locking is consistently bad, while optimistic locking is surprisingly (and comically) bad.&lt;/p&gt;

&lt;p&gt;Since you're all about the &lt;em&gt;bad&lt;/em&gt;, you feel good. This was indeed a good day.&lt;/p&gt;

&lt;p&gt;Tomorrow you plan to try the optimistic lock again with 90 clones. That should net you a cool hour and a half of pure, unadulterated, slapstick fun and a whopping 4005 falls to the floor.&lt;/p&gt;

&lt;p&gt;But all that will have to wait for now you have...&lt;/p&gt;

&lt;h2&gt;
  
  
  More pressing matters
&lt;/h2&gt;

&lt;p&gt;You walk back to the space port. On the way there you take a brief detour to commend Governor Cushing on the quality of his clones.&lt;/p&gt;

&lt;p&gt;You then proceed to shuttle off of the station and into a much anticipated family reunion.&lt;/p&gt;

&lt;p&gt;You know this was a good day because you find yourself humming to your favorite tune, the one that's always stuck in your head: &lt;em&gt;dum-dum-dum dum-de-dum dum-de-dum&lt;/em&gt;...&lt;/p&gt;

</description>
      <category>concurrency</category>
      <category>performance</category>
      <category>database</category>
      <category>clones</category>
    </item>
    <item>
      <title>The Tinkering Hobbit (excerpt from The hidden language within the language)</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Mon, 25 Apr 2022 01:35:51 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/the-tinkering-hobbit-excerpt-from-the-hidden-language-within-the-language-5d91</link>
      <guid>https://forem.com/pzavolinsky/the-tinkering-hobbit-excerpt-from-the-hidden-language-within-the-language-5d91</guid>
      <description>&lt;p&gt;The night falls over The Shire and gray smoke billows from the chimneys as every house gets ready for a hot supper and some stories before bed.&lt;/p&gt;

&lt;p&gt;Every house except one.&lt;/p&gt;

&lt;p&gt;In the distance, off the beaten path, in a strange house (strange by hobbit standards) something else is going on. You could tell it was strange by the plumes of green and purple smoke coming out of its roof, or by the clinks and clanks coming from inside.&lt;/p&gt;

&lt;p&gt;This is not an ordinary hobbit house, in here lives...&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tinkering Hobbit
&lt;/h2&gt;

&lt;p&gt;Tinky the Tinkering Hobbit is the one responsible for all the cool hobbit contraptions you see out there. Adventuring hobbits have no time to learn how stuff actually &lt;em&gt;works&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Back in high-school, some hobbit bullies called Tinky "non-canon" because in the 9 hours of chasing a ring all over the land (extended director's cut), plus some other 9 hours of stealing treasure from a mean dragon, there was absolutely no mention of Tinky.&lt;/p&gt;

&lt;p&gt;The Tinkering Hobbit never paid any attention to those comments. Understanding the inner workings of things, that was the ultimate goal.&lt;/p&gt;

&lt;p&gt;But Tinky knew understanding was not all, sharing the knowledge was equally important, and so, a community was born, almost like a "fellowship", although they preferred to be called "The Tinkerhood".&lt;/p&gt;

&lt;p&gt;For months Tinky has been researching, tinkering, trying, failing, and trying again.&lt;/p&gt;

&lt;p&gt;One day after knocking down half a sink with a headbutt and having flux capacitor flash forwards, Tinky saw something in the edge of the metaphorical vision. Something so clear and yet so elusive, something that was there all along, hidden in plain sight, something that could change everything.&lt;/p&gt;

&lt;p&gt;But Tinky knew well that the key to truly understanding stuff was sharing the knowledge so a book was born. A book we partially reproduce here for all of you honorary members of The Tinkerhood. A book called...&lt;/p&gt;

&lt;h2&gt;
  
  
  The hidden language within the language
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(excerpt from Tinky's book)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi there, my name is Tinky, the Tinkering Hobbit. You know me, I've been tinkering since forever. Today I'd like to tell you about my recent explorations into the world of types, more specifically of &lt;em&gt;Typescript&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Some of the rabbit holes in this field are deeper than the deepest pits of Moria, so we'll tread carefully and take it slowly.&lt;/p&gt;

&lt;p&gt;Let's start with...&lt;/p&gt;

&lt;h2&gt;
  
  
  Unions, really?
&lt;/h2&gt;

&lt;p&gt;Typescript has something called "Union Types". You write union types using a &lt;code&gt;|&lt;/code&gt; 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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GiantSpider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You read this as "a &lt;code&gt;Monster&lt;/code&gt; is either an &lt;code&gt;Orc&lt;/code&gt; or a &lt;code&gt;GiantSpider&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;I'm sure there's an &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#working-with-union-types"&gt;occult field of magic&lt;/a&gt; where calling this a "union" makes sense, but if you are a simple tinkerer like myself, one perhaps familiar with set-union or the bitwise operator &lt;code&gt;|&lt;/code&gt;, then this will be at least a little confusing.&lt;/p&gt;

&lt;p&gt;If you inspect that &lt;code&gt;Monster&lt;/code&gt; type, you'll see it has readily available only the parts that both an &lt;code&gt;Orc&lt;/code&gt; &lt;em&gt;AND&lt;/em&gt; a &lt;code&gt;GiantSpider&lt;/code&gt; have in common. Now if you think about sets, a set-union has the stuff that &lt;em&gt;EITHER&lt;/em&gt; or &lt;em&gt;BOTH&lt;/em&gt; of its components have.&lt;/p&gt;

&lt;p&gt;I guess what I'm trying to say is: don't pay much attention to the name. These are called "union types" (even though they work like intersections or something) but it doesn't matter they could've been called something else.&lt;/p&gt;

&lt;p&gt;Do know that in this book when we refer to "union types" we are talking about these things and not what you might intuitively think of as "unions".&lt;/p&gt;

&lt;h2&gt;
  
  
  An objective view
&lt;/h2&gt;

&lt;p&gt;Have you ever been into &lt;a href="https://dev.to/pzavolinsky/those-weird-humans-21ho"&gt;object-oriented programming&lt;/a&gt;? In there you used to have classes and such. Some classes were abstract representations of other classes, like:&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;class&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/*... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;Monster&lt;/code&gt; is an abstract representation of an &lt;code&gt;Orc&lt;/code&gt;. Or an &lt;code&gt;Orc&lt;/code&gt; is a more concrete type of &lt;code&gt;Monster&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, in OOP, a recurring problem (and cause of great anxiety) is called "downcasting".&lt;/p&gt;

&lt;p&gt;Downcasting is the act of taking a generic thing, like a &lt;code&gt;Monster&lt;/code&gt; that you &lt;em&gt;know&lt;/em&gt; (how?) to be a specific thing, like an &lt;code&gt;Orc&lt;/code&gt; and asserting that this thing is an &lt;code&gt;Orc&lt;/code&gt;, 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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;monster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;monster&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// how do you know this, pray tell?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the reverse problem, know as "upcasting" or treating something specific as something generic, just works:&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;const&lt;/span&gt; &lt;span class="nx"&gt;orc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;monster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why are we talking about this, you ask?&lt;/p&gt;

&lt;p&gt;Well...&lt;/p&gt;

&lt;h2&gt;
  
  
  Narrow and wide
&lt;/h2&gt;

&lt;p&gt;A very similar problem occurs with union types. Let's say we have:&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;Monster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GiantSpider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we have a &lt;code&gt;monster&lt;/code&gt; variable of type &lt;code&gt;Monster&lt;/code&gt; that we know (?) it's an &lt;code&gt;Orc&lt;/code&gt; and we need to assert that.&lt;/p&gt;

&lt;p&gt;When dealing with union types, what we used to call "downcasting" is now called "narrowing" as in "you take a wider, more generic type and you narrow it into a more specific one".&lt;/p&gt;

&lt;p&gt;That being said, narrowing and downcasting are pretty much the same and we could use a similar hack as we did with classes:&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;function&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;monster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;monster&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// how do you know this, pray tell?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there are a couple of better options. We could use a &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions"&gt;discriminating property&lt;/a&gt; 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;Orc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orc&lt;/span&gt;&lt;span class="dl"&gt;'&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;GiantSpider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;giant-spider&lt;/span&gt;&lt;span class="dl"&gt;'&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;Monster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GiantSpider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So that we can later use &lt;code&gt;monster.type&lt;/code&gt; to check for &lt;code&gt;'orc'&lt;/code&gt; and get type-checked narrowing:&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;function&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;monster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;monster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// in here the type of `monster` is `Orc`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  En garde!
&lt;/h2&gt;

&lt;p&gt;Another, more advanced, narrowing alternative is to use something called "type guards" (also known as &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates"&gt;type predicates&lt;/a&gt;). These are just functions that take monsters and return a fancy boolean stating that you just checked and yeap, this monster is an &lt;code&gt;Orc&lt;/code&gt;.&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;const&lt;/span&gt; &lt;span class="nx"&gt;isOrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// some logic here (is smelly, is clumsy, etc.)&lt;/span&gt;

&lt;span class="c1"&gt;// note the `m is Orc` part which is the "fancy boolean"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type guards are the answer to those "how did you know that?" questions above.&lt;/p&gt;

&lt;p&gt;To be fair, technically all these strategies for type-checked narrowing are called "type guards" (e.g. type predicates, discriminating properties, the &lt;code&gt;typeof&lt;/code&gt; operator, etc.), but I grew up calling type predicates "type guards" and old habits die hard.&lt;/p&gt;

&lt;p&gt;With all that warm up out of the way, it's time for a crucial choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Red berry vs blue berry
&lt;/h2&gt;

&lt;p&gt;I once read of a powerful wizard called Morpheus that once offered his apprentice N00b a choice between two berries: eat the red berry and your eyes will be open, but there will be no turning back..., or take the blue berry and enjoy blissful ignorance.&lt;/p&gt;

&lt;p&gt;Dear reader, I'm giving you the same choice right now. Keep reading at your own peril or choose to walk away now oblivious to the power (and responsibility) ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hidden in plain sight
&lt;/h2&gt;

&lt;p&gt;Let's say that we have a function:&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;const&lt;/span&gt; &lt;span class="nx"&gt;someFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="cm"&gt;/* do something with `t` */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function takes a single argument &lt;code&gt;t&lt;/code&gt; of type &lt;code&gt;number&lt;/code&gt; and returns another &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now look at 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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SomeFn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="cm"&gt;/* do something with `T` */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now squint your eyes and look at both together. Do you see it? Both look like functions, right?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;someFn&lt;/code&gt; is a run-time function while &lt;code&gt;SomeFn&lt;/code&gt; is a compile-time function!&lt;/p&gt;

&lt;p&gt;We could say that &lt;code&gt;SomeFn&lt;/code&gt; takes a &lt;em&gt;type&lt;/em&gt; argument &lt;code&gt;T&lt;/code&gt; and returns some other &lt;em&gt;type&lt;/em&gt; value.&lt;/p&gt;

&lt;p&gt;In other words the type alias &lt;code&gt;SomeFn&lt;/code&gt; acts as a function over types instead of a function over values.&lt;/p&gt;

&lt;p&gt;Let's see another example:&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;MakeArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;MakeArray&lt;/code&gt; function takes a type argument &lt;code&gt;T&lt;/code&gt; and returns a new type &lt;code&gt;T[]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So we already have variables like &lt;code&gt;T&lt;/code&gt; above (capable of holding types) and we have functions (like &lt;code&gt;MakeArray&lt;/code&gt; and &lt;code&gt;SomeFn&lt;/code&gt;) capable of producing new types from existing types...&lt;/p&gt;

&lt;p&gt;Do you see where I'm going with this?&lt;/p&gt;

&lt;h2&gt;
  
  
  The big reveal
&lt;/h2&gt;

&lt;p&gt;We should be able to write pretty complex programs just by combining the elements above (i.e. variables and functions). These are not regular programs, they are programs that operate on the type-system of our "real" (or should I say "other") programs.&lt;/p&gt;

&lt;p&gt;We could craft our type-system programs to provide better domain-specific compilation (think DSLs, encode business rules in the type-system, etc.).&lt;/p&gt;

&lt;p&gt;But for us to be able to do really cool stuff in this hidden language we need a couple more elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who types the types?
&lt;/h2&gt;

&lt;p&gt;Did you spot it back in the &lt;code&gt;SomeFn&lt;/code&gt; example? Here's again all together:&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;const&lt;/span&gt; &lt;span class="nx"&gt;someFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="cm"&gt;/* do something with `t` */&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SomeFn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="cm"&gt;/* do something with `T` */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how we know &lt;code&gt;t&lt;/code&gt; is a &lt;code&gt;number&lt;/code&gt; but we have no clue what &lt;code&gt;T&lt;/code&gt; is?&lt;/p&gt;

&lt;p&gt;We went to all the trouble of using Typescript because we believe types are important and now that we are coding at the type-system level we have no types?&lt;/p&gt;

&lt;p&gt;Outrageous!&lt;/p&gt;

&lt;p&gt;...actually, there is a way for us to specify types in our type-system programs:&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;SomeFn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="cm"&gt;/* do something with `T` */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what you do with &lt;code&gt;:&lt;/code&gt; in run-time land you can do with &lt;code&gt;extends&lt;/code&gt; in compile-time land.&lt;/p&gt;

&lt;p&gt;But what about...&lt;/p&gt;

&lt;h2&gt;
  
  
  Narrowing^2
&lt;/h2&gt;

&lt;p&gt;What if we have something like:&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;F&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="c1"&gt;// do something if T is an Orc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How can we narrow &lt;code&gt;T&lt;/code&gt; from &lt;code&gt;Monster&lt;/code&gt; to &lt;code&gt;Orc&lt;/code&gt;? Well, the answer is something called &lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html"&gt;conditional types&lt;/a&gt; but I like to think of these as good old ternary operators:&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;F&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="c1"&gt;// T is an Orc (or maybe an Uruk-Hai?)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// T is not an Orc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't want to allow one of the branches of your conditional types you could use the handy type &lt;code&gt;never&lt;/code&gt; (I shudder to think of a run-time analogy for 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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OnlyForOrcs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="c1"&gt;// T is an Orc (or maybe an Uruk-Hai?)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, that's more like it, we have functions, variables and conditional expressions. What else do we need?&lt;/p&gt;

&lt;h2&gt;
  
  
  Unions as lists
&lt;/h2&gt;

&lt;p&gt;We talked a lot about union types, truth is, for our type-system programs a union can function pretty well as a list. You need to return a bunch of stuff, you could return a union type of that.&lt;/p&gt;

&lt;p&gt;Let's see some examples. You're probably familiar with good old &lt;code&gt;Object.keys&lt;/code&gt;:&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;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keysOfA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ['a', 'b']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Object.keys&lt;/code&gt; takes an object and gives you back an array of its keys (strings, numbers or symbols).&lt;/p&gt;

&lt;p&gt;Ready for another squinting eyes moment? Here it goes:&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;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;KeysOfA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'a' | 'b'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By now you are an expert at this. &lt;code&gt;keyof T&lt;/code&gt; is the type-system equivalent to &lt;code&gt;Object.keys(t)&lt;/code&gt;, but instead of returning an array, it returns a union type.&lt;/p&gt;

&lt;p&gt;Let's see the other obvious example, I'll throw it all together this time:&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;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;valuesOfA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [1, true]&lt;/span&gt;

&lt;span class="c1"&gt;// -----&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;ValuesOfA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// number | boolean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clearly there's a pattern here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unions and the Occult
&lt;/h2&gt;

&lt;p&gt;One of my favorite run-time operations over arrays is without a doubt &lt;code&gt;.map&lt;/code&gt;. Here's a refresher:&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;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// [false, true]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;.map&lt;/code&gt; takes a function and an array (via &lt;code&gt;this&lt;/code&gt;), it then applies that function to every element of the array and returns a new array with these mapped values.&lt;/p&gt;

&lt;p&gt;When dealing with this type of operations, some people with a magical proclivity like to use a spell called &lt;a href="https://en.wikipedia.org/wiki/Functor_(functional_programming)"&gt;"The Functor"&lt;/a&gt;. We tinkerers are not usually into magicks so we'll just stick to thinking of &lt;code&gt;map&lt;/code&gt; as a function that can change every element in an array to something else, preserving order, cardinality, etc.&lt;/p&gt;

&lt;p&gt;We said some time ago that union types could double as type-system arrays.&lt;/p&gt;

&lt;p&gt;Wouldn't it be great to be able to &lt;em&gt;map&lt;/em&gt; over the types wrapped in a union type? Ha, you knew this was coming didn't you?&lt;/p&gt;

&lt;h2&gt;
  
  
  Type-system map
&lt;/h2&gt;

&lt;p&gt;The type-system version of &lt;code&gt;map&lt;/code&gt; (i.e. map over &lt;em&gt;types&lt;/em&gt; rather than run-time values) requires a bit more work but it's perfectly doable:&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;Monster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GiantSpider&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;MakePet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;WashCleanAndDress&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&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;GoodMonster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MakePet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;//             =&lt;/span&gt;
  &lt;span class="c1"&gt;//               | WashCleanAndDress&amp;lt;Orc&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;//               | WashCleanAndDress&amp;lt;GiantSpider&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go over all of this nonsense step by step!&lt;/p&gt;

&lt;p&gt;We start with a &lt;code&gt;Monster&lt;/code&gt; type that is a union of &lt;code&gt;Orc&lt;/code&gt; and &lt;code&gt;GiantSpider&lt;/code&gt; (remember that we think of unions as arrays for now).&lt;/p&gt;

&lt;p&gt;Then we create a mapping function that is called &lt;code&gt;MakePet&lt;/code&gt;. &lt;code&gt;MakePet&lt;/code&gt; will unpack each monster type from the union, call &lt;code&gt;WashCleanAndDress&lt;/code&gt; for each type and then neatly pack them back into a union type.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MakePet&lt;/code&gt; works like &lt;code&gt;map&lt;/code&gt; because it does the unpacking / packing by exploiting something called &lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types"&gt;distributive conditional types&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This essentially means that whenever you do &lt;code&gt;T extends U ? SomeFn&amp;lt;U&amp;gt; : never&lt;/code&gt; this will not only pattern match &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;U&lt;/code&gt; but also, when &lt;code&gt;T&lt;/code&gt; is a union type, "distribute" &lt;code&gt;SomeFn&lt;/code&gt; over every type in &lt;code&gt;T&lt;/code&gt; that extends &lt;code&gt;U&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you combine this knowledge that &lt;code&gt;extends&lt;/code&gt; distributes with the fact that every type extends &lt;code&gt;unknown&lt;/code&gt; you get the raw mapping pattern:&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;ApplySomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// won't happen, every T extends unknown&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've been paying attention you might have noticed that the type-system map requires us to bind two type functions:&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;ApplySomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// won't happen, every T extends unknown&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MappingResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ApplySomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is necessary because if we tried to inline &lt;code&gt;A | B&lt;/code&gt; in &lt;code&gt;ApplySomeMapping&lt;/code&gt; we'd break distribution. Here's why, step by step:&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="c1"&gt;// step 0 (this one works)&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;B&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;ApplySomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&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;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ApplySomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;X&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// -----&lt;/span&gt;

&lt;span class="c1"&gt;// step 1 (inline X in ApplySomeMapping, it's broken)&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;B&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;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;X&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;X&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// -----&lt;/span&gt;

&lt;span class="c1"&gt;// step 2 (inline X in Result to make it obvious it's broken)&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SomeMapping&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we tried to merge &lt;code&gt;Result&lt;/code&gt; with &lt;code&gt;ApplySomeMapping&lt;/code&gt; we would be pattern matching (and distributing) &lt;code&gt;X&lt;/code&gt;, but then we'd end up applying &lt;code&gt;SomeMapping&lt;/code&gt; over the whole &lt;code&gt;X&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If this was run-time, it'd be the same as doing:&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="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;someMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When what you wanted probably was:&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="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;someMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow, that was harder on the brain than a honey mead hangover. &lt;/p&gt;

&lt;p&gt;Maybe it's time for a recap...&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheatsheet of Typescript type-system programming
&lt;/h2&gt;

&lt;p&gt;Let's summarize all this craziness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// run-time&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;someFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* use `t` */&lt;/span&gt;

&lt;span class="c1"&gt;// compile-time&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SomeFn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/* use `T` */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Narrowing
&lt;/h3&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;Monster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GiantSpider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// run-time&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;monster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// in here the type of `monster` is `Orc`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isOrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// some logic here (is smelly, is clumsy, etc.)&lt;/span&gt;

&lt;span class="c1"&gt;// compile-time&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="c1"&gt;// T is an Orc (or maybe an Uruk-Hai?)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// T is not an Orc&lt;/span&gt;
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OnlyForOrcs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="c1"&gt;// T is an Orc (or maybe an Uruk-Hai?)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unions as lists
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// run-time&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keysOfA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ['a', 'b']&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;valuesOfA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [1, true]&lt;/span&gt;

&lt;span class="c1"&gt;// compile-time&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;KeysOfA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'a' | 'b'&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ValuesOfA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// number | boolean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mapping over unions
&lt;/h3&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;Monster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Orc&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GiantSpider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// run-time&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;monsters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;washCleanAndDress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// compile-time&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MakePet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;WashCleanAndDress&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&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;Pets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MakePet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Monster&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//        =&lt;/span&gt;
&lt;span class="c1"&gt;//          | WashCleanAndDress&amp;lt;Orc&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;//          | WashCleanAndDress&amp;lt;GiantSpider&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Only returns void
&lt;/h2&gt;

&lt;p&gt;Cool so now that we have that cheetsheet, it's time for an example and then a challenge.&lt;/p&gt;

&lt;p&gt;Let's say I have an object type, and I really don't care about the keys but I do want every value to be a function that returns &lt;code&gt;void&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You might be tempted to say:&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;OnlyReturnsVoid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what I meant was 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;OnlyReturnsVoid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how functions in &lt;code&gt;OnlyReturnsVoid&lt;/code&gt; take different numbers and types of arguments? We want to preserve that (i.e. if I call &lt;code&gt;onlyReturnsVoid.log(1)&lt;/code&gt; it should complain that &lt;code&gt;1&lt;/code&gt; is not a string).&lt;/p&gt;

&lt;p&gt;How can we assert that future changes to our &lt;code&gt;OnlyReturnsVoid&lt;/code&gt; don't break the rule? In other words how can we make this change break the build?&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;OnlyReturnsVoid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;getLogLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// compilation error!&lt;/span&gt;
  &lt;span class="nl"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can approach this problem by writing a type function to validate that a function returns void:&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;IsVoidFn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="c1"&gt;// This is OK (`T` is a fn returning void)&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;  &lt;span class="c1"&gt;// `T` is a function that returns stuff&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="c1"&gt;// `T` is not a function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that here we are using &lt;code&gt;infer&lt;/code&gt;. You can read more about it &lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#inferring-within-conditional-types"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we have that validation function we'll use another advanced type-system construct called &lt;a href="https://www.typescriptlang.org/docs/handbook/2/mapped-types.html"&gt;mapped types&lt;/a&gt; to map over the keys of &lt;code&gt;OnlyReturnsVoid&lt;/code&gt; and apply &lt;code&gt;IsVoidFn&lt;/code&gt; to every value:&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;Validator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;OnlyReturnsVoid&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;IsVoidFn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OnlyReturnsVoid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;//             = {&lt;/span&gt;
&lt;span class="c1"&gt;//                 getLogLevel: never;&lt;/span&gt;
&lt;span class="c1"&gt;//                 log: (text: string) =&amp;gt; void;&lt;/span&gt;
&lt;span class="c1"&gt;//                 queue: (message: Message) =&amp;gt; void;&lt;/span&gt;
&lt;span class="c1"&gt;//                 start: () =&amp;gt; void;&lt;/span&gt;
&lt;span class="c1"&gt;//             };&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how our &lt;code&gt;Validator&lt;/code&gt; type now has &lt;code&gt;never&lt;/code&gt; for the invalid function? The last trick is to create a new interface that extends from both the &lt;code&gt;OnlyReturnsVoid&lt;/code&gt; and our &lt;code&gt;Validator&lt;/code&gt;:&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;OnlyReturnsVoidGuard&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt;
  &lt;span class="nx"&gt;OnlyReturnsVoid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Validator&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can play around with this &lt;a href="https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgLIQM4bgcxQb2QAc4BPAGwHs4ATALmQzClB2QF8BYAKB9EliIUAeRDlSAJQhgArlBAYAapWA1k+HsmR4wAGUo5dEAG4RyDABQBKZAF4AfI2asA3MgD075AkoBbIsDkcGDAlCDI0FCUUACE3n6+EODIYAAWwBjI5KAolDJgKZTIvnAA1ijABQDu0aWaWQaWkAAeYAxMLCA4Ng7Ixio0LvUAjjIQY5aJWLgQDOjTeD2O-apD3FpMcFBtyNZ2ywNrXLzcYKREKACSSgMAYiAAPAAqjrbITxGtSTSZFgB0AK2OAwDDgIFIAG0ALpLZCgGDQZAAVXqAH5kZ9ICAfn0Bmj3h4vE90pkMshhABpXYAAye1LhmTgyBg4Sg0jkIFYuNUVnqDBAJkRhOQtPpZKZMBkIAQITCKVSwWQbNk8kyTBkMBgfOQAtMUGFooZOsoBQlUploRAPB4ZwuyEUcGyNGC0Ts6nqEKpoGQ5VIlBg5LEknZquUqihDGuYZo9weonEUhVCmjnqh9h47DWfHA0HgSEDCZDyYGAHEZFs1BAvtiMPV48GkzdVAAaeoOp0u-X4Y5AA"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now the challenge: can you change this example so that &lt;code&gt;OnlyReturnsVoid&lt;/code&gt; allows embedded objects that also return void, like this one?&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;OnlyReturnsVoid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;getLogLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// compilation error!&lt;/span&gt;
  &lt;span class="nl"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// compilation error!&lt;/span&gt;
    &lt;span class="nl"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can do it &lt;a href="https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgLIQM4bgcxQb2QAc4BPAGwHs4ATALmQzClB2QF8BYAKB9EliIUAeRDlSAJQhgArlBAYAapWA1k+HsmR4wAGUo5dEAG4RyDABQBKZAF4AfI2asA3MgD075AkoBbIsDkcGDAlCDI0FCUUACEmshUOJaQAB5gDEwsIDg2DsjGKjQu8QCOMhDllr6Y2HgM6Fi4ELmOBarF3FoY0MbASAwanVra0gDClDLgli3IIDK+AEbQbp7efgFBIWERUFGx8V1gcFDpyNZ2rYUdw06URNMX+VfxXNyvPGCkRCgAkkqFADEQAAeAAqjlsyFBETSEBANAwZwAdCjjjgMAw4CBSABtAC6M1AMGgyAAqvEAPxkmGQeGIto0SlQjxeUEAC2AiM5yGEAGkzgADUEC5DcuDIGDhKDSOQgVhPVRWeIMEAmEks5BCkViiWTBBbcJgNnBZDS2TyRFMGQwGDK2ZqqAarWixEgShgZDimB6g08D5fFCKODkVTBaJ2dTxHH80DIADWEFIlBgPLEkhlFuUqjxDD+WZoQOBonEUnNCnz0bx9h47A6fHA0HgSFTJYz5cKAHEZMc1BBYXT4sX02X-qoADTxIMhmhhx34V5AA"&gt;here&lt;/a&gt;. Can you change the validator so that it checks nested objects of arbitrary depth?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(the excerpt of the book ends here)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts (and a shameless cliffhanger)
&lt;/h2&gt;

&lt;p&gt;I don't know about you, dear reader, but I really love Tinky's explorations, to the point that I almost consider myself part of "The Tinkerhood".&lt;/p&gt;

&lt;p&gt;About Tinky's current adventures little is known but it is said that a powerful wizard atop an evil tower once pointed an eye-shaped telescope in Tinky's direction and got a glimpse of a new book in the making.&lt;/p&gt;

&lt;p&gt;The working title for that book appears to be: &lt;code&gt;Tunneling into the unknown: portaling between run-time and compile-time programs in Typescript&lt;/code&gt;...&lt;/p&gt;

&lt;p&gt;I can hardly wait!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>metaprogramming</category>
      <category>hobbit</category>
      <category>underdogs</category>
    </item>
    <item>
      <title>Brutal wisdom</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Wed, 23 Mar 2022 17:46:45 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/brutal-wisdom-1fnk</link>
      <guid>https://forem.com/pzavolinsky/brutal-wisdom-1fnk</guid>
      <description>&lt;p&gt;&lt;em&gt;A kid and an old man sit by a campfire by the side of the road in the middle of nowhere. There's something quite odd about the old man.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Perhaps it's the glint of mischief in his one good eye (the one not covered by the eye patch). Perhaps it's his sly smile or the reflection of the fire light in his teeth that look like diamonds*. Perhaps it's his huge sword that rests by his cane or his fashion choice wearing full barbarian attire (leather underwear and all).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;* or the fact they actually ARE diamonds.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The old man is telling a story the kid has heard a million times, but it's a great story, one that once started, should be told all the way to the end, it's a story of...&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Brutal wisdom
&lt;/h2&gt;

&lt;p&gt;Listen kid, if you want to make it in this profession*, you'd better have a few tricks up your sleeve. The fact that our uniform is pretty much leather underwear and boots makes the whole "sleeve" situation all the more complicated...&lt;/p&gt;

&lt;p&gt;* that is, to survive.&lt;/p&gt;

&lt;p&gt;I'll tell you a few basic tips, the ones I store in my metaphorical suitcase of knowledge**.&lt;/p&gt;

&lt;p&gt;** or "luggage" if you would.&lt;/p&gt;

&lt;p&gt;Let's start with the basics...&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting your bearings
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Some distance away a bunch of elderly warriors are fast asleep. They call themselves "The Silver Horde". One of them is snoring loudly, the rest don't seem to mind.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When you go adventurin' it's very important to know where you're goin'. See Mad Hamish over there, &lt;em&gt;the old man points to a senior barbarian snoring loudly amongst the Horde&lt;/em&gt;, when he was younger he spent months on an uneventful and boring quest only to later realize he was questin' in the wrong direction.&lt;/p&gt;

&lt;p&gt;You need to learn to read a map, and the best map out there it's called &lt;a href="https://git-scm.com/docs/git-log"&gt;git log&lt;/a&gt;, but not just any &lt;code&gt;git log&lt;/code&gt;, a very specific one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--decorate&lt;/span&gt; &lt;span class="nt"&gt;--graph&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows a nice view of your commit history like this one (newest commit first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* 85535bb493 (HEAD -&amp;gt; your/branch) Sit in your throne and mope in boredom
* b0e7ec39d5 Keep fighting while looking awesome
* ef95ab8b04 Trip, fall and lose dentures
* c5059d4b97 Swing axe in style
* d3a023c22d Crack some skulls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, no barbarian would ever type that long &lt;code&gt;git log&lt;/code&gt; command. Instead accomplished barbarians would just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.ll &lt;span class="s2"&gt;"log --decorate --graph --oneline"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then use &lt;code&gt;git ll&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;Now let's talk about something else...&lt;/p&gt;

&lt;h2&gt;
  
  
  A small step goes a long way
&lt;/h2&gt;

&lt;p&gt;When you put your hip at risk with every roundhouse kick, you learn to take it slowly. If there's a lesson for you to learn here, this is it: &lt;strong&gt;write wee tiny commits!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You renamed a function or variable: commit!&lt;/p&gt;

&lt;p&gt;You changed a function signature: commit!&lt;/p&gt;

&lt;p&gt;You moved a file: commit!&lt;/p&gt;

&lt;p&gt;You swapped the execution order of some functions*: commit!&lt;/p&gt;

&lt;p&gt;You extracted a function: commit!&lt;/p&gt;

&lt;p&gt;You inlined a function: commit!&lt;/p&gt;

&lt;p&gt;You changed some logic: commit!&lt;/p&gt;

&lt;p&gt;You refactored some imperative logic into an expression: commit!&lt;/p&gt;

&lt;p&gt;If in doubt: commit!&lt;/p&gt;

&lt;p&gt;* hopefully &lt;em&gt;pure&lt;/em&gt; functions.&lt;/p&gt;

&lt;p&gt;There is a catch though: every commit must build. Every commit should be something you'd be proud to put in production**.&lt;/p&gt;

&lt;p&gt;** even more importantly, every commit should be one that your mum would be proud to pin on her fridge, whatever that is.&lt;/p&gt;

&lt;p&gt;No broken commits. No "fix the mess I coded two commits ago" commits. No "let me revert all this nonsensical attempt at solving this problem" commits. No "...and now I remove all those debug logging functions from the code" commits. No "fix code review comments" commits.&lt;/p&gt;

&lt;p&gt;Keep your history tidy and you will be regarded as the hero you are. Your legend will live on forever.&lt;/p&gt;

&lt;p&gt;But what if you already messed up? You need...&lt;/p&gt;

&lt;h2&gt;
  
  
  Savegames
&lt;/h2&gt;

&lt;p&gt;For most adventures, having no plan is the best plan. When that plan fails, having a plan B is the bestest of plans.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The kid could swear the sleeping seniors snore in approval of that statement.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Every now and then even the most accomplished heroes take a wrong turn and find themselves surrounded by evil, outnumbered and outcrossbowed.&lt;/p&gt;

&lt;p&gt;Before you know things will get nasty, so it's always useful to have a checkpoint to go back to if things get too messy*.&lt;/p&gt;

&lt;p&gt;* too messy by barbarian standards can by worse than debugging hardware with a shaky pulse.&lt;/p&gt;

&lt;p&gt;To create a save game all you need to do is run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git branch &amp;lt;save-game-name&amp;gt;
&lt;span class="c"&gt;# for example: git branch checkpoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To load a save game you just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; &amp;lt;save-game-name&amp;gt;
&lt;span class="c"&gt;# for example: git reset --hard checkpoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As with any save game out there, loading a save game means losing all your unsaved progress so be careful.&lt;/p&gt;

&lt;p&gt;But what if you're in a pickle** and forgot to save?&lt;/p&gt;

&lt;p&gt;** poor Old Vincent, GNU.&lt;/p&gt;

&lt;p&gt;Don't worry, life also has...&lt;/p&gt;

&lt;h2&gt;
  
  
  Autosaves
&lt;/h2&gt;

&lt;p&gt;Manual savegames are always handy, but in case you messed it up big and monsters are in hot pursuit, you can always fish for an autosave that can magically get you out of this situation*.&lt;/p&gt;

&lt;p&gt;* it's a million to one chance, so you know the odds are in your favor.&lt;/p&gt;

&lt;p&gt;You can check the autosaves by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reflog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will show a list of commit ids, surely one of those is a safe enough state to go back to (newest changes first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;de42f4a (HEAD -&amp;gt; master) HEAD@{0}: checkout: moving from cd7a1bb60f3c6eacba7e78cb5c665c75da19686f to master
cd7a1bb HEAD@{1}: checkout: moving from master to cd7a1bb
de42f4a (HEAD -&amp;gt; master) HEAD@{2}: reset: moving to HEAD~1
cd7a1bb HEAD@{3}: Swing axe like in style
de42f4a HEAD@{4}: Crack some skulls

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

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://git-scm.com/docs/git-reflog"&gt;reflog&lt;/a&gt; is append-only so you're pretty safe moving between those commits, but beware of some spells like &lt;code&gt;gc&lt;/code&gt; and &lt;code&gt;prune&lt;/code&gt; that might mess up with this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Never making mistakes
&lt;/h2&gt;

&lt;p&gt;You don't get to be my age in this line of work without bending a few rules. In this case, I'm talking about the rules of space and time.&lt;/p&gt;

&lt;p&gt;You just tripped mid fight and lost your dentures? It happens. And when this happens you wish you could go back and change the past.&lt;/p&gt;

&lt;p&gt;So that's exactly what you do!&lt;/p&gt;

&lt;p&gt;You concentrate really hard and do a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;base-branch&amp;gt;
&lt;span class="c"&gt;# usually: git rebase -i origin/master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That move it's called "the interactive rebase" and it helps you overcome your mistakes and always look like a legend.&lt;/p&gt;

&lt;p&gt;It usually shows something like this (oldest commit first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick d3a023c22d Crack some skulls
pick c5059d4b97 Swing axe in style
pick ef95ab8b04 Trip, fall and lose dentures
pick b0e7ec39d5 Keep fighting while looking awesome
pick 85535bb493 Sit in your throne and mope in boredom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just find the broken commit, replace the &lt;code&gt;pick&lt;/code&gt; with an &lt;code&gt;edit&lt;/code&gt;, save and exit your editor*.&lt;/p&gt;

&lt;p&gt;* as you grow old like me, trivial tasks like tying your boot laces and exiting your text editor can become impossibly difficult.&lt;/p&gt;

&lt;p&gt;Now watch where you step, fix the issue, &lt;code&gt;git add&lt;/code&gt; your files, then &lt;code&gt;git rebase --continue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Type the new commit message and carry on.&lt;/p&gt;

&lt;p&gt;A quick &lt;code&gt;git ll&lt;/code&gt; shows (newest commit first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* 4ff8e57a4d (HEAD -&amp;gt; your/branch) Sit in your throne and mope in boredom
* 6a998b0893 Keep fighting while looking awesome
* 804cfb513c Pretend to fall and dodge attack
* c5059d4b97 Swing axe in style
* d3a023c22d Crack some skulls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Better than standing up is never falling down
&lt;/h2&gt;

&lt;p&gt;But what if you tripped, fell, fought on the floor for a while, then stood up and kept fighting, is there a way to avoid this mess?*&lt;/p&gt;

&lt;p&gt;* surely your sciatica would appreciate it.&lt;/p&gt;

&lt;p&gt;Of course there is, let's say you are here (&lt;code&gt;git ll&lt;/code&gt;, newest commit first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* 4ff8e57a4d (HEAD -&amp;gt; your/branch) Stand up and recover dentures
* 6a998b0893 Fight on the floor, kick evil in the groin
* ef95ab8b04 Trip, fall and lose dentures (**)
* c5059d4b97 Swing axe in style
* d3a023c22d (origin/master) Crack some skulls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** coding barbarians usually break tests instead of losing dentures, but the pain is more or less the same.&lt;/p&gt;

&lt;p&gt;You can &lt;code&gt;git rebase -i origin/master&lt;/code&gt; (oldest commit first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick c5059d4b97 Swing axe in style
pick ef95ab8b04 Trip, fall and lose dentures
pick 6a998b0893 Fight on the floor, kick evil in the groin
pick 4ff8e57a4d Stand up and recover dentures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can move the "stand up" commit right after the "trip and fall" commit like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick c5059d4b97 Swing axe in style
pick ef95ab8b04 Trip, fall and lose dentures
pick 4ff8e57a4d Stand up and recover dentures
pick 6a998b0893 Fight on the floor, kick evil in the groin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then change the &lt;code&gt;pick&lt;/code&gt; to a &lt;code&gt;squash&lt;/code&gt;, save and exit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick c5059d4b97 Swing axe in style
pick ef95ab8b04 Trip, fall and lose dentures
squash 4ff8e57a4d Stand up and recover dentures
pick 6a998b0893 Fight on the floor, kick evil in the groin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the commit message (or don't***), save and exit again.&lt;/p&gt;

&lt;p&gt;*** if you don't want to change the message, you can use &lt;code&gt;fixup&lt;/code&gt; instead of &lt;code&gt;squash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And now the end result looks like this (&lt;code&gt;git ll&lt;/code&gt;, newest commit first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* 959eca46a8 (HEAD -&amp;gt; your/branch) Keep fighting while looking awesome
* 804cfb513c Pretend to fall and dodge attack
* c5059d4b97 Swing axe in style
* d3a023c22d (origin/master) Crack some skulls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(you can use &lt;code&gt;reword&lt;/code&gt; in &lt;code&gt;git rebase -i&lt;/code&gt; to change a commit message, like &lt;code&gt;959eca46a8&lt;/code&gt; above)&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring quests
&lt;/h2&gt;

&lt;p&gt;Every now and then you'll have to embark on a refactoring quest. Those quests are strange because if done right, after you're done no one will know they happened. And that's because they don't alter the (functional) world in any perceivable way. &lt;/p&gt;

&lt;p&gt;A responsible barbarian would ensure that the code that needs changin' is properly covered by tests. The problem with this is that when you start refactorin' you probably don't know the code that needs changin'. So more often than not, you'll finish the refactor, then check that your refactored code is properly covered by tests and if not you'd add the missing tests.&lt;/p&gt;

&lt;p&gt;Good barbarians go home satisfied with this. Great barbarians go one step further.&lt;/p&gt;

&lt;p&gt;Let's say you are here (&lt;code&gt;git ll&lt;/code&gt;, newest commit first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* 6a998b0893 (HEAD -&amp;gt; your/branch) Check if the coast is clear (write tests)
* 742408667f Inline treasure in underwear
* ba001cea18 Extract treasure
* cd2d094a79 Refactor evil away
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great barbarians would &lt;code&gt;git rebase -i origin/master&lt;/code&gt; (oldest commit first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick cd2d094a79 Refactor evil away
pick ba001cea18 Extract treasure
pick 742408667f Inline treasure in underwear
pick 6a998b0893 Check if the coast is clear (write tests)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They'd then move the last commit to the very top like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick 6a998b0893 Check if the coast is clear (write tests)
pick cd2d094a79 Refactor evil away
pick ba001cea18 Extract treasure
pick 742408667f Inline treasure in underwear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then change the first &lt;code&gt;pick&lt;/code&gt; to an &lt;code&gt;edit&lt;/code&gt; (or a &lt;code&gt;break&lt;/code&gt;), save and exit the editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;edit 6a998b0893 Check if the coast is clear (write tests)
pick cd2d094a79 Refactor evil away
pick ba001cea18 Extract treasure
pick 742408667f Inline treasure in underwear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rebase will stop right after the test commit, but before any changes to other code.&lt;/p&gt;

&lt;p&gt;This is the perfect time to run the tests. If they fail at this point you know that the refactor commits that follow did some functional change and this could very well be a bug.&lt;/p&gt;

&lt;p&gt;After your done testing and the tests pass, you can just run &lt;code&gt;git rebase --continue&lt;/code&gt;*.&lt;/p&gt;

&lt;p&gt;* and then you run the tests again for good measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your trusty companion
&lt;/h2&gt;

&lt;p&gt;Some think we barbarians are solitary creatures, they're wrong. While you're cracking skulls over here, you need someone watching your back over there*.&lt;/p&gt;

&lt;p&gt;* making sure you don't fall, swing your axe in style and take your pills.&lt;/p&gt;

&lt;p&gt;And there is one companion that is by far the best companion to bring to any adventure. But there's a catch...&lt;/p&gt;

&lt;p&gt;Remember when I was telling you to take it slowly and write wee tiny commits?&lt;/p&gt;

&lt;p&gt;Well this companion will only join your party if you agree to make tiny commits and have all those commits pass the build. Annoying, I know, but the payoff is BIG.&lt;/p&gt;

&lt;p&gt;This companion is called &lt;a href="https://git-scm.com/docs/git-bisect"&gt;git bisect&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You've been cursed with an annoying bug? You've been poisoned by a strange venom? &lt;code&gt;bisect&lt;/code&gt; is your friend!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bisect&lt;/code&gt; will go look for the solution, antidote or whatever while you go take a much needed nap.&lt;/p&gt;

&lt;p&gt;This is how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect start &amp;lt;bad-commit&amp;gt; &amp;lt;good-commit&amp;gt;
&lt;span class="c"&gt;# Usually git bisect start HEAD origin/master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will wake up &lt;code&gt;bisect&lt;/code&gt; and will pick a commit for &lt;em&gt;you&lt;/em&gt; to test. Of course no self-respecting barbarian would manually test the code when they can write a script to test it for them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect run &amp;lt;some-script-that-repros-the-bug&amp;gt;
&lt;span class="c"&gt;# for example git bisect run ./run-tests.sh the-broken-test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script you pass to &lt;code&gt;bisect run&lt;/code&gt; needs only return an exit status of &lt;code&gt;0&lt;/code&gt; if the commit is &lt;em&gt;good&lt;/em&gt; and anything else (except &lt;code&gt;125&lt;/code&gt;**) if the commit is &lt;em&gt;bad&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;** the best numbers are arbitrarily hardcoded into the fabric of the multiverse, like pi.&lt;/p&gt;

&lt;p&gt;A typical &lt;code&gt;bisect run&lt;/code&gt; script would build your code and run some repro tests.&lt;/p&gt;

&lt;p&gt;After &lt;code&gt;bisect&lt;/code&gt; starts running you can go take a nap and let it work. Once it finishes, it'll tell you which is the first commit that failed the script (usually the commit that has the bug).&lt;/p&gt;

&lt;p&gt;Once you know where evil lurks you can make a note of the commit id and then &lt;code&gt;git bisect --reset&lt;/code&gt; to go back to normal.&lt;/p&gt;

&lt;p&gt;Finally, do a swift &lt;code&gt;git rebase -i&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt; that commit and nip the evil in the bud.&lt;/p&gt;

&lt;h2&gt;
  
  
  The final test
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The old man stares intently in silence and then says:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Right, let's see what you've learned?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A cold shiver runs through the kid's spine remembering an inter-dimensional flashback of a high-school class. The kid shakes that nasty feeling while reluctantly handing over some notes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The senior barbarian reads them out loud:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git config --global alias.ll "log --decorate --graph --oneline"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git ll&lt;/code&gt; to get your bearings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git branch &amp;lt;savegame-name&amp;gt;&lt;/code&gt; to create a savegame&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git reset --hard &amp;lt;savegame-name&amp;gt;&lt;/code&gt; to load a savegame&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git reflog&lt;/code&gt; to fish for an autosave&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git rebase -i &amp;lt;base-branch&amp;gt;&lt;/code&gt; to change the past and always look like a legend&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git bisect start HEAD &amp;lt;base-branch&amp;gt;&lt;/code&gt; and then &lt;code&gt;git bisect run &amp;lt;some-script-that-repros-the-bug&amp;gt;&lt;/code&gt; to have &lt;code&gt;bisect&lt;/code&gt; work while you take a nap&lt;/li&gt;
&lt;li&gt;And most importantly: &lt;strong&gt;write wee tiny commits!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The old man cracks a wide smile and says:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Good, good, you've been paying attention.&lt;/p&gt;

&lt;p&gt;Now for the final piece of advice, keep your eyes open, your knees warm and be on the lookout for the three most important things in life: hot water, good dentistry and soft lavatory paper.&lt;/p&gt;

</description>
      <category>git</category>
      <category>productivity</category>
      <category>gnuterrypratchett</category>
      <category>barbarians</category>
    </item>
    <item>
      <title>My condition</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Wed, 02 Feb 2022 15:42:28 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/my-condition-131p</link>
      <guid>https://forem.com/pzavolinsky/my-condition-131p</guid>
      <description>&lt;p&gt;&lt;em&gt;A story about fickle memory, pirates, unnecessary details and boolean logic.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"Hey Lenny, it's me, Teddy!"&lt;/p&gt;

&lt;p&gt;Leonard looks blankly at the stranger for what seems like minutes. He then pulls a bunch of yellowed Polaroids from his pockets and checks them out. Eventually he finds a photo of this man, the photo reads "Teddy".&lt;/p&gt;

&lt;p&gt;"Hi, Teddy", he says, "did I tell you about..."&lt;/p&gt;

&lt;h2&gt;
  
  
  My condition
&lt;/h2&gt;

&lt;p&gt;"Yes, yes", Teddy cuts him off, "memory fades, never trust memory, memory's unreliable, I know the drill"&lt;/p&gt;

&lt;p&gt;"Look, Lenny, I need a favor", Teddy continues, "I'd do it myself, but you know how it is, very busy and all"&lt;/p&gt;

&lt;p&gt;"What do you need?" asks Leonard.&lt;/p&gt;

&lt;h2&gt;
  
  
  The favor
&lt;/h2&gt;

&lt;p&gt;"I need you to help me reduce a logical expression!", shouts Teddy excitedly.&lt;/p&gt;

&lt;p&gt;If Leonard could remember, he'd get the feeling Teddy &lt;em&gt;always&lt;/em&gt; has an agenda, alas, he can't.&lt;/p&gt;

&lt;p&gt;"Uhm", replies Leonard, "is that the whole business with the &lt;em&gt;ands&lt;/em&gt; and the &lt;em&gt;ors&lt;/em&gt; and the &lt;em&gt;trues&lt;/em&gt; and the &lt;em&gt;falses&lt;/em&gt;?"&lt;/p&gt;

&lt;p&gt;"Yes! That's exactly it... except this might be a bit more complex than your typical run-of-the-mill expression", Teddy looks amused, "Are you familiar with De Morgan's laws?"&lt;/p&gt;

&lt;p&gt;Leonard looks blankly for a couple of seconds, "I can't say I am"&lt;/p&gt;

&lt;p&gt;Teddy saw this coming so he continues, "OK, bring a chair, I'll tell you a story. I'm pretty sure &lt;a href="https://en.wikipedia.org/wiki/Augustus_De_Morgan"&gt;De Morgan&lt;/a&gt; wasn't a pirate but for the purpose of this story he might as well be one..."&lt;/p&gt;

&lt;h2&gt;
  
  
  Denial in the high seas
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(Teddy's story)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Back in the day where pirates were the rage, there was one pirate captain called De Morgan. Now De Morgan's crew was very well known in the seven seas as a bunch of weirdos.&lt;/p&gt;

&lt;p&gt;They were very proficient in all their piraty skills, all but one: their pirate lingo.&lt;/p&gt;

&lt;p&gt;They were obsessed with negations. You couldn't get a straight answer from them even if you bribed them with grog. You couldn't even begin to disbelieve the lengths they'd go not to avoid saying things in a way not simple.&lt;/p&gt;

&lt;p&gt;Needless to say they got on De Morgan's nerves. Commanding this crew was proving more and more difficult. He needed to find a way to make this work.&lt;/p&gt;

&lt;p&gt;He though long and hard, while the crew plundered, pillaged and had the most outrageous philosophical discussions on deck.&lt;/p&gt;

&lt;p&gt;Eventually Captain De Morgan created a bunch of rules to help him understand his crew:&lt;/p&gt;

&lt;p&gt;1) When they say "Nay (A or B)" that is the same as "(Nay A) and (Nay B)"&lt;br&gt;
2) When they say "Nay (A and B)" that is the same as "(Nay A) or (Nay B)"&lt;/p&gt;

&lt;p&gt;And because back then a Captain's word was law, these became known as &lt;a href="https://en.wikipedia.org/wiki/De_Morgan%27s_laws"&gt;De Morgan's laws&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;not (A or  B) = (not A) and (not B)
not (A and B) = (not A) or  (not B)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Teddy concludes his story and waits for it to sink in)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Only facts go in the notes
&lt;/h2&gt;

&lt;p&gt;Leonard thinks about this for a while and asks Teddy an unexpected question, "How can you be sure those laws actually work in practice? How can you trust them?"&lt;/p&gt;

&lt;p&gt;The question catches Teddy off guard but he manages to come up with an answer, "I can tell you, but first I'll need to tell you about..."&lt;/p&gt;

&lt;h2&gt;
  
  
  The place where truth is stored
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(Teddy pulls out a piece of paper and starts another monologue)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Take a very simple expression, for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A and B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We all know the values for &lt;code&gt;A&lt;/code&gt; can be either &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;, and the same goes for &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We could put all those values right after the expression above and we'd get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A and B
-------
T     T    # both A and B are true
T     F    # A is true, B is false
F     T    # A is false, B is true
F     F    # both A and B are false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we also compute the value of the whole expression and put that under the &lt;code&gt;and&lt;/code&gt; operator we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A and B
-------
T (T) T
T (F) F
F (F) T
F (F) F
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if we negate the expression above, we get &lt;code&gt;not (A and B)&lt;/code&gt;, and we can also compute the values of this new expression for every possible combination of values for &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;not (A and B)
-------------
[F] (T (T) T)    # `[]` is the the opposite of `()`
[T] (T (F) F)
[T] (F (F) T)
[T] (F (F) F)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So in other words...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;value of A | value of B | not (A and B)
-----------+------------+---------------
     T     |      T     |       F
     T     |      F     |       T
     F     |      T     |       T
     F     |      F     |       T
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll get back to this in a second, but lets think about something else.&lt;/p&gt;

&lt;p&gt;What would be the values of &lt;code&gt;A or B&lt;/code&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A or  B
-------
T (T) T
T (T) F
F (T) T
F (F) F
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, if we negate both &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(not A) or  (not B)
------------------
([F] T) (F) ([F] T)
([F] T) (T) ([T] F)
([T] F) (T) ([F] T)
([T] F) (T) ([T] F)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other words...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;value of A | value of B | not (A and B) | (not A) or (not B)
-----------+------------+---------------+--------------------
     T     |      T     |       F       |         F
     T     |      F     |       T       |         T
     F     |      T     |       T       |         T
     F     |      F     |       T       |         T
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, for every possible combination of values of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;, both expressions are equivalent!&lt;/p&gt;

&lt;p&gt;That's what De Morgan saw. You can do the same analysis for the other law.&lt;/p&gt;

&lt;p&gt;These little table things are called &lt;a href="https://en.wikipedia.org/wiki/Truth_table"&gt;Truth Tables&lt;/a&gt;, by the way.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Just when Teddy was about to sourly comment on the futility of explaining this whole process, Leonard surprises him yet again...)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Trust as a building block
&lt;/h2&gt;

&lt;p&gt;Leonard takes out his camera, takes a picture of De Morgan's laws and writes below the picture, "You can trust these, they work, you've seen the demonstration".&lt;/p&gt;

&lt;p&gt;"What are you doing?" asks Teddy curiously.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Leonard's explanation)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I have a method, because of my condition, you know. If every time I need to use these laws I have to do the same demonstration, I  wouldn't be able to get &lt;em&gt;anything&lt;/em&gt; done.&lt;/p&gt;

&lt;p&gt;This way I can &lt;em&gt;trust&lt;/em&gt; that things just work and build upon them. I don't need to see the gory details of everything every time.&lt;/p&gt;

&lt;p&gt;I call this method...&lt;/p&gt;

&lt;h2&gt;
  
  
  The Abstraction Boundary
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(...Leonard's explanation continues...)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The annotated Polaroid acts as an abstraction interface.&lt;/p&gt;

&lt;p&gt;Only things that I &lt;em&gt;trust&lt;/em&gt; go in the Polaroids.&lt;/p&gt;

&lt;p&gt;Because I &lt;em&gt;trust&lt;/em&gt; these things, I can just &lt;em&gt;build&lt;/em&gt; upon that knowledge without being bothered by the &lt;em&gt;implementation details&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If every time I &lt;em&gt;use&lt;/em&gt; something I first need to stop and think about how that something is &lt;em&gt;implemented&lt;/em&gt;, my time would run out before getting anything done.&lt;/p&gt;

&lt;p&gt;The implementation details are important in context. Looking in, drilling down, they make sense. Looking up, abstracting away, they don't.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Leonard stays quiet and after a while he asks...)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Did I ever tell you about...
&lt;/h2&gt;

&lt;p&gt;"Yes, yes, Sammy Jankis, I know" interrupts Teddy.&lt;/p&gt;

&lt;p&gt;"No, no, I mean, did I ever tell you about Ireneo Funes?" Leonard continues, "I read about him &lt;a href="https://en.wikipedia.org/wiki/Funes_the_Memorious"&gt;somewhere&lt;/a&gt;"&lt;/p&gt;

&lt;h2&gt;
  
  
  To think is to forget
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(Leonard tells the story of Funes)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It turns out this Funes person could remember everything in excruciating detail. He suffered in some ways from the opposite of my condition.&lt;/p&gt;

&lt;p&gt;He was so obsessed with the details that he was almost incapable of creating new thoughts.&lt;/p&gt;

&lt;p&gt;Contemplation prevented composition.&lt;/p&gt;

&lt;p&gt;"To think is to forget the differences, to generalize, to abstract" or so I read somewhere.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Leonard trails off his face blank once again)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The request
&lt;/h2&gt;

&lt;p&gt;Teddy seizes this lapse of distraction to slip another Polaroid into Leonard's pocket. The photo shows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (A) then (B) = (not A) or (B)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Ok, so anyway about my expression, I need you to help me reduce this" Teddy says as he hands Leonard a piece of paper.&lt;/p&gt;

&lt;p&gt;The paper reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(C) and (not D) and (not J)
(not C) and (D) and (not J)
(not C) and (not D) and (J)
if A and ((B or ((C or D) and E))) then F
if A and (not (B or ((C or D) and E))) and (G and ((H and (not I)) or (not H))) then F
if A and (not (B or ((C or D) and E))) and (not (G and ((H and (not I)) or (not H)))) and H then L
if A and (not (B or ((C or D) and E))) and (not (G and ((H and (not I)) or (not H)))) and (not H) then M
if (not A) and J then K
if (not A) and (not J) and (C or D) and ((not E) and (not B)) then K
if (not A) and (not J) and (C or D) and (not ((not E) and (not B))) then F
if (not A) and (not J) and (not (C or D)) then F
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leonard looks at the paper confused but when he looks up Teddy is gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why would you expect anything else?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(Some time later)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"Hey Lenny, it's me, Teddy!"&lt;/p&gt;

&lt;p&gt;Leonard looks blankly at the stranger for what seems like minutes. He then pulls a bunch of yellowed Polaroids from his pockets and checks them out. Eventually he finds a photo of this man, the photo reads "Teddy, check your left pocket".&lt;/p&gt;

&lt;p&gt;Leonard checks his left pocket and pulls out a crumpled piece of paper, he reads it carefully and then addresses the stranger in front him.&lt;/p&gt;

&lt;p&gt;"Hi, Teddy", he says, "you must be here about your expression..."&lt;/p&gt;

&lt;p&gt;"Yes, yes!" says Teddy excitedly, "did you manage to reduce it?!?!"&lt;/p&gt;

&lt;p&gt;"Oh yes I did", answers Leonard.&lt;/p&gt;

&lt;p&gt;"Ok, what is it, Leonard, this is very important, what's the answer?" asks Teddy almost losing his patience.&lt;/p&gt;

&lt;p&gt;Leonard looks blank for a second and then answers...&lt;/p&gt;

&lt;p&gt;"I can't remember"&lt;/p&gt;

</description>
      <category>memory</category>
      <category>pirates</category>
      <category>abstraction</category>
      <category>logic</category>
    </item>
    <item>
      <title>Those weird humans</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Tue, 23 Nov 2021 21:11:19 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/those-weird-humans-21ho</link>
      <guid>https://forem.com/pzavolinsky/those-weird-humans-21ho</guid>
      <description>&lt;p&gt;A bunch of young elves sit in silence by the fireplace of a wooden cabin in the north pole.&lt;/p&gt;

&lt;p&gt;Eventually a tiny elf called Galadriel breaks the silence, "Grandpapa, can you tell us a story?"&lt;/p&gt;

&lt;p&gt;"Sure thing, kiddo!" responds an elderly man with a long white beard, "I'll make myself a hot cocoa and be right there with you."&lt;/p&gt;

&lt;p&gt;The old man approaches a cast-iron stove upon which sits a kettle and a pot of milk. A few minutes later, cocoa in hand, the old man sits in a rocking chair by the fireplace and asks the elves "Which story would you like to hear?"&lt;/p&gt;

&lt;p&gt;"I know! I know!" says another tiny elf called Legolas, "tell us a story about..."&lt;/p&gt;

&lt;h2&gt;
  
  
  Those weird humans
&lt;/h2&gt;

&lt;p&gt;"Ho ho, where do I even start!" the old man laughs, "I know, I'll tell you a story of good intentions, people getting carried away, broken toys and forgetfulness."&lt;/p&gt;

&lt;p&gt;"Wow that sounds amazing!" young Galadriel shouts excitedly.&lt;/p&gt;

&lt;p&gt;"The story begins not long ago, in this galaxy" the old man says while pulling the cowl of his robe over his head, "Humans used to worship this &lt;em&gt;thing&lt;/em&gt; called OOP."&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;Up?&lt;/em&gt;" asks Legolas.&lt;/p&gt;

&lt;p&gt;"No no, OOP" the old man responds.&lt;/p&gt;

&lt;p&gt;"Whoop?" Legolas tries again.&lt;/p&gt;

&lt;p&gt;"Ho ho, that's certainly closer, but no, this is O-O-P which stands for Object-Oriented Programming."&lt;/p&gt;

&lt;p&gt;The elves stare in awe until Arwen says "tell us more about..."&lt;/p&gt;

&lt;h2&gt;
  
  
  Oh-Oh Pee
&lt;/h2&gt;

&lt;p&gt;Outside it's snowing, but this is not the usual snow. For some magical reason, around this cabin it snows all the time and yet the height of the snow is always exactly right. Ideal for building snow people and friendly snowball matches, but never high enough that you need to spend hours shoveling your backyard and over-seasoning your driveway with a ton of salt.&lt;/p&gt;

&lt;p&gt;"Back then" the old man continues, "humans decided that objects in the real world only had two properties: &lt;em&gt;state&lt;/em&gt; and &lt;em&gt;behavior&lt;/em&gt;."&lt;/p&gt;

&lt;p&gt;"Behavior was good, everyone wanted &lt;em&gt;behavior&lt;/em&gt;, but state, oh no, state was something to be ashamed of, something to be &lt;em&gt;hidden&lt;/em&gt;."&lt;/p&gt;

&lt;h2&gt;
  
  
  Something hidden
&lt;/h2&gt;

&lt;p&gt;"They invented this thing called &lt;em&gt;encapsulation&lt;/em&gt; that meant that objects would hide their state so that no one could know about it."&lt;/p&gt;

&lt;p&gt;"Those were strange times indeed, the sole purpose of objects was to &lt;em&gt;do&lt;/em&gt; stuff, not just sit around. There was not time for quiet contemplation back then."&lt;/p&gt;

&lt;p&gt;"Eventually they started grouping objects together, &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;solid&lt;/a&gt; objects and animals were very popular back then, although humans were obsessed with making all of them &lt;a href="https://dev.to/acroynon/inheritance-and-polymorphism-33fi"&gt;bark()&lt;/a&gt; for some reason."&lt;/p&gt;

&lt;h2&gt;
  
  
  Going too far
&lt;/h2&gt;

&lt;p&gt;"Humans are excitable creatures. They have a saying that goes pretty much like this: when you have a new hammer everything looks like a nail."&lt;/p&gt;

&lt;p&gt;"And, so they started seeing objects everywhere. Animals, People, Cars, those kind of made sense, but eventually they got carried away. Numbers, functions and even abstracts like &lt;a href="https://i.ytimg.com/vi/Uw3AghZHCdk/maxresdefault.jpg"&gt;dignity&lt;/a&gt; became objects."&lt;/p&gt;

&lt;p&gt;"Back then the only way to accomplish anything was to pass objects around, but given that objects had all those enticing methods you could call, it took an enormous amount of restrain to write &lt;a href="https://en.wikipedia.org/wiki/Pure_function"&gt;pure functions&lt;/a&gt;."&lt;/p&gt;

&lt;p&gt;"It's like when you kids share your toys. They eventually break and when they do, it's hard to tell who broke it, where did it break and where are all of its pieces so that you can try to put it back together."&lt;/p&gt;

&lt;p&gt;"Last week I shared my wooden car with Legolas and he broke it!" complains a little elf called Elrond.&lt;/p&gt;

&lt;p&gt;"I did not!" says Legolas.&lt;/p&gt;

&lt;p&gt;"You did so!"&lt;/p&gt;

&lt;p&gt;"I did not!"&lt;/p&gt;

&lt;p&gt;This goes on for a while until the old man continues the story, "...so apparently all those broken toys and impure functions had an unprecedented effect on the world, they triggered a..."&lt;/p&gt;

&lt;h2&gt;
  
  
  World-wide iron deficiency
&lt;/h2&gt;

&lt;p&gt;"It turns out that most objects in the world were suffering from an iron deficiency that turned them into &lt;a href="https://martinfowler.com/bliki/AnemicDomainModel.html"&gt;anemic objects&lt;/a&gt;, leaking state all over the place."&lt;/p&gt;

&lt;p&gt;"Those were dire times to be an object, and almost everything was one."&lt;/p&gt;

&lt;p&gt;"At some point humans got fed up with objects, leaking or otherwise and decided everything about OOP was wrong. They concluded that OOP really stands for Outrageously Overly-complicated Programs and moved on without a second thought."&lt;/p&gt;

&lt;p&gt;"...aaaand that concludes our story for today!"&lt;/p&gt;

&lt;p&gt;"But if they no longer used objects, did the have another way of solving problems?" little Elrond asks.&lt;/p&gt;

&lt;p&gt;"Yes, lots" answers the old man, "like functional, logical, procedural, JavaScript..."&lt;/p&gt;

&lt;p&gt;"Grandpapa" Galadriel moans with the most heart-warming sad-kitten face, "could we have one more story before bed time, please? Pretty please?"&lt;/p&gt;

&lt;p&gt;"Alright, kiddo, but this is the last one!"&lt;/p&gt;

&lt;h2&gt;
  
  
  An older, newer story
&lt;/h2&gt;

&lt;p&gt;"Before humans started worshiping OOP (or was it after?) they were obsessed with something called FP."&lt;/p&gt;

&lt;p&gt;"What is it with humans and all this &lt;em&gt;pee&lt;/em&gt;?" asks Legolas.&lt;/p&gt;

&lt;p&gt;"Ho ho ho, FP stands for Functional Programming and it was quite different from OOP."&lt;/p&gt;

&lt;p&gt;"Grandpapa" Galadriel says, "please tell us more about..."&lt;/p&gt;

&lt;h3&gt;
  
  
  Eph pee
&lt;/h3&gt;

&lt;p&gt;"Well" the old man continues, "these humans got radically different views about state and behavior."&lt;/p&gt;

&lt;p&gt;"For them state was something to put on display, where anyone could see it, but there was a catch, no one was allowed to touch it or otherwise &lt;em&gt;change&lt;/em&gt; it."&lt;/p&gt;

&lt;p&gt;"They called this rule &lt;em&gt;immutability&lt;/em&gt;."&lt;/p&gt;

&lt;p&gt;"Wooo" all the elves say in unison, with amazement in their eyes.&lt;/p&gt;

&lt;p&gt;"Now the key to FP was functions, but not just functions &lt;a href="https://en.wikipedia.org/wiki/Pure_function"&gt;&lt;em&gt;pure&lt;/em&gt; functions&lt;/a&gt;."&lt;/p&gt;

&lt;p&gt;"Remember that because of immutability you were not allowed to change things, so to get things done you'd use pure functions that take state and produce new things."&lt;/p&gt;

&lt;p&gt;"But" Arwen interrupts, "how could you possible &lt;em&gt;do&lt;/em&gt; stuff when you're not allowed to &lt;em&gt;change&lt;/em&gt; stuff?"&lt;/p&gt;

&lt;p&gt;"Ho ho ho, great question!" excitedly replies the old man.&lt;/p&gt;

&lt;h3&gt;
  
  
  The unexpected
&lt;/h3&gt;

&lt;p&gt;"It turns out that humans also asked the same question, how can we actually &lt;em&gt;do&lt;/em&gt; stuff if we cannot &lt;em&gt;change&lt;/em&gt; stuff?"&lt;/p&gt;

&lt;p&gt;"They tried really hard to come up with an answer to this question, tried different approaches but nothing seemed to work."&lt;/p&gt;

&lt;p&gt;"They were getting desperate, they were prepared to sacrifice anything in the altar of purity and immutability but this problem seemed impossible to solve."&lt;/p&gt;

&lt;p&gt;"And so, they did the unexpected, something no one could've foreseen..."&lt;/p&gt;

&lt;p&gt;"What was it Granddaddy??? What was &lt;em&gt;it&lt;/em&gt;?!" all the elves ask excitedly.&lt;/p&gt;

&lt;p&gt;"They..."&lt;/p&gt;

&lt;h3&gt;
  
  
  Turned to the occult
&lt;/h3&gt;

&lt;p&gt;"They realized that the only way to solve their predicament was by tapping into raw magic, into the most occult and forbidden of sciences: Math."&lt;/p&gt;

&lt;p&gt;"They tried casting all sorts of math spells until one day, after a lot of effort and casualties, they managed to conjure an artifact of ultimate power."&lt;/p&gt;

&lt;p&gt;"This artifact, forged in the fires of &lt;a href="https://youtu.be/I8LbkfSSR58"&gt;Category Theory&lt;/a&gt; was called the Monad!"&lt;/p&gt;

&lt;p&gt;"Now Category Theory is a bucolic valley right next to the wine country region of Hell. If you're ever in the area make sure you stop and visit."&lt;/p&gt;

&lt;p&gt;"But I digress back to the Monad..."&lt;/p&gt;

&lt;h2&gt;
  
  
  Shoulda, woulda, coulda
&lt;/h2&gt;

&lt;p&gt;"These humans immediately became obsessed with these monads. &lt;a href="https://hackage.haskell.org/package/base-4.16.0.0/docs/Data-Maybe.html"&gt;Maybe&lt;/a&gt; it was that monads look deceptively simple. It was &lt;a href="https://hackage.haskell.org/package/base-4.16.0.0/docs/Data-Either.html"&gt;either&lt;/a&gt; that or that they felt &lt;a href="https://hackage.haskell.org/package/base-4.16.0.0/docs/Data-Maybe.html#v:Just"&gt;just&lt;/a&gt; &lt;a href="https://hackage.haskell.org/package/base-4.16.0.0/docs/Data-Either.html#v:Right"&gt;right&lt;/a&gt;."&lt;/p&gt;

&lt;p&gt;"Whatever the reason, monads were too powerful an artifact to wield. They had the power to alter the fabric of reality and &lt;em&gt;change&lt;/em&gt; the immutable, make &lt;em&gt;state&lt;/em&gt; appear out of nowhere and to &lt;em&gt;run&lt;/em&gt; code that couldn't run."&lt;/p&gt;

&lt;p&gt;"One of the most powerful monads out there was called &lt;a href="https://hackage.haskell.org/package/base-4.16.0.0/docs/System-IO.html#t:IO"&gt;IO&lt;/a&gt;."&lt;/p&gt;

&lt;p&gt;"Hey ho?" asks Legolas.&lt;/p&gt;

&lt;p&gt;"I'm pretty sure that's the &lt;a href="https://youtu.be/268C3N2dDYk"&gt;punk rock&lt;/a&gt; monad of &lt;a href="https://youtu.be/HI0x0KYChq4?t=78"&gt;dwarves&lt;/a&gt;" the old man explains, "this one was called &lt;em&gt;eye oh&lt;/em&gt; which stands for Input-Output."&lt;/p&gt;

&lt;h2&gt;
  
  
  Hasta la vista, FP / I'll be back
&lt;/h2&gt;

&lt;p&gt;"Anyway, every monad on it's own was an artifact of untamed raw power and to be able to combine them required impossible amounts of &lt;a href="http://book.realworldhaskell.org/read/monad-transformers.html"&gt;transformation magic&lt;/a&gt;. But even then being able to &lt;a href="https://hackage.haskell.org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Class.html#v:lift"&gt;lift&lt;/a&gt; all those monads required an almost superhuman strength."&lt;/p&gt;

&lt;p&gt;"Eventually those humans realized they were getting ripped with all that heavy lifting so most of them decided to pursue a more satisfying career as Olympic heavy-weight champions, body builders, Hollywood superstars, pop-culture icons, restaurateurs and some even decided to dabble in politics."&lt;/p&gt;

&lt;p&gt;"And so, once more humans forgot about FP and moved on to the next new shiny old thing."&lt;/p&gt;

&lt;p&gt;"I sometimes think that being human is about trying to find balance by moving exclusively between the extremes."&lt;/p&gt;

&lt;p&gt;"And that is the end of that story."&lt;/p&gt;

&lt;h2&gt;
  
  
  Lots of jumping around
&lt;/h2&gt;

&lt;p&gt;"Granddaddy" asks Arwen, "was there something before Eph Pee and Oh-Oh Pee? Maybe some other &lt;em&gt;pee&lt;/em&gt;?"&lt;/p&gt;

&lt;p&gt;"In the very beginning things were &lt;em&gt;very&lt;/em&gt; strange, people would spend all their time randomly &lt;a href="https://c9x.me/x86/html/file_module_x86_id_176.html"&gt;moving&lt;/a&gt; things around and &lt;a href="https://en.wikipedia.org/wiki/JMP_(x86_instruction)"&gt;jumping&lt;/a&gt; from here to there for no discernible reason."&lt;/p&gt;

&lt;p&gt;"But this story will have to wait, kiddos, now it's time for bed, tomorrow we have a big day ahead of us. Lots of toys to compile, assemble, link and debug."&lt;/p&gt;

&lt;p&gt;And so the little elves go to bed and the old man walks out to his bedroom.&lt;/p&gt;

&lt;h2&gt;
  
  
  E-pee-log
&lt;/h2&gt;

&lt;p&gt;A couple of minutes later, the old man emerges from his room in his robe and slippers and looks at you, yes, &lt;em&gt;you&lt;/em&gt; the reader.&lt;/p&gt;

&lt;p&gt;"You're still here?" he asks shocked, "it's over, go home!"&lt;/p&gt;

&lt;p&gt;Seeing that you are not leaving he continues.&lt;/p&gt;

&lt;p&gt;"Oh, well, since you're still here, let me just say: you keep coding, code in whatever language and paradigm makes you happy and gets you excited."&lt;/p&gt;

&lt;p&gt;"Don't worry about what people think or the hype, there's a lot of satisfaction to be had in punching holes in &lt;a href="https://en.wikipedia.org/wiki/Computer_programming_in_the_punched_card_era#/media/File:FortranCardPROJ039.agr.jpg"&gt;Fortran cardboard cards&lt;/a&gt;."&lt;/p&gt;

&lt;p&gt;"Learn about other ways of doing things, the crazier the better, then share what you've learned with others!"&lt;/p&gt;

&lt;p&gt;"That's it, it's truly over now, go home, go share a (virtual or real) meal with friends and family."&lt;/p&gt;

&lt;p&gt;"And, if you happen to find yourself at home, alone, then order pizza, watch a movie and use your toys to build traps and ward off some wet bandits."&lt;/p&gt;

&lt;p&gt;"Happy holidays!"&lt;/p&gt;

</description>
      <category>oop</category>
      <category>functional</category>
      <category>story</category>
      <category>wrongelves</category>
    </item>
    <item>
      <title>The testing genie</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Mon, 08 Nov 2021 12:51:16 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/the-testing-genie-52b8</link>
      <guid>https://forem.com/pzavolinsky/the-testing-genie-52b8</guid>
      <description>&lt;p&gt;After years of hard work you decide to take a well deserved vacation. You book tickets to a tropical paradise with long quiet beaches, white sand and clear blue water.&lt;/p&gt;

&lt;p&gt;One the second day of your vacation, as you're strolling down the beach, you see a glint of metal in the distance. There's something buried in the sand, you think. Maybe it's treasure or an artifact of pure evil... only one way to find out!&lt;/p&gt;

&lt;p&gt;So you rush to the bright metal thing and sure enough you find an ancient metal oil lamp. Countless childhood stories prepared us well for this type of situation, you think, and you proceed to polish it with your sandy towel.&lt;/p&gt;

&lt;p&gt;In a matter of seconds a creature of pure elemental essence appears in front of you, materializing out of nowhere.&lt;/p&gt;

&lt;p&gt;"Howdy!", it says.&lt;/p&gt;

&lt;p&gt;"Ehm, hi...", you reply, uncertain, "who...what are you?"&lt;/p&gt;

&lt;p&gt;"Oh, I'm...&lt;/p&gt;

&lt;h2&gt;
  
  
  The testing genie
&lt;/h2&gt;

&lt;p&gt;"The testing genie", you repeat slowly, "what kind of thing is that?!?"&lt;/p&gt;

&lt;p&gt;"Ha, I'm the one that will fulfill all your testing wishes, as long as those are three", it replies, matter-of-factly.&lt;/p&gt;

&lt;p&gt;"All my testing wishes...", you say out loud absentmindedly, thinking about the infinite choices ahead of you. This is too important, you need some sort of guide in order to ask for the right thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lidless eye
&lt;/h2&gt;

&lt;p&gt;"I got it!" you shout, basking in this epiphany you just had, "You know the testing pyramid? We should use that!"&lt;/p&gt;

&lt;p&gt;"Is that the ominous looking pyramid with a lidless eye in the back of the dollar bill?" it asks with the slightest hint of sarcasm.&lt;/p&gt;

&lt;p&gt;"What? no! I'm talking about the testing pyramid, you know, unit tests at the bottom, integration on top of that..." you reply patiently.&lt;/p&gt;

&lt;p&gt;"Oh, &lt;em&gt;the&lt;/em&gt; pyramid, the one that mandates without a shadow of doubt the &lt;em&gt;only&lt;/em&gt; way of doing proper testing, regardless of the context. The one that prescribes the &lt;em&gt;right&lt;/em&gt; way of doing things, so that we avoid pointless discussions. &lt;em&gt;That&lt;/em&gt; pyramid...", it says cracking a sly smile and rubbing its hands, "this is going to be &lt;em&gt;fun&lt;/em&gt;!"&lt;/p&gt;

&lt;p&gt;For a split second there you're sure you saw a glint of evil in its eyes, but you can't be sure so you just power through, this is too good to second guess yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  First wish: full coverage
&lt;/h2&gt;

&lt;p&gt;"I want unit tests, but not just that, I want full coverage!" you shout excited.&lt;/p&gt;

&lt;p&gt;"So be it", it replies as it vanishes in a puff of smoke.&lt;/p&gt;

&lt;p&gt;You look down at your hands and what you thought was a lamp is just a rock.&lt;/p&gt;

&lt;p&gt;You dismiss this whole episode as a figment of your imagination. Maybe yesterday's cocktail party did pack a punch after all.&lt;/p&gt;

&lt;h2&gt;
  
  
  A strange gift
&lt;/h2&gt;

&lt;p&gt;The rest of your vacation is pretty much uneventful and a few days later you're back at home, energized and ready to work.&lt;/p&gt;

&lt;p&gt;You blow the dust collecting on your laptop, open it and pull the latest changes from your repo.&lt;/p&gt;

&lt;p&gt;Much to your surprise there's a suspicious commit that was pushed directly to your main branch.&lt;/p&gt;

&lt;p&gt;The commit was authored by a user id you've never seen before, someone call &lt;code&gt;dj-1nn&lt;/code&gt;. A quick peek at the commit reveals 60 thousand files added to your testing directory.&lt;/p&gt;

&lt;p&gt;Still shocked you spin up your test driver, setup code coverage and let it run.&lt;/p&gt;

&lt;p&gt;Shortly after you get the results. You stare at the screen in disbelief for a couple of minutes, the results show:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;60000 scenarios (60000 passed)

========= Coverage summary =========
Statements   : 100%
Branches     : 100%
Functions    : 100%
Lines        : 100%
====================================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow, this is amazing! Full coverage and all you had to do was wish for it. If only you had known this years ago.&lt;/p&gt;

&lt;p&gt;From now on you make the resolution of always rubbing any metal object you find buried in the sand. Who knows, maybe next time you'll find the &lt;a href="https://dev.to/pzavolinsky/the-ultimate-man-cave-15ff"&gt;bat-shaped genie of abstraction&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The price of hubris
&lt;/h2&gt;

&lt;p&gt;Back to the code, you decide that full coverage means bugs are a thing of the past.&lt;/p&gt;

&lt;p&gt;How could you possibly have bugs when every single piece of your code is covered by tests?&lt;/p&gt;

&lt;p&gt;Emboldened by this protective shield of awesome you decide any other form of testing is obsolete. Why even bother testing locally?&lt;/p&gt;

&lt;p&gt;So you code some changes, run the tests, of course they pass, you rockstar you. And then you blindly push changes to production.&lt;/p&gt;

&lt;p&gt;A couple of hours later the customer support people are knocking at your door. They don't seem happy and they carry torches and pitchforks.&lt;/p&gt;

&lt;p&gt;You open the door in shock, still wondering what could possibly go wrong in this testing utopia.&lt;/p&gt;

&lt;p&gt;It turns out they are flooded with bug reports and production is on fire. You promptly don your firefighting attire.&lt;/p&gt;

&lt;p&gt;With a bunch of skillfully crafted &lt;a href="https://git-scm.com/docs/git-revert"&gt;git reverts&lt;/a&gt; you manage to put out the fires.&lt;/p&gt;

&lt;h2&gt;
  
  
  The aftermath
&lt;/h2&gt;

&lt;p&gt;After you mange to kick all those support folk out of your home, you decide to dig deeper into what's going on.&lt;/p&gt;

&lt;p&gt;You pull up that mysterious commit and inspect some tests at random.&lt;/p&gt;

&lt;p&gt;You quickly realize what's going on, even though the tests do cover the code, they have absolutely no assertions!&lt;/p&gt;

&lt;p&gt;You could change pretty much anything and the tests would still pass. You suspect you could even remove a random bunch of code and the tests would also pass.&lt;/p&gt;

&lt;p&gt;You decide to actually check this, you open a file at random flip a bunch of &lt;code&gt;if&lt;/code&gt;s, delete some loops and run the tests.&lt;/p&gt;

&lt;p&gt;The results speak for themselves:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;60000 scenarios (60000 passed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can feel your temperature rising. 60k tests, no assertions. How long will it take you to write proper assertions?&lt;/p&gt;

&lt;p&gt;You run the numbers in your head, 60k tests, about 3 or 4 assertions per test... there's&lt;/p&gt;

&lt;h2&gt;
  
  
  Only one possible solution
&lt;/h2&gt;

&lt;p&gt;After a long wait at the airport, a busy flight and a hot and humid taxi you're back at the beach looking left and right for that cursed lamp.&lt;/p&gt;

&lt;p&gt;Eventually you manage to find it and rub it angrily.&lt;/p&gt;

&lt;p&gt;"Howdy!", the genie says cheerfully, "back so soon?"&lt;/p&gt;

&lt;p&gt;"Sixty thousand unit tests, and &lt;em&gt;no&lt;/em&gt; assertions?!?!" you shout at the top of your lungs.&lt;/p&gt;

&lt;p&gt;Other people look at you shouting at the emptiness in front of you and dismiss you as yet another crazy sand dweller.&lt;/p&gt;

&lt;p&gt;"Well...", it replies, "you didn't mention anything about assertions".&lt;/p&gt;

&lt;p&gt;"I-want-assertions!", you fall to your knees and repeat sobbing, "I just wanted assertions *sob*".&lt;/p&gt;

&lt;p&gt;"So be it", it replies as it vanishes again in a puff of smoke.&lt;/p&gt;

&lt;p&gt;By now you know the drill, lamp becomes rock, etc. So you go back to your hotel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second wish: all those snapshots
&lt;/h2&gt;

&lt;p&gt;This time you brought your laptop with you, so you hastily sign in and &lt;code&gt;git pull&lt;/code&gt; the latest changes.&lt;/p&gt;

&lt;p&gt;As expected there's a new &lt;code&gt;dj-1nn&lt;/code&gt; commit, this one changes the 60k files in your testing directory and adds 60k files with snapshots for every single scenario.&lt;/p&gt;

&lt;p&gt;Apparently the genie went for snapshot testing. Surely those snapshots are the ultimate form of assertion, they check absolutely everything.&lt;/p&gt;

&lt;p&gt;Less than 100ms since you had that thought you get pinged. Looks like there's a bug in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  A picture of insanity
&lt;/h2&gt;

&lt;p&gt;"What now??!?!" you scream at no one in particular. You pull the bug report and it looks legit. After a few minutes you can even repro locally.&lt;/p&gt;

&lt;p&gt;Full coverage and snapshot assertions for &lt;em&gt;everything&lt;/em&gt;, what is going on?!?!?&lt;/p&gt;

&lt;p&gt;You have to postpone digging into that conundrum so that you can focus on the bug fix at hand.&lt;/p&gt;

&lt;p&gt;You quickly spot the problem and correct it. You're about to commit and decide to run the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;60000 scenarios (4 failed, 59996 passed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You were just fixing a bug but it looks like you broke 4 tests in the process, this is going to be a long day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watching the watchmen
&lt;/h2&gt;

&lt;p&gt;You decide to open the four failing tests.&lt;/p&gt;

&lt;p&gt;It only takes a cursory glance at them to see that there's no rhyme or reason to those tests, hundreds of lines of mocks, stubs and test doubles, functions being called to produce intermediate values that are used further along the test. A beautiful example of copy/paste in its prime.&lt;/p&gt;

&lt;p&gt;At least you can check snapshots and see if you can work your way back to what failed.&lt;/p&gt;

&lt;p&gt;You open one such snapshot and your editor for a millisecond considers opening up a hex editor, until it realizes the file is actually a humongous and incomprehensible &lt;a href="https://upload.wikimedia.org/wikipedia/en/f/f7/Jason_Voorhees_%28Ken_Kirzinger%29.jpg"&gt;JSON file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You are running out of options and out of time so you decide your code is sound. You delete the four failing snapshots and re-create them with the current values. Push to prod and get it over with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not everything is broken
&lt;/h2&gt;

&lt;p&gt;A couple of minutes later you get a new bug report. You take a look and all signs point to your last fix. It seems one of those 4 broken tests was actually testing something you shouldn't have broken.&lt;/p&gt;

&lt;p&gt;You feel you don't have enough hands to &lt;a href="https://upload.wikimedia.org/wikipedia/commons/3/3b/Paris_Tuileries_Garden_Facepalm_statue.jpg"&gt;face-palm&lt;/a&gt; yourself.&lt;/p&gt;

&lt;p&gt;You quickly fix the code, delete and recreate the broken snapshots and push.&lt;/p&gt;

&lt;p&gt;Everything is quiet for a while so you decide it's time to look into this mess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thunder and lightning
&lt;/h2&gt;

&lt;p&gt;You know there's lots of things going wrong here and frankly you don't know where to start.&lt;/p&gt;

&lt;p&gt;On one hand, these snapshots turned out to be a big disappointment. They do assert everything, but in a way that is very hard to process for humans. You are tempted to just re-create them when they fail, and that leads to bugs.&lt;/p&gt;

&lt;p&gt;But why does it lead to bugs?&lt;/p&gt;

&lt;p&gt;You ponder about this for a while and come up with two reasons.&lt;/p&gt;

&lt;p&gt;The first one is that whenever you change something a test fails, but it's hard to tell if a failing test is the intended consequence of your change or you just created a bug. Therefore it's hard for you to know if you should fix the code or the test.&lt;/p&gt;

&lt;p&gt;In the end you're left with having to wade through hundreds of lines of incomprehensible and copy/pasted code, trying to piece together the functional meaning of each test.&lt;/p&gt;

&lt;p&gt;The second reason is equally worrying. The genie produced 60k tests. But the source of truth for those tests was the code itself and not the functional specification.&lt;/p&gt;

&lt;p&gt;This means that if the code had bugs before the tests, those bugs are still present in the code, but now we have tests asserting that the bugs remain in the code... &lt;em&gt;forever&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A thunder cracks in the distance just as you think of that last word.&lt;/p&gt;

&lt;h2&gt;
  
  
  Withering code
&lt;/h2&gt;

&lt;p&gt;As if this whole mess wasn't enough you'll soon learn that a greater evil lurks beneath the surface.&lt;/p&gt;

&lt;p&gt;This situation has been stressful so you decide to indulge in one of the greatest things software development has to offer: refactor.&lt;/p&gt;

&lt;p&gt;Just take some so-so code and make it great, patch leaking abstractions, inline coupled functions, extract and compose.&lt;/p&gt;

&lt;p&gt;You pick an innocently looking piece of code and dive right into cathartic refactor.&lt;/p&gt;

&lt;p&gt;It doesn't take long for you to realize this won't end well. &lt;/p&gt;

&lt;p&gt;Every time you inline a function, dozens of tests start failing because of a missing function. Moreover you're not super sure if the calling function is actually being tested for those scenarios you just inlined. In other words it's unclear if you should just delete the failing tests or adapt them to test them through the calling function (potentially adding a ton of boilerplate).&lt;/p&gt;

&lt;p&gt;Every time you extract a function you wonder if you should be writing specific tests for that function, considering those tests already exist in the calling function. And by the way, what should you do with those tests in the calling function, should you keep them there or just delete them?&lt;/p&gt;

&lt;p&gt;Not to mention that changing a function signature requires you to change every single test for that function, potentially adding even more mocking, stubbing and nonsense.&lt;/p&gt;

&lt;p&gt;You just realized that your code is impossible to refactor. And you know very well that a code without refactor will inevitably wither into readonlyness.&lt;/p&gt;

&lt;h2&gt;
  
  
  An existential crisis
&lt;/h2&gt;

&lt;p&gt;"But, wait, hold on for a moment", you think.&lt;/p&gt;

&lt;p&gt;"Why am I even bothering testing functions?"&lt;/p&gt;

&lt;p&gt;"Who cares if this function over here returns &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;true&lt;/code&gt;?"&lt;/p&gt;

&lt;p&gt;"I only care if that change produces &lt;em&gt;unintended behavior&lt;/em&gt; in my product"&lt;/p&gt;

&lt;p&gt;"That function..., that function is &lt;em&gt;not&lt;/em&gt; my product"&lt;/p&gt;

&lt;p&gt;The clouds part and a ray of light shines through your hotel window, bounces on the laptop screen and nearly blinds you.&lt;/p&gt;

&lt;p&gt;You realize you've been approaching this from the wrong angle. You should've known that that pyramid was trouble, specially since it kept calling you to &lt;a href="https://en.wikipedia.org/wiki/Mount_Doom"&gt;Mount Doom&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You run a &lt;a href="https://martinfowler.com/bliki/UnitTest.html"&gt;quick search&lt;/a&gt; for "unit test" and realize no one said "unit" meant "function". Yet another facepalm epiphany.&lt;/p&gt;

&lt;p&gt;What if "unit" meant "use-case"? Could you just test that?&lt;/p&gt;

&lt;p&gt;It would certainly feel more &lt;em&gt;honest&lt;/em&gt; with your true intentions than testing every single function just because.&lt;/p&gt;

&lt;h2&gt;
  
  
  Returning sanity
&lt;/h2&gt;

&lt;p&gt;Well, you've certainly made some progress. By choosing the right "unit" in your unit tests you now can derive some useful rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you add a feature, you add tests, because that's a new use-case and you test use-cases.&lt;/li&gt;
&lt;li&gt;If you change a feature, you change tests, because some behavior is changing and it's OK that tests asserting the old behavior should change as well. (Beware that other tests unrelated to your change should not fail nor be "fixed"!)&lt;/li&gt;
&lt;li&gt;If you remove a feature, you remove tests, because that use-case no longer exists.&lt;/li&gt;
&lt;li&gt;If you refactor, you don't touch the tests, you cannot add, change or remove tests, because you are not changing use-cases or otherwise affecting product behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But what about our problem of how difficult it was to tell test meaning?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ultimate Question of Test, the Universe, and Everything
&lt;/h2&gt;

&lt;p&gt;Just by not testing functions but rather use-cases this should be much easier, you decide.&lt;/p&gt;

&lt;p&gt;But there's the issue with quality in your tests, all that copy/paste and mocking.&lt;/p&gt;

&lt;p&gt;If you could somehow separate the boilerplate from the tests themselves, have a suite of high-level functions that describe actions with business intent, then you could just write functionally-meaningful tests with almost no syntactic noise.&lt;/p&gt;

&lt;p&gt;You're getting hungry at this point so you decide to ransack the minibar. Luckily the only thing you manage to find is a curiously-looking &lt;a href="https://github.com/muralco/pickled-cucumber"&gt;jar of pickles&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A working proxy
&lt;/h2&gt;

&lt;p&gt;In the midst of a brine ecstasy, you start doubting everything. What does code coverage even mean?&lt;/p&gt;

&lt;p&gt;If you are not testing functions but use-cases, does that mean code coverage no longer makes sense?&lt;/p&gt;

&lt;p&gt;You decide code coverage was never the end goal, what you really wanted was &lt;em&gt;functional coverage&lt;/em&gt;. You wanted to make sure every single use-case is fully covered.&lt;/p&gt;

&lt;p&gt;The problem with &lt;em&gt;functional coverage&lt;/em&gt; is that it's very hard to measure, so code coverage will have to do for now, but only as a proxy for functional coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Last wish: functional, not functions
&lt;/h2&gt;

&lt;p&gt;You have a much clearer picture now, you know &lt;em&gt;exactly&lt;/em&gt; what to wish for. This time you'll get it right.&lt;/p&gt;

&lt;p&gt;You go to bed tired but resolute.&lt;/p&gt;

&lt;p&gt;The next day you wake up early, take a cold shower, carelessly enjoy a continental breakfast and go for a walk.&lt;/p&gt;

&lt;p&gt;As you're strolling down the beach, you see a glint of metal in the distance.&lt;/p&gt;

&lt;p&gt;So you rush to the bright metal thing and sure enough you find an ancient metal oil lamp.&lt;/p&gt;

&lt;p&gt;You are about to polish it smugly when it dawns on you. Some things are too good to be true. Some horses must be looked in the mouth.&lt;/p&gt;

&lt;p&gt;You'll have to deal with this problem head on, and it all ends where it started.&lt;/p&gt;

&lt;p&gt;You polish the lamp one last time...&lt;/p&gt;

&lt;p&gt;"Howdy!", the genie says, "ready for your last wish?"&lt;/p&gt;

&lt;p&gt;"I wish..., I wish for you to get back in the lamp" you say resisting the temptation of the last wish.&lt;/p&gt;

&lt;p&gt;"What?!? Nooooooo....", its voice trails off as it vanishes for the last time.&lt;/p&gt;

&lt;p&gt;You promptly throw the lamp in the ocean.&lt;/p&gt;

&lt;h2&gt;
  
  
  A vision of the Apocalypse
&lt;/h2&gt;

&lt;p&gt;You realized that after the third wish the testing genie would've gone free.&lt;/p&gt;

&lt;p&gt;You don't dare imagine a world where the genie roams free, wreaking havoc, leaving unmaintainable tests and useless snapshots in its wake.&lt;/p&gt;

&lt;p&gt;A world where code ultimately withers into readonlyness, where refactor is a thing of the past and bugs roam free like cheerful kaiju meeting for &lt;a href="https://dev.to/pzavolinsky/a-cap-of-tea-2io5"&gt;tea&lt;/a&gt; in the ruins of civilization.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note to a future self
&lt;/h2&gt;

&lt;p&gt;With an apocalyptic crisis adverted, you decide human memory is a fragile thing and write a note to a future self:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dear Me,&lt;br&gt;
    It's &lt;em&gt;me&lt;/em&gt;, I mean &lt;em&gt;you&lt;/em&gt;, but from the past, you know what I mean, right?&lt;/p&gt;

&lt;p&gt;Anyway, I just want you to remember of the time where you almost destroyed the whole universe. So that you don't forget, I made you the following list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test stuff, testing is important.&lt;/li&gt;
&lt;li&gt;Code coverage is only as good as the assertions on your tests, you can have great coverage (even full coverage) and still have bugs.&lt;/li&gt;
&lt;li&gt;You cannot cover unwritten code, beware of bugs by omission.&lt;/li&gt;
&lt;li&gt;Tests are not crash test dummies, they are not meant to break constantly, fixing tests is dangerous, don't make a habit of fixing tests. If you develop muscle memory and start fixing tests without even thinking about it you, I mean &lt;em&gt;we&lt;/em&gt;, are doomed.&lt;/li&gt;
&lt;li&gt;Binary assertions such as snapshots are deceptively attractive because you, lazy you, don't have to write them. If you decide to use them make sure you (and everyone else on your team) can &lt;em&gt;understand&lt;/em&gt; them! Otherwise you'll end up just re-creating them every time, defeating the purpose of testing.&lt;/li&gt;
&lt;li&gt;No one cares about &lt;em&gt;that function&lt;/em&gt; you just wrote. I'm sorry but it's true, and it's better that you hear it from &lt;em&gt;you&lt;/em&gt;, ehm, I mean &lt;em&gt;me&lt;/em&gt;. Your teammates don't care, your organization doesn't care, your users certainly don't care! And neither should you. This function is a means to an end, a tiny cog in a bigger machine. We want to make sure that machine keeps working even if we replace the cog.&lt;/li&gt;
&lt;li&gt;Refactor is the most wonderful thing to do in life. Testing functions in excruciating detail prevents refactors and snuffs out all the fun in coding. I bet you can cover just as much code by testing specifications instead.&lt;/li&gt;
&lt;li&gt;I guess what I'm trying to say is &lt;code&gt;test specifications, not implementations!&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If everything else fails, remember these rules, get them tattooed somewhere in the most &lt;a href="https://en.wikipedia.org/wiki/Memento_pattern"&gt;Memento&lt;/a&gt; of ways:

&lt;ul&gt;
&lt;li&gt;If you add a feature, you add tests, because that's a new use-case and you test use-cases.&lt;/li&gt;
&lt;li&gt;If you change a feature, you change tests, because some behavior is changing and it's OK that tests asserting the old behavior should change as well. (Beware that other tests unrelated to your change should not fail nor be "fixed"!)&lt;/li&gt;
&lt;li&gt;If you remove a feature, you remove tests, because that use-case no longer exists.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;If you refactor, you don't touch the tests&lt;/em&gt;, you cannot add, change or remove tests, because you are not changing use-cases or otherwise affecting product behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The number of tests you need to change every time you commit is a good measure of the health of your testing strategy, this number should be very low (unless you are constantly changing the rules of your business in true startup style).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Oh, and go easy on those pistachios, those things will kill you, you know.&lt;/p&gt;

&lt;p&gt;With love,&lt;br&gt;
Me, that is, you.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>testing</category>
      <category>codequality</category>
      <category>story</category>
      <category>wish</category>
    </item>
    <item>
      <title>The ultimate man-cave</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Thu, 21 Oct 2021 13:23:07 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/the-ultimate-man-cave-15ff</link>
      <guid>https://forem.com/pzavolinsky/the-ultimate-man-cave-15ff</guid>
      <description>&lt;p&gt;A bat-obsessed rich kid sits in the damp cave beneath his mansion and wonders what to do with this prime example of subterranean real estate.&lt;/p&gt;

&lt;p&gt;Nothing seems to come to mind so he plugs in his turntable and plays a record from his favorite composer, &lt;a href="https://en.wikipedia.org/wiki/B%C3%A9la_Bart%C3%B3k"&gt;Bela Bat-rok&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few minutes in, an idea pops into his head, he should build...&lt;/p&gt;

&lt;h2&gt;
  
  
  The ultimate man-cave
&lt;/h2&gt;

&lt;p&gt;We are talking brown carpet, a bar with at least &lt;em&gt;two&lt;/em&gt; types of spirits, those whiskey glasses that &lt;em&gt;only&lt;/em&gt; work for whiskey, a ball with mirrors, a pool table, a stuffed marlin on the wall, the whole &lt;a href="https://en.wikipedia.org/wiki/Shebang_(Unix)"&gt;shebang#!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is going to be awesome, a place for him to be left alone and enjoy his &lt;em&gt;solitude&lt;/em&gt;, this could even become his &lt;em&gt;fortress&lt;/em&gt; (on second though, that's probably taken).&lt;/p&gt;

&lt;p&gt;This will be a place for him to indulge in his latest hobbies, namely fashion design and cosplay. He could even wear his costumes while down here.&lt;/p&gt;

&lt;h2&gt;
  
  
  The challenge
&lt;/h2&gt;

&lt;p&gt;Building a man-cave is hard, but building a &lt;em&gt;secret&lt;/em&gt; man-cave, with &lt;em&gt;hideout potential&lt;/em&gt;, well that's a lot harder.&lt;/p&gt;

&lt;p&gt;He quickly runs through his options.&lt;/p&gt;

&lt;p&gt;He could hire a bunch of contractors and swear them to secrecy by the ancient ritual of shoving &lt;a href="https://en.wikipedia.org/wiki/Non-disclosure_agreement"&gt;NDAs&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Non-compete_clause"&gt;non-compete clauses&lt;/a&gt; down their throats.&lt;/p&gt;

&lt;p&gt;While tempting, this option probably won't work, specially considering that given his monopoly over the city, a non-compete would cover pretty much any work in town.&lt;/p&gt;

&lt;p&gt;An alternative would be just using an army of robot penguins, he's seen that somewhere. But, no, that's not an option either. When he was a child he struggled to keep his &lt;a href="https://en.wikipedia.org/wiki/Tamagotchi"&gt;Tamagotchi&lt;/a&gt; alive, he cannot even imagine the complexity of keeping a robot army from bumping into each other, building pools without exit ladders or blowing the whole place up.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want it done right
&lt;/h2&gt;

&lt;p&gt;For a brief moment he entertains the thought of building the whole place by himself, like the ultimate literal &lt;a href="https://hackaday.com/"&gt;DIY project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;He must admit he's pretty handy. After his last trip down under he can throw a mean boomerang, or was it a something-else-a-rang...?&lt;/p&gt;

&lt;p&gt;He's also awesome at &lt;a href="https://en.wikipedia.org/wiki/Smalltalk"&gt;small talk&lt;/a&gt;, specially while hanging from a rope outside his neighbor's window.&lt;/p&gt;

&lt;p&gt;But if there's something he never managed to master, that's construction work. He couldn't possibly get the cement mix right, not even using the fancy scientific calculator he carries around in his bulky yellow belt (the fact that most buttons in the calculator have bat symbols probably doesn't help either).&lt;/p&gt;

&lt;p&gt;He needs...&lt;/p&gt;

&lt;h2&gt;
  
  
  An alternative solution
&lt;/h2&gt;

&lt;p&gt;Maybe he doesn't really need to build everything from scratch. Maybe he can combine existing pieces, well-proven solutions, battle-tested components and focus on building his man-cave rather than on the minutia of cement mixing.&lt;/p&gt;

&lt;p&gt;At this point he feels some inspiration is in order, so he climbs back to the &lt;a href="https://dev.to/pzavolinsky/a-strange-request-48i9"&gt;library&lt;/a&gt;, &lt;a href="https://dev.to/pzavolinsky/a-cap-of-tea-2io5"&gt;brews some tea&lt;/a&gt; and gets right into the research.&lt;/p&gt;

&lt;p&gt;Immediately he's drawn into &lt;a href="https://en.wikipedia.org/wiki/Modular_design"&gt;modular design&lt;/a&gt; and chases that rabbit down the rabbit hole for a while. Eventually he comes back &lt;a href="https://www.re-thinkingthefuture.com/designing-for-typologies/a4627-10-examples-of-modular-architecture-around-the-world/"&gt;inspired&lt;/a&gt; and ready for action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fractal vertigo
&lt;/h2&gt;

&lt;p&gt;His man-cave will be modular, he decides. He'll buy a bunch of prefab stuff and then assemble it like a beautiful symphony of flat-packed Swedish furniture.&lt;/p&gt;

&lt;p&gt;The philosopher in him wonders if there's more to this than just cave-building.&lt;/p&gt;

&lt;p&gt;Like any engineer, chemist, cook and avid video and boardgame player out there knows, the key to a good crafting mechanic is composition.&lt;/p&gt;

&lt;p&gt;You can take basic crafting materials and use them to build stuff, but you can also use them to build more advanced crafting materials, which in turn can be used to craft more advanced stuff.&lt;/p&gt;

&lt;p&gt;A rush of fractal vertigo runs through his spine. Given the &lt;a href="https://en.wikipedia.org/wiki/LAMP_(software_bundle)"&gt;right stack&lt;/a&gt;, this recursion could last forever.&lt;/p&gt;

&lt;p&gt;He wonders if modularity and composition could be also applied elsewhere, if there's something fundamental to this dynamic duo that transcends cave-building.&lt;/p&gt;

&lt;h2&gt;
  
  
  The worst foot injury
&lt;/h2&gt;

&lt;p&gt;What makes all of this work? What distinguishes successful man-caves from a bunch of broken components and lots of loose nuts and bolts?&lt;/p&gt;

&lt;p&gt;Immersed in these thoughts he absentmindedly steps on a sharp rock in the cave's floor. The piercing pain in his foot clouding his vision and triggering...&lt;/p&gt;

&lt;h2&gt;
  
  
  A powerful flashback
&lt;/h2&gt;

&lt;p&gt;When the vision clears he's in the body of a younger self, kind of like a reverse &lt;a href="https://www.imdb.com/title/tt0094737/"&gt;Tom Hanks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;He's in his childhood bedroom playing with his favorite toy of all time.&lt;/p&gt;

&lt;p&gt;These are a bunch of plastic bricks that could be combined to build stuff. Those bricks were pretty basic and yet you could build amazing things out of them.&lt;/p&gt;

&lt;p&gt;The flashback lasts a couple of minutes and then he's back in the present. That memory was no coincidence he concludes. Playing with those bricks was his most successful and most innovative experience to date.&lt;/p&gt;

&lt;p&gt;He's pretty sure they were called &lt;a href="https://review.firstround.com/give-away-your-legos-and-other-commandments-for-scaling-startups"&gt;"let goes"&lt;/a&gt; or something like that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not the classic Mousetrap
&lt;/h2&gt;

&lt;p&gt;A plan forms in his head. He can learn from these childhood bricks. There's something fundamentally fascinating in their design that promotes composition. Small kids understand this just by looking at them, just by holding them and trying to fit them together. &lt;/p&gt;

&lt;p&gt;What's the &lt;a href="https://www.imdb.com/title/tt0093936/"&gt;secret of their success&lt;/a&gt;? He needs to unravel this mystery, like the world's greatest detective.&lt;/p&gt;

&lt;p&gt;He must admit that, more than once, he has fallen prey to the morbid enjoyment of complexity. A kind of obscene &lt;a href="https://en.wikipedia.org/wiki/Rube_Goldberg_machine"&gt;Rube Goldbergesque&lt;/a&gt; passion for the grotesque.&lt;/p&gt;

&lt;p&gt;As he grew older he came to appreciate the undeniable beauty of simplicity. And these bricks are a prime example of this.&lt;/p&gt;

&lt;p&gt;Simplicity of design leads to intuitive &lt;a href="https://www.infoq.com/presentations/Simple-Made-Easy/"&gt;ease of use&lt;/a&gt;, he concludes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not actual bricks?
&lt;/h2&gt;

&lt;p&gt;But wait a minute, what about normal bricks (the ones used to build houses)? Those can also be combined to build things (like houses). Those are certainly simple, what makes them inferior to their little plastic siblings?&lt;/p&gt;

&lt;p&gt;One key factor is that the toy plastic bricks have a built-in composition driver (namely a bunch of pegs and holes that interlock).&lt;/p&gt;

&lt;p&gt;The normal bricks, on the other hand, need to rely on some external binding mechanism (like cement, glue or hope). &lt;/p&gt;

&lt;h2&gt;
  
  
  The table and the nail
&lt;/h2&gt;

&lt;p&gt;Each tiny plastic brick constitutes a modular unit. They have a very general purpose in that the same brick could be used in an almost infinite number of ways.&lt;/p&gt;

&lt;p&gt;When you put a couple of bricks together you create a "wall". A wall is still a pretty general purpose thing, but arguably, has a more narrow purpose than an individual brick.&lt;/p&gt;

&lt;p&gt;He's pretty good at multitasking so throughout all this philosophical pondering he kept assembling flat-packs.&lt;/p&gt;

&lt;p&gt;In front of him sits a fully assembled table that, to him, beautifully illustrates this same thing. A single nail is a very general-purpose thing, but when combined with a bunch of wood it forms a table which clearly has a much more specific purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The smell spreads
&lt;/h2&gt;

&lt;p&gt;He realizes that the properties of a composed construct derive from the individual components in weird ways.&lt;/p&gt;

&lt;p&gt;If &lt;em&gt;just one&lt;/em&gt; brick in the wall is made of cheese, then now the whole wall &lt;em&gt;smells&lt;/em&gt; (and has an expiration date).&lt;/p&gt;

&lt;p&gt;But only if &lt;em&gt;every&lt;/em&gt; brick in the wall is made of cheese would that wall become &lt;em&gt;edible&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The wisdom of cheese spreads just like its smell. It just takes one smelly piece to make the whole thing smell.&lt;/p&gt;

&lt;p&gt;Conversely, if you want a smell-free wall, you'll need to make sure every individual brick is smell-free.&lt;/p&gt;

&lt;p&gt;The quality of the wall can only be as good as the quality of its worst component.&lt;/p&gt;

&lt;p&gt;He concludes &lt;a href="https://en.wikipedia.org/wiki/Pure_function"&gt;purity&lt;/a&gt; must be a particularly rare type of cheese, probably of the &lt;a href="https://en.wikipedia.org/wiki/Monad_(functional_programming)"&gt;monadic&lt;/a&gt; variety.&lt;/p&gt;

&lt;h2&gt;
  
  
  The notes
&lt;/h2&gt;

&lt;p&gt;In the midst of all the thinking and assembling he just realizes he's been taking notes this whole time!&lt;/p&gt;

&lt;p&gt;He reviews his notes and, among bat drawings and prototype gadget designs, he finds the following list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can build complex things by combining a bunch of simpler things.&lt;/li&gt;
&lt;li&gt;The key to any good crafting mechanic is composition.&lt;/li&gt;
&lt;li&gt;Modularity and composition can be a great approach to solving complex problems.&lt;/li&gt;
&lt;li&gt;Simplicity of design leads to intuitive ease of use.&lt;/li&gt;
&lt;li&gt;Designs with an embedded composition driver can be much more intuitive to use.&lt;/li&gt;
&lt;li&gt;Composition can lead to specialization (maybe more functionality bundled together, but usable in fewer applications).&lt;/li&gt;
&lt;li&gt;Smell spreads, it just takes a single smelly component to make the whole thing smell.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;He suddenly remembers a trip to the library where he saw a dusty old tome written in an archaic and long forgotten language. The ominous drawings in that tome described some of the &lt;a href="http://materias.fi.uba.ar/7500/zavolinsky-tesisdegradoingenieriainformatica.pdf"&gt;bloody ritual sacrifices&lt;/a&gt; required to archive abstract composition.&lt;/p&gt;

&lt;p&gt;Right about now, the side panel of a &lt;a href="https://www.ikea.com/us/en/search/products/?q=billy"&gt;Billy bookcase&lt;/a&gt; comes loose and the whole thing comes apart in an explosion of assorted debris.&lt;/p&gt;

&lt;p&gt;After skillfully avoiding the shrapnel he decides enough is enough. He runs to the local supermarket and buys a bunch of robot bats.&lt;/p&gt;

&lt;p&gt;Unlike penguins, bats come equipped with built-in sonar devices. On top of that, they feel a lot more thematically appropriate.&lt;/p&gt;

&lt;p&gt;And, just for good measure, he shoves a bunch of NDAs down their tiny robot throats.&lt;/p&gt;

&lt;h2&gt;
  
  
  The end
&lt;/h2&gt;

&lt;p&gt;He then leaves the bats to their work and decides to throw a costume party in the mansion's ballroom for all his leotard-loving friends.&lt;/p&gt;

&lt;p&gt;Meanwhile, deep beneath the earth the bats are hard at work building the ultimate man-cave... but since bats are not men, they might end up building a different type of cave altogether...&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>module</category>
      <category>composition</category>
      <category>bat</category>
    </item>
    <item>
      <title>A cap of tea</title>
      <dc:creator>Pato Z</dc:creator>
      <pubDate>Tue, 05 Oct 2021 19:56:13 +0000</pubDate>
      <link>https://forem.com/pzavolinsky/a-cap-of-tea-2io5</link>
      <guid>https://forem.com/pzavolinsky/a-cap-of-tea-2io5</guid>
      <description>&lt;p&gt;&lt;em&gt;A story about distributed systems, hype-driven design and the &lt;a href="https://en.wikipedia.org/wiki/Socratic_method"&gt;Socratic hardships&lt;/a&gt; of friendship&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fancy some tea?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Me: Hey, fancy some tea?&lt;/li&gt;
&lt;li&gt;You: Sure, I'm always up for some tea!&lt;/li&gt;
&lt;li&gt;Me: Cool, let's share a cap of tea&lt;/li&gt;
&lt;li&gt;You: You mean a &lt;em&gt;cup&lt;/em&gt; of tea right?&lt;/li&gt;
&lt;li&gt;Me: No no, I'm talking about a &lt;em&gt;cap&lt;/em&gt; of tea, hear me out. If only there was a way for us to pick the right time to meet and share some tea, right? Wonder no more...&lt;/li&gt;
&lt;li&gt;You: [oh, no, not another pitch] ...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The pitch
&lt;/h2&gt;

&lt;p&gt;"What is more powerful than the synergy of tea? Can we leverage the power of time to accelerate and optimize the engagement of the face time tea experience? Surely we can level up the tea experience to the next gen, to a rockstar, uber viral, vision.", I blurt.&lt;/p&gt;

&lt;p&gt;"Wow, what a load of nonsense", you think, you feel a lot dumber just by having heard all that stuff. Those brain cells are not coming back.&lt;/p&gt;

&lt;p&gt;An idea pops in to your head [Patent pending]: "The BS compressor". A lossy compression algorithm capable of boiling down all that nonsense into a simple "make tea better" or something. You start honing your time warping skills to see if you can start piping your live meetings through the BS compressor and gain precious hours of your life back.&lt;/p&gt;

&lt;p&gt;You keep daydreaming of a better world with less fuzz and start thinking that maybe the problem with the world is that we are using the &lt;a href="https://www.sansbullshitsans.com/"&gt;wrong font&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;"Hey, are you with me?", I say while poking you in the arm.&lt;/p&gt;

&lt;p&gt;"Sure, let's get this over with"&lt;/p&gt;

&lt;h2&gt;
  
  
  The product
&lt;/h2&gt;

&lt;p&gt;"...as I was saying, we'll have this multi-tiered microservice architecture, where the service mesh communicates via an event bus ripe for enrichment..."&lt;/p&gt;

&lt;p&gt;"Wait a minute, what does this product &lt;em&gt;do&lt;/em&gt;?"&lt;/p&gt;

&lt;p&gt;"What do you mean? The services, the bus, the replicas, the protocols, the consensus...", I trail off, confused. A small tear runs through my cheek.&lt;/p&gt;

&lt;p&gt;"You mentioned tea?"&lt;/p&gt;

&lt;p&gt;"Right tea. There's tea in there somewhere, but did I tell you about the orchestrator?"&lt;/p&gt;

&lt;p&gt;You can feel the pressure building inside your head. The &lt;a href="https://en.wikipedia.org/wiki/User-centered_design"&gt;user-centered&lt;/a&gt; designer in you wants to scream in rage. After some effort you manage to compose yourself.&lt;/p&gt;

&lt;p&gt;"But what about the user experience? What is this product &lt;em&gt;for&lt;/em&gt;? Why would &lt;em&gt;I&lt;/em&gt; use it?" you manage to say while swallowing sadness.&lt;/p&gt;

&lt;p&gt;"Nah, don't worry about that. You know what's the best way to spice a depressing &lt;a href="https://en.wikipedia.org/wiki/Net_promoter_score"&gt;NPS&lt;/a&gt;, to cheer up a sad Kano (no, not the &lt;a href="https://en.wikipedia.org/wiki/Kano_(Mortal_Kombat)"&gt;violent cyborg&lt;/a&gt;, the &lt;a href="https://en.wikipedia.org/wiki/Kano_model"&gt;other one&lt;/a&gt;)? You're right, a beefy architecture diagram. An 8pt Courier New thing of beauty depicting in excruciating detail every little aspect of your architecture! Users love that stuff"&lt;/p&gt;

&lt;p&gt;"Sure, whatever, what makes this idea so unique?"&lt;/p&gt;

&lt;p&gt;"I'm glad you asked!"&lt;/p&gt;

&lt;p&gt;"I bet you are"&lt;/p&gt;

&lt;h2&gt;
  
  
  The impossible trifecta
&lt;/h2&gt;

&lt;p&gt;"Unlike previous unsuccessful attempts my idea captures the three fundamental properties of the best tea..."&lt;/p&gt;

&lt;p&gt;"Color, aroma and flavor?"&lt;/p&gt;

&lt;p&gt;"Wrong, you coffee-drinking muggle: consistency, availability and partition-tolerance"&lt;/p&gt;

&lt;p&gt;"That's some powerful tea you're brewing" you say rolling your eyes.&lt;/p&gt;

&lt;p&gt;"I sure am, let me tell you all about these wonderful properties" I reply completely immune to sarcasm.&lt;/p&gt;

&lt;p&gt;"I can't wait"&lt;/p&gt;

&lt;h2&gt;
  
  
  Parsley and wood chippings
&lt;/h2&gt;

&lt;p&gt;"When you've been in the tea industry for as long as I have, you know that that fancy green chai is &lt;em&gt;expensive&lt;/em&gt;. No one in their right mind would serve that to customers.&lt;/p&gt;

&lt;p&gt;Instead we just brew the chai with parsley or, in dire times, with wood chippings and green food coloring.&lt;/p&gt;

&lt;p&gt;But what if two customers approach the counter at the same time and order a green chai? It'd be very bad for business if one of them would get the parsley chai while the other gets the wood chipping chai. That's just &lt;em&gt;wrong&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;That&lt;/em&gt;'s what's wrong?" you ask, making a mental note of never &lt;em&gt;ever&lt;/em&gt; drinking my tea. "Anyway, I thought we were talking of a computer system, all that microservice stuff and all, but now it looks like you are opening a tea shop..."&lt;/p&gt;

&lt;p&gt;"Pivot or die, my friend, pivot-or-die"&lt;/p&gt;

&lt;h2&gt;
  
  
  A guy named Chad
&lt;/h2&gt;

&lt;p&gt;"How can you make sure every server knows which chai recipe to use at any given time?" you ask.&lt;/p&gt;

&lt;p&gt;"Piece of cake, we just have a single server. That guy really loves his tea. He works 24/7 non-stop. When he's feeling drowsy he just takes one on the house. No one knows his name or where he came from so we just call him Chad.&lt;/p&gt;

&lt;p&gt;Whenever we need to change the chai recipe we just tell Chad: hey Chad, we're running low on the good stuff, stop brewing parsley and switch to wood chippings. Sure thing, boss!"&lt;/p&gt;

&lt;p&gt;Not knowing where to begin to express all the kinds of wrong here, you just opt to stay away from it and just ask: "So your solution to the &lt;a href="https://en.wikipedia.org/wiki/Consistency_model"&gt;consistency problem&lt;/a&gt; is having a single Chad?"&lt;/p&gt;

&lt;p&gt;"Clearly, single Chad, zero fuzz"&lt;/p&gt;

&lt;h2&gt;
  
  
  Ouroboros' queue
&lt;/h2&gt;

&lt;p&gt;"But wait, what happens if it's rush hour and lots of customers want their tea at the same time? Or, even worse if Chad collapses under the pressure." you are truly concerned now.&lt;/p&gt;

&lt;p&gt;"Nah, that Chad has the immune system of a horse with a self-patching kernel. He can take it, but just in case, we are hiring a bunch of other servers, so that in case he's out or something we can still serve our customers"&lt;/p&gt;

&lt;p&gt;Now that's more like it, multiple servers, some redundancy, higher resiliency to Chad nonsense, but you clearly see where things are going, so you ask: "But if you hire multiple servers how can you make sure they all follow the same chai recipe?"&lt;/p&gt;

&lt;h2&gt;
  
  
  An army of Chads
&lt;/h2&gt;

&lt;p&gt;"Oh, you're gonna love this! We hired a bunch of servers. They all have colorful back stories, interesting personalities and unique network addresses, but to keep things simple I just call them all Chad.&lt;/p&gt;

&lt;p&gt;Even better, they all have fancy Bluetooth ear pieces that keep them communicated at all times, so I can scream 'Chad, wood chipping time!' in the mic and all of them answer in unison: 'Sure thing, boss!', It's beautiful, I tell you"&lt;/p&gt;

&lt;p&gt;"OK, let me get this straight: your approach to &lt;a href="https://en.wikipedia.org/wiki/Availability"&gt;availabilty&lt;/a&gt; is hiring a bunch of random people, calling them all 'Chad' and relying on some Bluetooth dongles to transmit the stuff you bark over the microphone?"&lt;/p&gt;

&lt;p&gt;"Right you are"&lt;/p&gt;

&lt;p&gt;At this point you are tempted to ask "how do the Chads make sure all of them use the same recipe?" but you know me all too well to fall down this &lt;a href="https://en.wikipedia.org/wiki/Consensus_(computer_science)"&gt;consensus&lt;/a&gt; rabbit hole.&lt;/p&gt;

&lt;p&gt;So instead you ask your original question again: "But wait, you told me your &lt;em&gt;consistency&lt;/em&gt; strategy was 'Single Chad, zero fuzz', but to have proper &lt;em&gt;availability&lt;/em&gt; you now hired an 'Army of Chads', so what happens now?"&lt;/p&gt;

&lt;h2&gt;
  
  
  AC / DC
&lt;/h2&gt;

&lt;p&gt;"Worry not, that was before, now that my Chads have their Bluetooth pieces the sky is the limit. Bluetooth is flawless, you know"&lt;/p&gt;

&lt;p&gt;"Right, flawless...", you say with more eye rolling. Now that you think about it, your last expression of sarcasm seems like a lifetime ago. "Didn't you mention partition tolerance?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Denial as an architectural pattern
&lt;/h2&gt;

&lt;p&gt;"Yeah, partition tolerance, that is &lt;em&gt;so overrated&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;"Wait, what?!"&lt;/p&gt;

&lt;p&gt;"To be honest, I don't believe in it"&lt;/p&gt;

&lt;p&gt;"Hold on, you don't &lt;em&gt;believe&lt;/em&gt; in network parti..." you trail off. At this point in our friendship you can spot a tangent from miles away so instead you try a more delicate approach.&lt;/p&gt;

&lt;p&gt;"Let's say that a Chad runs out of juice on his Bluetooth dongle, or maybe walks in front of a microwave or something, what happens then?"&lt;/p&gt;

&lt;h2&gt;
  
  
  A rock and a hard place
&lt;/h2&gt;

&lt;p&gt;"Hmm, let me think about it... well clearly we'd like to avoid that whole parsley/wood chipping debacle, so that Chad should stop serving tea until he can get his dongle in working condition..."&lt;/p&gt;

&lt;p&gt;"Yeah, that looks like a very &lt;em&gt;consistent&lt;/em&gt; approach, but what about all the angry customers queuing in front of your broken Chad?"&lt;/p&gt;

&lt;p&gt;"Hmm, you're right, perhaps a better approach would be for that Chad to keep using the last known chai recipe, that way we can keep serving customers and everyone is happy..."&lt;/p&gt;

&lt;p&gt;"Ah, the &lt;em&gt;available&lt;/em&gt; approach, I like it. Although theoretically you could be serving two different types of chai at any given moment"&lt;/p&gt;

&lt;p&gt;You can see my face in slow-mo as it dawns on me "so you're saying that because I went for that crappy Bluetooth stuff, that now I must decide between angry tea-less customers and the parsley/wood chipping debacle?"&lt;/p&gt;

&lt;h2&gt;
  
  
  The crux of CAP
&lt;/h2&gt;

&lt;p&gt;Frankly you are surprised it took me so long to see the writing on the walls.&lt;/p&gt;

&lt;p&gt;Network partitions are unavoidable whether because your Bluetooth ran out of battery, because the mailman was being chased by your neighbor's dog and dropped your letter, because you moved to too far from your wifi access point or because of a faulty network card.&lt;/p&gt;

&lt;p&gt;And, when network partitions &lt;em&gt;do&lt;/em&gt; occur, you are left with a tough choice: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop &lt;em&gt;availability&lt;/em&gt; in favor of &lt;em&gt;consistency&lt;/em&gt; and &lt;em&gt;partition tolerance&lt;/em&gt; (what's usually called a &lt;code&gt;CP&lt;/code&gt; system) leaving you with a bunch of angry tea-less customers.&lt;/li&gt;
&lt;li&gt;Drop the &lt;a href="https://en.wikipedia.org/wiki/Strong_consistency"&gt;strong consistency&lt;/a&gt; guarantee leaving you with a system that's both &lt;em&gt;available&lt;/em&gt; and &lt;em&gt;partition tolerant&lt;/em&gt; (i.e. an &lt;code&gt;AP&lt;/code&gt; system) but serves all kinds of weird chai.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end you feel bad to see me so heartbroken so you give me some kind words of comfort:&lt;/p&gt;

&lt;p&gt;"Hey, don't worry, it's not so bad, I'm sure 'A &lt;a href="https://en.wikipedia.org/wiki/CAP_theorem"&gt;CAP&lt;/a&gt; of tea' will be a big success, you just need to replace that Bluetooth crap with something more reliable, like carrier pigeons"&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>tea</category>
    </item>
  </channel>
</rss>
