<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor N.</title>
    <description>The latest articles on DEV Community by Victor N. (@novak_20).</description>
    <link>https://dev.to/novak_20</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%2F541171%2Fc36bb41a-0ae5-4be3-bb86-d06331e45d68.jpg</url>
      <title>DEV Community: Victor N.</title>
      <link>https://dev.to/novak_20</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/novak_20"/>
    <language>en</language>
    <item>
      <title>From object-oriented JS to functional ReScript</title>
      <dc:creator>Victor N.</dc:creator>
      <pubDate>Mon, 06 Dec 2021 14:55:09 +0000</pubDate>
      <link>https://dev.to/novak_20/from-object-oriented-js-to-functional-rescript-5f37</link>
      <guid>https://dev.to/novak_20/from-object-oriented-js-to-functional-rescript-5f37</guid>
      <description>&lt;p&gt;This article might be easily titled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From object-oriented C++ to functional Haskell&lt;/li&gt;
&lt;li&gt;From object-oriented C# to functional F#&lt;/li&gt;
&lt;li&gt;From object-oriented Python to functional OCaml&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main idea is to show how OOP (Object Oriented Programming) concepts can be projected to FP (Functional Programming) while accomplishing the same tasks. It’s always good to base on specifics for the sake of an example. So, I’ve chosen the JavaScript vs. ReScript combo for the illustration because these are the languages I use the most currently.&lt;/p&gt;

&lt;p&gt;I’m expecting you’re a developer familiar with JS who uses objects, their methods, and properties regularly. Not sure, you are creating your own classes to get things done, but definitely use objects from third-party libraries, feel what &lt;code&gt;myObj.foo.func()&lt;/code&gt; means, seen that “Boom! undefined is not a function” for many times, and maybe even never thought if you might do things another way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Destructuring Object-Oriented Programming
&lt;/h2&gt;

&lt;p&gt;OOP is a programming &lt;em&gt;paradigm&lt;/em&gt;. It is a synthetic concept that offers a way to structure your program. You know, OOP is ubiquitous: most popular programming languages allow or enforce to structure programs and libraries this way.&lt;/p&gt;

&lt;p&gt;However, objects are not the only way of programming and are definitely not a silver bullet solution to all problems. Objects were proven to have downsides: composability issues, implicit state dependencies, monolithness, and others. One possible alternative is the &lt;em&gt;functional programming&lt;/em&gt; paradigm.&lt;/p&gt;

&lt;p&gt;And what does that “functional” mean in practice? I’m going to break down OOP into parts, see what problems they are intended to solve and try to find a functional programming way to do the similar. The parts I’m referring to are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;encapsulation&lt;/li&gt;
&lt;li&gt;abstraction&lt;/li&gt;
&lt;li&gt;inheritance&lt;/li&gt;
&lt;li&gt;polymorphism&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Encapsulation
&lt;/h2&gt;

&lt;p&gt;Encapsulation, arguably, the most recognized part of OOP. It is that dot (&lt;code&gt;.&lt;/code&gt;) allowing you to drill down the objects to obtain a value you want or a method you are going to call.&lt;/p&gt;

&lt;p&gt;Formally speaking, encapsulation is an ability to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;group related data and functions within a single thing (known as &lt;em&gt;object&lt;/em&gt;);&lt;/li&gt;
&lt;li&gt;using a reference to the object, access to the data (known as &lt;em&gt;fields&lt;/em&gt;);&lt;/li&gt;
&lt;li&gt;using a reference to the object, call its functions to operate over the data (known as &lt;em&gt;methods&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many languages extend the concept with things like “properties” (fields that are methods actually, aka getters/setters), “events” (fields that are arrays of callback function pointers actually), and other features. Still, it does not change the big picture.&lt;/p&gt;

&lt;p&gt;To illustrate encapsulation, let’s make some burgers with JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Burger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Add a field `layers` to burger objects&lt;/span&gt;
    &lt;span class="c1"&gt;// Let it be an array of layer objects&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrays are by themselves objects too having methods `push`, `splice`, etc;&lt;/span&gt;
    &lt;span class="c1"&gt;// so, we have a nested hierarchy of objects here&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BreadRoll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BeefPatty&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BreadRoll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="c1"&gt;// Another field to hold a menu title&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Provide a method to further build a burger&lt;/span&gt;
  &lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// access the array method and its `length` property through `this` reference&lt;/span&gt;
    &lt;span class="c1"&gt;// to insert a new layer right before the last bread roll&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Construct a couple of different burgers using the class we’ve just defined&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cheeseburger&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;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cheeseburger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;cheeseburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;kingburger&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;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Special King Burger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;kingburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SecretSauce&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;kingburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;kingburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Onion&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;kingburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Tomato&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ve built (an oversimplified) system to describe burgers as objects. Now, we can pass &lt;code&gt;Burger&lt;/code&gt;s around an app to compute prices, show menu, take orders, manage a cooking queue, and so on.&lt;/p&gt;

&lt;p&gt;OK, and if we make an app using the functional programming paradigm, how will the code look? Most FP languages, including ReScript, lack the concept of classes along with their props and methods at all. Functional languages strictly separate data from behavior and algorithms. Data and functions are the bread and butter of functional programming, with a clear point stating that bread ≠ butter. Given that, let’s start with a definition of the data we operate upon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Burger.res ===&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&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;Here we define a new type that groups all the data related to burgers. The type is a record with two fields to model our burgers. It’s that simple. No methods, no indirection, no funky syntax: just what a JS programmer would call a “plain old JavaScript object.”&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;t&lt;/code&gt; name is a ReScript convention for a type describing the primary data type of the current module. It’s handy because you can then fluently refer to such types from other modules like this: &lt;code&gt;Burger.t&lt;/code&gt;, &lt;code&gt;Layer.t&lt;/code&gt;, &lt;code&gt;Order.t&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;We’ve got data; let’s move on to the behavior, that is, to the functions. First, we’re going to add a constructor for our type. A user of &lt;code&gt;Burger.t&lt;/code&gt; might easily create a new instance directly by specifying all the fields one by one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;myBurger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="s2"&gt;"My personal burger"&lt;/span&gt;,
  &lt;span class="n"&gt;layers&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;…but following the same logic as in the JavaScript example, let’s pre-populate layers with a very basic ingredient stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Burger.res ===&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="n"&gt;title&lt;/span&gt;,
  &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BreadRoll&lt;/span&gt;,
    &lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BeefPatty&lt;/span&gt;,
    &lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BreadRoll&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;Again, nothing fancy here. Constructors are just regular functions conventionally named &lt;code&gt;make&lt;/code&gt; or &lt;code&gt;makeBlahBlahBlah&lt;/code&gt;. Our constructor takes a string as a parameter and returns a new &lt;code&gt;Burger.t&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The final bit is our &lt;code&gt;addLayer&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Burger.res ===&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&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="n"&gt;title&lt;/span&gt;: &lt;span class="n"&gt;title&lt;/span&gt;,
  &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BreadRoll&lt;/span&gt;,
    &lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BeefPatty&lt;/span&gt;,
    &lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BreadRoll&lt;/span&gt;,
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;burger&lt;/span&gt;, &lt;span class="n"&gt;layer&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;switch&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;ArrayX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// put the layer before the last one (which is a bread roll)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;, ~&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// list new layers&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
       ...&lt;span class="n"&gt;burger&lt;/span&gt;,
       &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concatMany&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;, &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;, &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;,
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// hmmm... someone messed up with layers, let it be a burger&lt;/span&gt;
    &lt;span class="c1"&gt;// of one ingredient&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; ...&lt;span class="n"&gt;burger&lt;/span&gt;, &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layer&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;Now a developer can use our system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;kingburger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Special King Burger"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecretSauce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Onion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tomato&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two previous snippets are pretty simple but carry so many essential details of FP and ReScript in particular. Let’s look at them one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pipes
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;-&amp;gt;&lt;/code&gt; operator in ReScript is known as a fast pipe. It’s a syntax sugar over regular function call that puts the value on the left-hand side as the first argument of the function on the right-hand side. The following are equivalent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="n"&gt;myBurger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myBurger&lt;/span&gt;, &lt;span class="nc"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to the fast pipe, working with data almost feels like working with objects in OOP using its dot-notation. But in contrast to OOP, accessing “object” (data), “methods” (compatible functions) is not a unique language mechanic; it’s an alternative syntax of the good old plain function call. The “object” (the one with type &lt;code&gt;t&lt;/code&gt;) is conventionally passed as the first argument explicitly. Beautiful, eh?&lt;/p&gt;

&lt;h3&gt;
  
  
  No methods, no monkey-patching
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;kingburger&lt;/code&gt; construction pipeline above, you might be caught on the repetition of &lt;code&gt;Burger.&lt;/code&gt;, &lt;code&gt;Burger.&lt;/code&gt;, &lt;code&gt;Burger.&lt;/code&gt;. These qualifiers are a direct consequence of the fact that &lt;code&gt;-&amp;gt;&lt;/code&gt; is just a function call; it’s not something that belongs to the “object.” We have to tell ReScript the module name where the functions are defined, thus the module prefix on every step.&lt;/p&gt;

&lt;p&gt;It might look annoying, but in practice, it’s beneficial. First, when you read code, you can easily follow the most complex processing pipelines without guessing what type a method returns and where to find a class with such a method: the code is much more self-documenting. Second, such (ugly) things as object monkey-patching or polyfills are just irrelevant in ReScript: if you miss a “method” on an “object” you don’t control, go ahead and write the desired new function in a module you do control and use it.&lt;/p&gt;

&lt;p&gt;Note, in the example above I used &lt;code&gt;ArrayX.last&lt;/code&gt; to get the last element of an array. The &lt;code&gt;Array&lt;/code&gt; module of the standard ReScript library does not include such a function, but I find it handy in this project. So I’m free to create a module (say, &lt;code&gt;ArrayX&lt;/code&gt;) and add whatever array utilities I find useful (e.g., &lt;code&gt;ArrayX.last&lt;/code&gt;). There are no agonies of choosing whether I should monkey-patch the built-in &lt;code&gt;Array&lt;/code&gt; object, inherit a new &lt;code&gt;Array&lt;/code&gt; class, or keep utilities in a module and have code with mixed method/function calls.&lt;/p&gt;

&lt;p&gt;In the same way, even if I were given the &lt;code&gt;Burger&lt;/code&gt; module as a library, I could extend it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === BurgerPreset.res ===&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addVegiLayers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;burger&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Onion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tomato&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cucumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Salat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use the new “method” afterthen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;freshburger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Double Fresh Burger"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecretSauce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;BurgerPreset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addVegiLayers&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BeefPatty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case you’re still too annoyed, ReScript offers two possible shortcuts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Opening a module brings all its functions&lt;/span&gt;
&lt;span class="c1"&gt;// to the scope of the current one&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;Burger&lt;/span&gt;

&lt;span class="c1"&gt;// Module aliases useful for more compact code&lt;/span&gt;
&lt;span class="c1"&gt;// still leaving the trails to the origin&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;BP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BurgerPreset&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;freshburger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Double Fresh Burger"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecretSauce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;BP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addVegiLayers&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BeefPatty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Immutable data
&lt;/h3&gt;

&lt;p&gt;Although nothing in the OOP paradigm forces you to change the values of objects’ fields, this is the default way to do the job when using classes. A method accesses fields of &lt;code&gt;this&lt;/code&gt; instance and changes their values. Or it calls another method on the nested child object that changes its values, etc. In other words, OOP traditionally &lt;em&gt;mutates&lt;/em&gt; data associated with objects on method calls.&lt;/p&gt;

&lt;p&gt;In contrast, the default way in FP languages is to hold on to data that never changes, the &lt;em&gt;immutable&lt;/em&gt; data. If you want to change the value of one field, you don’t. Instead, you &lt;em&gt;clone&lt;/em&gt; the data you want to change, keeping values for everything the same, except for the fields you want to change. Retake a look at our topping function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;burger&lt;/span&gt;, &lt;span class="n"&gt;layer&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;switch&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;ArrayX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&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;let&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;, ~&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// 👇 Clone!&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
       ...&lt;span class="n"&gt;burger&lt;/span&gt;,
       &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concatMany&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;, &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;, &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;,
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// 👇 Clone!&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; ...&lt;span class="n"&gt;burger&lt;/span&gt;, &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layer&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;The &lt;code&gt;...&lt;/code&gt; operator in ReScript clones a record copying all values over, except for the fields specified explicitly. So, the &lt;code&gt;addLayer&lt;/code&gt; function takes a &lt;code&gt;burger&lt;/code&gt;, makes a &lt;em&gt;new&lt;/em&gt; one which looks exactly like the original but with the additional layer, then throws the original one to a trash bin. I’d say it’s the direct opposite of OOP encapsulation, and this is the authentic way of FP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;kingburger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Special King Burger"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// make burger #1&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecretSauce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// make burger #2, throw away #1&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// make burger #3, throw away #2&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Onion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// make burger #4, throw away #3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, I know, it’s strange to throw away a burger and make a new one from scratch just to add a slice of cheese. Gordon Ramsay probably didn’t get it, so he failed to become a programmer (that’s good, actually). However, immutability has a massive effect on programs' simplicity and reliability for us, developers. Working with immutable data structures, you don’t even touch the problem of a shared state which is the source of so many bugs. Before changing a field, you don’t think which other system parts you can affect and how they will behave after that. You don’t think about inconsistent and incomplete data updates in a multithreading environment. You don’t think about orphan nested objects. You just don’t have to think broader than the function you’re writing or reviewing. Immutable data reduces so much stress.&lt;/p&gt;

&lt;p&gt;Everything has a cost, and the cost of immutability is performance. But the performance isn’t hit to an extent you might imagine. With guarantees of recursive immutability, creating a clone of a complex and deeply nested object is effectively done by creating one shallow copy at the outermost nesting level. All nested objects are reused in the copy because they cannot change anyway. So, cloning is cheap in most cases.&lt;/p&gt;

&lt;p&gt;And when absolutely required, ReScript offers escape hatches. Namely, the &lt;code&gt;mutable&lt;/code&gt; keyword can be applied to a record field declaration. Also, the standard library provides some in-place modification functions for potentially heavy operations. Such functions are explicitly named with caution (for example, &lt;code&gt;stableSortInPlaceBy&lt;/code&gt;) and return &lt;code&gt;unit&lt;/code&gt; (that is, “nothing”) to forbid further pipeline-style processing that could introduce implicit mutable dependencies. When you’re in the danger zone of conventional chaotic imperative programming, ReScript shows this apparently at the level of the language syntax and standard library design.&lt;/p&gt;

&lt;h3&gt;
  
  
  No null references
&lt;/h3&gt;

&lt;p&gt;Not obviously related to object-oriented programming or encapsulation in particular, there’s a curse in programming familiar to every developer. &lt;a href="https://en.wikipedia.org/wiki/Null_pointer"&gt;The billion-dollar mistake&lt;/a&gt;, the null reference. Yes, null pointers were introduced way before OOP, but I’m sure mainstream OOP languages like C++, Java, C#, then JavaScript ultimately escalated the problem to a historical extent. That’s because OOP is built around the concept of objects and that objects should be passed around somehow every time. They are passed by &lt;em&gt;reference&lt;/em&gt; (aka pointer) and the actual object behind this reference can be—well—the real object, or it can be a bomb which will crash the program once touched 🍔💥&lt;/p&gt;

&lt;p&gt;ReScript makes “undefined is not a function” impossible. Let’s take a look at our function one more time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;burger&lt;/span&gt;, &lt;span class="n"&gt;layer&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;switch&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;ArrayX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&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;let&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;, ~&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;
       ...&lt;span class="n"&gt;burger&lt;/span&gt;,
       &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concatMany&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;, &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;, &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;,
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; ...&lt;span class="n"&gt;burger&lt;/span&gt;, &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layer&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;First, because ReScript has no null references, you can be 100% sure that the arguments (&lt;code&gt;burger&lt;/code&gt; and &lt;code&gt;layer&lt;/code&gt;) are indeed valid data values, neither can be &lt;code&gt;null&lt;/code&gt;/&lt;code&gt;undefined&lt;/code&gt;. So the program will never crash operating on &lt;code&gt;burger.layers&lt;/code&gt;. Also, the layers array can never accidentally get a null layer that will be a time bomb ready to explode later. Beef, tomato, &lt;strong&gt;null&lt;/strong&gt;, cheese, anyone?&lt;/p&gt;

&lt;p&gt;Next, ReScript makes the possibility of an error obvious using one of the idiomatic functional programming mechanics. For example, in our case, &lt;code&gt;ArrayX.last&lt;/code&gt; returns an &lt;em&gt;option&lt;/em&gt; that can be &lt;em&gt;some&lt;/em&gt; value or &lt;em&gt;none&lt;/em&gt; if the array is empty. It sounds similar to what JavaScript does anyway, but there’s a vital difference. You are forced to check both outcomes; otherwise, ReScript compiler barks on you with an error.&lt;/p&gt;

&lt;p&gt;Ironic enough, this enforcement made it apparent that the same function implemented earlier in JavaScript is incorrect: it won’t add anything if a burger object has no layers. It should not happen in our simplistic model but inevitably will occur in a real system during its evolution.&lt;/p&gt;

&lt;p&gt;Again, there are escape hatches for the cases when you know what you do. ReScript has exceptions and unsafe routines when they are necessary. Such functions are conventionally named with precautionary suffixes like &lt;code&gt;lalaExn&lt;/code&gt;, &lt;code&gt;lalaUnsafe&lt;/code&gt; to warn you about the slippery floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Abstraction
&lt;/h2&gt;

&lt;p&gt;Abstraction is an OOP feature allowing you to hide implementation details of an object. You’re given an abstraction along with a well-defined interface, and you use it through this interface without thinking how it works under the hood. Let’s see again at our JavaScript class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Burger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BreadRoll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BeefPatty&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BreadRoll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cheeseburger&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;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cheeseburger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;cheeseburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s transparent that any object of type &lt;code&gt;Burger&lt;/code&gt; has a field named &lt;code&gt;layers&lt;/code&gt;, and that field is an array. It’s not obvious though, if I’m, as an object user, allowed to tweak or even access this field directly. After all, nothing can stop me from messing up layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cheeseburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a burger without bread on the bottom, which is unacceptable for our app. To solve the problem, OOP languages allow hiding some fields and methods of an object, making them private for the outside world. C++, C#, Java have class member keyword specifiers; Python, JavaScript recommend following a convention of starting private property names from an underscore &lt;code&gt;_&lt;/code&gt;. Modern JS also allows using hash &lt;code&gt;#&lt;/code&gt; prefix to mark a field private, so we’d better define our class this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Burger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BreadRoll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BeefPatty&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BreadRoll&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cheeseburger&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;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cheeseburger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;cheeseburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;cheeseburger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// error!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, no one outside the &lt;code&gt;Burger&lt;/code&gt; methods can shuffle the layers. It’s better protected from entering an invalid state now.&lt;/p&gt;

&lt;p&gt;Can we hide implementation details in functional programming as well? Easy. Not talking about all FP languages, ReScript has a couple of features that perfectly solve the problem. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interface files / module signatures&lt;/li&gt;
&lt;li&gt;opaque types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Earlier in the article, we implemented a &lt;code&gt;Burger&lt;/code&gt; module in the &lt;code&gt;Burger.res&lt;/code&gt; source file. Now we can add a &lt;code&gt;Burger.resi&lt;/code&gt; file next to &lt;code&gt;Burger.res&lt;/code&gt; to define the API of this module, effectively limiting how a consumer can use the module from the outside world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Burger.resi ===&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addLayer&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we declared the &lt;code&gt;t&lt;/code&gt; type in this interface file but didn’t provide any details of its underlying structure. That is an &lt;em&gt;opaque&lt;/em&gt; type. Having this restriction, a user can’t create arbitrary data values, possibly violating business rules. The only way to make a new burger now is the &lt;code&gt;make&lt;/code&gt; function: you give it a string (the title), you get your burger. Likewise, we declare the signature of &lt;code&gt;addLayer&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;If we’d add a new function, constant, type definition, or whatever to the &lt;code&gt;Burger.res&lt;/code&gt; implementation file now, they won’t be available anywhere outside of the &lt;code&gt;Burger&lt;/code&gt; module. You must also add them to the interface file to express the public “export” intent.&lt;/p&gt;

&lt;p&gt;In the example, we’ve created a module and then declared its interface. In practice, most of the time, I do the reverse: first, create an interface, and only after that write down the implementation. Focusing on the interface rather than implementation details at the first step forces you to imagine and design the best and cleanest API for your mini-library (consider modules are mini-libraries). And only after the well-shaped framework is ready, you complete it with minimally required implementation. Such workflow automatically makes you follow &lt;a href="https://en.wikipedia.org/wiki/KISS_principle"&gt;KISS&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it"&gt;YAGNI&lt;/a&gt; principles.&lt;/p&gt;

&lt;p&gt;Now we’ve hidden all the details behind a module signature. I’d say we’ve hidden too much. It’s no longer possible to get a burger name or layers put so far. Let’s fix it and evolve our signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Burger.resi ===&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="c1"&gt;// We don’t allow a burger to be renamed after construction,&lt;/span&gt;
&lt;span class="c1"&gt;// but of course, we provide a way to get the given name&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

&lt;span class="c1"&gt;// Get all layers. As long as we follow immutability requirements,&lt;/span&gt;
&lt;span class="c1"&gt;// do whatever you want with the result, it won’t affect the&lt;/span&gt;
&lt;span class="c1"&gt;// underlying burger data&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;layers&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addLayer&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple and clear API, isn’t it? It’s time to fill the gaps in the implementation, and that’s trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Burger.res ===&lt;/span&gt;

&lt;span class="cm"&gt;/* ... */&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;layers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I found this pattern of making all record types opaque and publishing just a minimal set of data getters/updaters super-typical for domain objects modeling. With only techniques shown up to this point, you can go very far, and probably your app does not require anything further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Inheritance
&lt;/h2&gt;

&lt;p&gt;OOP offers a mechanism of class extension when a new class declares it is based on some other class. In this case, the derived class &lt;em&gt;inherits&lt;/em&gt; all the properties and methods of the base class, then adds new stuff over this base. So, whenever we have several classes derived from the same base, we can be sure they all provide the goodness declared in the base class.&lt;/p&gt;

&lt;p&gt;Inheritance expresses the “is a” relation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Button is a UI Component&lt;/li&gt;
&lt;li&gt;Cat is an Animal&lt;/li&gt;
&lt;li&gt;Car is a Vehicle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our restaurant app, besides burgers, we could also serve cocktails. They both, burgers and cocktails, should be present in a menu where’s it is required to show their title, photo, and price. That title, photo, and price are properties they have in common because any such object “is a” product. However, the construction procedure differs; hence we have different object classes. Here’s a possible class hierarchy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h1VQ9HaO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rqfatgc2clbwf57ypsjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h1VQ9HaO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rqfatgc2clbwf57ypsjf.png" alt="Inheritance diagram" width="297" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In JavaScript, the hierarchy could be expressed like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;##&lt;/span&gt;&lt;span class="nx"&gt;hhDiscount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hhDiscount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;hhDiscount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hhDiscount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;discountForHappyHour&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;hhDiscount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Burger&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hhDiscount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hhDiscount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ... add the basic layers ...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&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;class&lt;/span&gt; &lt;span class="nx"&gt;Cocktail&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hhDiscount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hhDiscount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;drink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&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;Now, given a list of products, whether burgers or cocktails, a system can render a menu using the common fields and the method to compute a happy-hour price.&lt;/p&gt;

&lt;p&gt;The traditional question: how can I express inheritance in a functional programming paradigm? You don’t! Inheritance, like most practices in programming, is an ephemeral concept. You don’t inherit classes for the sake of inheritance; you’re trying to solve problems. And the problem inheritance tries to solve is providing a common ground across different entities. Let’s focus on that.&lt;/p&gt;

&lt;p&gt;OOP has a proven principle that any inheritance &lt;a href="https://en.wikipedia.org/wiki/Composition_over_inheritance"&gt;can be replaced with composition&lt;/a&gt;. This is useful because, in general, FP languages have no common inheritance mechanisms, but the composition is something built into their DNA. So, to the practice, how can we express &lt;code&gt;Product&lt;/code&gt;, &lt;code&gt;Burger&lt;/code&gt;, and &lt;code&gt;Cocktail&lt;/code&gt; in ReScript to render a menu of available items and keep the difference in construction? Bonus obstacle to overtake JS OOP inheritance: we already have the &lt;code&gt;Burger&lt;/code&gt; module from above, we are happy with it, we don’t want to change anything there.&lt;/p&gt;

&lt;p&gt;First, let’s model our menu render service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Menu.resi ===&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, we need a product, here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Product.resi ===&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;:
  &lt;span class="p"&gt;(&lt;/span&gt;
    ~&lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
    ~&lt;span class="n"&gt;imageUrl&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
    ~&lt;span class="n"&gt;price&lt;/span&gt;: &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;,
    ~&lt;span class="n"&gt;discount&lt;/span&gt;: &lt;span class="kt"&gt;float&lt;/span&gt;,
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;imageUrl&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;happyHourPrice&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good. But isn’t the product is too abstract? Yep, we’ve lost any traces of what the item is and how it is constructed. Let’s fix it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Product.resi ===&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 100% reuse&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;:
  &lt;span class="p"&gt;(&lt;/span&gt;
    ~&lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
    ~&lt;span class="n"&gt;imageUrl&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
    ~&lt;span class="n"&gt;price&lt;/span&gt;: &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;,
    ~&lt;span class="n"&gt;discount&lt;/span&gt;: &lt;span class="kt"&gt;float&lt;/span&gt;,
    &lt;span class="n"&gt;kind&lt;/span&gt;: &lt;span class="n"&gt;kind&lt;/span&gt;,
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;imageUrl&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;happyHourPrice&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I use the thing any FP language provides: an algebraic data type (ADT), known as &lt;em&gt;variant&lt;/em&gt; in ReScript. It’s a straightforward yet powerful concept. A value of a variant is strictly one of the enumerated cases along with the payload value(s) specified in parens. In this case, the product kind can be either a &lt;code&gt;Burger&lt;/code&gt; with &lt;code&gt;Burger.t&lt;/code&gt; payload we’ve implemented earlier or a &lt;code&gt;Cocktail&lt;/code&gt; with &lt;code&gt;Cocktail.t&lt;/code&gt; payload.&lt;/p&gt;

&lt;p&gt;Now, whenever I deal with a value of &lt;code&gt;Product.kind&lt;/code&gt; type, I’m forced to explain all the variants to the compiler, otherwise it will bark on me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;isAllowedBefore18&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prodKind&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;prodKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&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="kc"&gt;true&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;containsAlcohol&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;To recap, what was the fuss all about? To abstract burgers and cocktails enough so that the &lt;code&gt;Menu&lt;/code&gt; module could render a nice menu image for our restaurant without thinking much about what particular item is actually. Can we do it now? Definitely!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cheeseburger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cheese&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ... other instnances ...&lt;/span&gt;

&lt;span class="c1"&gt;// Most likely these would come from a DB,&lt;/span&gt;
&lt;span class="c1"&gt;// but many great things start with hardcode :)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;summerMenu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nn"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    ~&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Cheeseburger"&lt;/span&gt;,
    ~&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/f562e1f4.jpg"&lt;/span&gt;,
    ~&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;.&lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eur&lt;/span&gt;,
    ~&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;.&lt;span class="mi"&gt;5&lt;/span&gt;,
    &lt;span class="nc"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cheeseburger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;,
  &lt;span class="nn"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    ~&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Holy King Burger"&lt;/span&gt;,
    ~&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/ab1a63a0.jpg"&lt;/span&gt;,
    ~&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;.&lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eur&lt;/span&gt;,
    ~&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;.&lt;span class="mi"&gt;5&lt;/span&gt;,
    &lt;span class="nc"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;holyburger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;,
  &lt;span class="nn"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    ~&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Nonlynchburg Lemonade"&lt;/span&gt;,
    ~&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/b585a3c4.jpg"&lt;/span&gt;,
    ~&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;.&lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eur&lt;/span&gt;,
    ~&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;.&lt;span class="mi"&gt;25&lt;/span&gt;,
    &lt;span class="nc"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lemonade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;,
  &lt;span class="nn"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    ~&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"B52"&lt;/span&gt;,
    ~&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/8a5066aa.jpg"&lt;/span&gt;,
    ~&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;.&lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eur&lt;/span&gt;,
    ~&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;,
    &lt;span class="nc"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b52&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;,
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nn"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summerMenu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Team&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendToReview&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I were reading this text 10-15 years ago, I would complain: “— Bullshit! It’s hardcode! The generalized entity has to know all the concrete specifications, inflexible, cannot work!” The reality is that you can’t create an abstraction over an abstraction within an abstraction to model everything in the world. The actual business requirements evolve and show our mental models of classifying things become wrong at some point most of the time.&lt;/p&gt;

&lt;p&gt;The good news is the world is simple, actually! If you know you’re making software to manage burgers and cocktails only (OK, a product owner would add maybe appetizers and salads later), it’s perfectly OK to be explicit about it. If you know there will be hundreds of product kinds, go ahead and inverse the structure: let the specific types provide a &lt;code&gt;ProductDescription&lt;/code&gt; instead of keeping specific types inside a &lt;code&gt;Product&lt;/code&gt;. Be flexible, yet simple!&lt;/p&gt;

&lt;p&gt;And again, for the most complex scenarios, ReScript offers effective mechanisms like module functors to do metaprogramming. I don’t want to touch them in this article. They can make miracles more impressive than OOP tricks. And if you’d apply them just for a case, your code will become a hocus-pocus: fun for your mates, less fun to solve the problems. Everything has pros and cons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: Polymorphism
&lt;/h2&gt;

&lt;p&gt;The last pillar of OOP is &lt;em&gt;subtyping polymorphism&lt;/em&gt; also known as virtual methods or inherited methods overloading. The purpose is the following. You can be given a reference to an object that you think is an instance of some class (let’s call it &lt;code&gt;Base&lt;/code&gt;) and call its method (e.g. &lt;code&gt;doJob&lt;/code&gt;). But under the cover—and you neither know it nor want to know—this object can have a type of another class inherited from the &lt;code&gt;Base&lt;/code&gt; (let’s call it &lt;code&gt;Derived&lt;/code&gt;). In this case, instead of the code defined in &lt;code&gt;Base.doJob&lt;/code&gt;, the program will execute the code of &lt;code&gt;Derived.doJob&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before C-style classes came to JavaScript in ES6, I would say web devs rarely used OOP polymorphism because the JS-native prototype chain inheritance is too brain-bending for a casual developer. However, it was always a casual tool in other languages to delegate and split various problems. Now it is in JS as well. Imagine generating a minimalistic HTML menu for a given product list. The JavaScript code might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* ... */&lt;/span&gt;

  &lt;span class="c1"&gt;// Returns an HTML snippet to render a minimalistic&lt;/span&gt;
  &lt;span class="c1"&gt;// menu item in the following style:&lt;/span&gt;
  &lt;span class="c1"&gt;//&lt;/span&gt;
  &lt;span class="c1"&gt;// ***&lt;/span&gt;
  &lt;span class="c1"&gt;// Classic Omelet&lt;/span&gt;
  &lt;span class="c1"&gt;// (Eggs, Cheese, Onion, Parsley)&lt;/span&gt;
  &lt;span class="c1"&gt;// ***&lt;/span&gt;

  &lt;span class="nx"&gt;menuItemHtml&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;dt&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/dt&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;dd&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ingredientsString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/dd&amp;gt;&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="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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="nx"&gt;ingredientsString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Chef recipe&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;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Burger&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* ... */&lt;/span&gt;

  &lt;span class="nx"&gt;ingredientsString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;
      &lt;span class="c1"&gt;// exclude bread on the top and bottom as implied&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&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;l&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, &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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Cocktail&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* ... */&lt;/span&gt;

  &lt;span class="nx"&gt;ingredientsString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;drinks&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;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ml&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="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; / &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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;menuHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;dl&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;products&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;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;menuItemHtml&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/dl&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have the &lt;code&gt;ingredientsString&lt;/code&gt; method, which is polymorphic. It should give the customer an idea of what he orders. The method can be used on its own, but in particular, it is called by the base class &lt;code&gt;Product.menuItemHtml&lt;/code&gt; to generate the whole menu item markup used elsewhere while menu rendering. The trick with polymorphism is handy because the final result for burgers and cocktails is similar but different in detail. And method overloading can express this requirement in OOP.&lt;/p&gt;

&lt;p&gt;How can we express such polymorphism in ReScript? You know the answer: “we don’t!” Again, polymorphism is a synthetic concept employed to solve particular problems, not to use polymorphism on its own, right? All we need is to solve the given problem using the tools available. Variants to the rescue again! I even think it’s too similar to dealing with inheritance to the point of boring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Product.res ===&lt;/span&gt;

&lt;span class="cm"&gt;/* ... */&lt;/span&gt;

&lt;span class="c1"&gt;// Yes, boring dispatching based on the product kind&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientsString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ingredientsString&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ingredientsString&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;menuItemHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"&amp;lt;dt&amp;gt;"&lt;/span&gt;,
    &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;,
    &lt;span class="s2"&gt;"&amp;lt;/dt&amp;gt;"&lt;/span&gt;,
    &lt;span class="s2"&gt;"&amp;lt;dd&amp;gt;"&lt;/span&gt;,
    &lt;span class="s2"&gt;"("&lt;/span&gt;,
    &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ingredientsString&lt;/span&gt;,
    &lt;span class="s2"&gt;")"&lt;/span&gt;,
    &lt;span class="s2"&gt;"&amp;lt;/dd&amp;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="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our burger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Burger.res ===&lt;/span&gt;

&lt;span class="cm"&gt;/* ... */&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientsString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;burger&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;burger&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;, ~&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;burger&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinWith&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And cocktails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Cocktail.res ===&lt;/span&gt;

&lt;span class="cm"&gt;/* ... */&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientsString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cocktail&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;cocktail&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;drinks&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;drink&lt;/span&gt;, &lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nn"&gt;Drink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Volume&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#ml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;"ml"&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinWith&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boring? Well, yes. Unscalable? Not quite. Of course, when you have a dozen virtual methods, it &lt;em&gt;could&lt;/em&gt; become tedious to add &lt;code&gt;switch&lt;/code&gt;-based dispatching again and again. However, I cannot remember a single case when this particular point became boilerplate. First, it’s rare to have a really wide inheritance graph with all classes having their very specific method implementations: in most cases, they are all the same, and only 1 of 10 has something uncommon to say. Second, suppose you absolutely want inheritance polymorphism without dispatch boilerplate. In that case, ReScript offers module functors and first-class modules to achieve it, and I’m still ignoring them in the article because they are ninja-weapon for other issues, I bet it. Third…&lt;/p&gt;

&lt;p&gt;Which came earlier: the chicken or the egg? In our case, both should also know about HTML. So the question is going to expand! Which came earlier: the chicken, the egg, or the HTML?! What the hell should an egg think about its presentation on a menu? Should an egg be an expert in HTML, or maybe in PDF or SVG? Hell, no! For so many times, I saw objects that were too smart about the context they live in as I’m giving a high five to the famous quote.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.&lt;br&gt;—Joe Armstrong, creator of Erlang programming language&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The subtyping polymorphism is a beautiful idea that often does not sustain real-world requirements. In the example above, I’d group stuff related to the HTML-menu generation to a separate module leaving the essence untouched.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === HtmlMenu.res ===&lt;/span&gt;

&lt;span class="c1"&gt;// Hmm… not so dull. All rendering in a single place.&lt;/span&gt;
&lt;span class="c1"&gt;// This module is self-sufficient for solving the rendering problem.&lt;/span&gt;
&lt;span class="c1"&gt;// The original modules are free to remain dumb.&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientsString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// A potentially long switch that nevertheless allows you to imagine&lt;/span&gt;
  &lt;span class="c1"&gt;// and compare the outcome of different kinds of products&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Burger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;, ~&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;.&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinWith&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="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Cocktail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;drinks&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;drink&lt;/span&gt;, &lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nn"&gt;Drink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Volume&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#ml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;"ml"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinWith&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"&amp;lt;dt&amp;gt;"&lt;/span&gt;,
    &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;,
    &lt;span class="s2"&gt;"&amp;lt;/dt&amp;gt;"&lt;/span&gt;,
    &lt;span class="s2"&gt;"&amp;lt;dd&amp;gt;"&lt;/span&gt;,
    &lt;span class="s2"&gt;"("&lt;/span&gt;,
    &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ingredientsString&lt;/span&gt;,
    &lt;span class="s2"&gt;")"&lt;/span&gt;,
    &lt;span class="s2"&gt;"&amp;lt;/dd&amp;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="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, everything related to the HTML menu is nicely grouped in a dedicated module. Easy to read, easy to reason about, easy to change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s wrong with OOP
&lt;/h2&gt;

&lt;p&gt;Nothing. It is overpriced, though. OOP is given to us as a universal solution to all problems in mainstream development. Sure, you can go arbitrarily far just sticking to object-oriented patterns. The question is efficiency and development experience. Besides OOP, other worlds do exist. I’m not saying they are perfect, but we deserve to know the options. Luckily, alternative concepts leak into the mainstream world from time to time and become famous. Take React, for example; I’d say it is an object-oriented antipode; it differs a lot from UI frameworks that were popular before. I’m glad it got traction.&lt;/p&gt;

&lt;p&gt;The same is about ReScript. It’s a practical language for real-world development, albeit with a (relaxed) functional paradigm. ReScript also has lightweight JavaScript interop, so it’s easy to mix ReScript parts into an existing JS codebase and vice versa. Take your scale: if your wants for code reliability, simplicity, and robustness overweight the risk of employing new technology, give a chance to the functional programming with &lt;a href="https://rescript-lang.org/"&gt;ReScript&lt;/a&gt;. BTW, I’m not affiliated with the ReScript team anyhow; I’m just a humble, proud user 😌&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cross-posting. This post was originally published at&lt;/em&gt;  &lt;a href="https://fullsteak.dev/posts/from-oop-javascript-to-functional-rescript"&gt;https://fullsteak.dev/posts/from-oop-javascript-to-functional-rescript&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>rescript</category>
      <category>functional</category>
      <category>architecture</category>
    </item>
    <item>
      <title>ReScript JSON Typed Strongly</title>
      <dc:creator>Victor N.</dc:creator>
      <pubDate>Tue, 02 Nov 2021 19:37:56 +0000</pubDate>
      <link>https://dev.to/novak_20/rescript-json-typed-strongly-404b</link>
      <guid>https://dev.to/novak_20/rescript-json-typed-strongly-404b</guid>
      <description>&lt;p&gt;As a follow-up to the “&lt;a href="https://fullsteak.dev/posts/fullstack-rescript-architecture-overview"&gt;Full stack ReScript&lt;/a&gt;” post, I’d like to zoom in on an architectural layer that was intentionally omitted in that article to avoid focus blurring. Namely, the layer responsible for making strongly-typed and business-valid domain objects out of bits and bytes coming over the wire.&lt;/p&gt;

&lt;p&gt;More generally, how can we deserialize raw data provided as JSONs (or XML, or Protobuf, or whatever) into domain objects that make sense for the business logic and serialize them back?&lt;/p&gt;

&lt;p&gt;Go cooking! Imagine we’re making a cookbook application and have domain objects describing recipe ingredients. The app should be smart, allowing users to adjust the number of portions they want to cook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === RecipeDomain.resi ===&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Quantity&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;units&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#pc&lt;/span&gt; &lt;span class="c1"&gt;// pieces&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#tsp&lt;/span&gt; &lt;span class="c1"&gt;// tea spoon&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#tbsp&lt;/span&gt; &lt;span class="c1"&gt;// table spoon&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#cup&lt;/span&gt; &lt;span class="c1"&gt;// half a pint&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#ml&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#l&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#g&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#kg&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#oz&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#lb&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#clove&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;, &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

  &lt;span class="cm"&gt;/* Multiplies value by the given factor */&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rawValue&lt;/span&gt;: &lt;span class="n"&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="kt"&gt;float&lt;/span&gt;, &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="cm"&gt;/* Rounds value to nearest 1, ½, ⅓, or ¼ and converts
   units to more appropriate if possible */&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;humanValue&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#us&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#metric&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="kt"&gt;float&lt;/span&gt;, &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Ingredient&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;, &lt;span class="nn"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;IngredientList&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;, ~&lt;span class="n"&gt;numberOfPortions&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;numberOfPortions&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;originalNumberOfPortions&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While building our front-end app prototype, we work in this cozy land of business domain objects. At some moment we need to save the user’s recipe somewhere and be able to load it later. It might be our back-end or browser local storage. Can we pass &lt;code&gt;IngredientList&lt;/code&gt; there as is? The general answer is “no” because wire, file, and browser storage require a continuous sequence of bytes. In contrast, our domain object runtime presentation is unknown and is unlikely to be sequential in RAM.&lt;/p&gt;

&lt;p&gt;Well, technically you can use &lt;code&gt;IngredientList&lt;/code&gt; almost as is, as long as you’re developing in ReScript. It compiles to JavaScript, and JS objects ≈ JSON objects that trivially serialize into strings. But such way would be too fragile and unsafe 🤞&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the internal presentation of any domain object model changes, you break backward compatibility&lt;/li&gt;
&lt;li&gt;If data comes from an untrusted source (a user), you pass invalid and inconsistent data to the house&lt;/li&gt;
&lt;li&gt;The JSON schema can be already defined by another party: external service API or another team member&lt;/li&gt;
&lt;li&gt;A requirement to support other formats besides JSON can appear&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OK, domain objects and their JSON representation are different things, and we should learn how to transform one to another and back. For the example, we’re going to work with the following JSON shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"number-of-portions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jumbo Egg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2 pc"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Salt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1 tspn"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Milk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2 tbspn"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How do we convert between this and our &lt;code&gt;IngredientList&lt;/code&gt;? There’re obviously several ways to do it. I’ll describe one that might seem complicated at first sight. But it has proven to scale well if a project has many types of objects and messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three layers
&lt;/h2&gt;

&lt;p&gt;Yep, layers again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dXI6SIFZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4x4vykg3roujokolti2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dXI6SIFZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4x4vykg3roujokolti2h.png" alt="Layers" width="466" height="77"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first one we had described already: it’s the domain layer defining our &lt;code&gt;IngredientList&lt;/code&gt;, &lt;code&gt;Ingredient&lt;/code&gt;, and &lt;code&gt;Quantity&lt;/code&gt; objects. To keep architecture well-shaped, this layer must &lt;em&gt;not&lt;/em&gt; care about serialization/deserialization, know something about app message format, or even know anything about such thing as JSON. It should just do the business; constructing and destructing domain objects is others’ responsibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  DTO
&lt;/h3&gt;

&lt;p&gt;Next comes DTO layer. DTO stands for “Data Transfer Object.” This layer contains type definitions that more or less resemble the shape of JSON data. DTO layer is also responsible for converting DTOs to domain objects and back. In our case, it might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === RecipeDto.res ===&lt;/span&gt;

&lt;span class="c1"&gt;// This module works only with DTO types defined in it and domain&lt;/span&gt;
&lt;span class="c1"&gt;// object types. This domain `open` makes code less cluttered.&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;RecipeDomain&lt;/span&gt;

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

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;product&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
  &lt;span class="n"&gt;quantity&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ingredientList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;numberOfPortions&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt;,
  &lt;span class="n"&gt;items&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ingredient&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;// Converters&lt;/span&gt;
&lt;span class="c1"&gt;//======================================================================&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;unitsFromDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;: &lt;span class="nn"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;units&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;switch&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#pc&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"pc"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#tsp&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"tsp"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#tbsp&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"tsp"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#cup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"cup"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#ml&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"ml"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#l&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"ltr"&lt;/span&gt; &lt;span class="c1"&gt;// there might be difference&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#g&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"gr"&lt;/span&gt; &lt;span class="c1"&gt;// there might be difference&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#kg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"kg"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#oz&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"oz"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#lb&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"lb"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#clove&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"clove"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;unitsToDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"pc"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#pc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"tsp"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#tsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"tbsp"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#tbsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"cup"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#cup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"ml"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#ml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"ltr"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"gr"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"kg"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#kg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"oz"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#oz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"lb"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#lb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"clove"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#clove&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// it can fail&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#UnkonwnUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientFromDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredient&lt;/span&gt;: &lt;span class="nn"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="n"&gt;ingredient&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;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;, &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;product&lt;/span&gt;: &lt;span class="n"&gt;ingredient&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;,
    &lt;span class="n"&gt;quantity&lt;/span&gt;: &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;unitsFromDomain&lt;/span&gt;,
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientToDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;: &lt;span class="n"&gt;ingredient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;&amp;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;// Handle that non-machine-friendly "2 tspn" format&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;quantityR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;String2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&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="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;amountStr&lt;/span&gt;, &lt;span class="n"&gt;unitsStr&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;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amountStr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromString&lt;/span&gt;, &lt;span class="n"&gt;unitsStr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;unitsToDomain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;, &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;, &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;Ok&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;, &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#BadQuantityFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#BadQuantityFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;quantityR&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;product&lt;/span&gt;, &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientListFromDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredients&lt;/span&gt;: &lt;span class="nn"&gt;IngredientList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="n"&gt;ingredientList&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;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ingredients&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;IngredientList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;originalNumberOfPortions&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;numberOfPortions&lt;/span&gt;: &lt;span class="n"&gt;n&lt;/span&gt;,
    &lt;span class="n"&gt;items&lt;/span&gt;: &lt;span class="n"&gt;ingredients&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;IngredientList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;numberOfPortions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredientFromDomain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientListToDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;: &lt;span class="n"&gt;ingredientList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;IngredientList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;&amp;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="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;items&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredientToDomain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;ResultX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;IngredientList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;, ~&lt;span class="n"&gt;numberOfPortions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;numberOfPortions&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 might ask, what’s the point of creating another set of types that is similar to the set already defined in the domain layer?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain objects are opaque. We’re free to tweak their internal presentation without fear of breaking communication; DTOs are &lt;em&gt;transparent&lt;/em&gt; and much closer resemble the data shape rather than domain objects. And the difference between a DTO and a domain object is sometimes significant.&lt;/li&gt;
&lt;li&gt;Domain objects and DTOs can evolve independently. For example, DTOs may change in response to an API update, and business logic will not be affected.&lt;/li&gt;
&lt;li&gt;Domain objects include strict runtime checks to verify business rules and often make it impossible to have an invalid state; DTOs, on the other side, hold data as is providing only minimal validation like field presence or types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, the separation gives you more flexibility in the long run.&lt;/p&gt;

&lt;p&gt;Whew, we are almost done supporting our JSON data schema. But… where is JSON itself here?&lt;/p&gt;

&lt;h3&gt;
  
  
  Codecs
&lt;/h3&gt;

&lt;p&gt;Here comes codec layer. Its responsibility is converting between a basic primitive type such as &lt;code&gt;string&lt;/code&gt; or &lt;code&gt;Js.Json.t&lt;/code&gt; and data transfer objects. Why another layer in addition to DTO? It’s all about flexibility again. First, JSON field names might differ (e.g., use kebab-case-names) or imply some defaults; second, you are not limited to JSON only or a particular JSON parser. Having a dedicated layer allows creating different variations for different cases: full-fledged JSON parser/validator for user-facing JSONs, XML parser/validator for interaction with an external system, blind JSON “any-cast” for internal performance-critical message exchange.&lt;/p&gt;

&lt;p&gt;To build a solid JSON codec layer I use &lt;a href="https://github.com/nkrkv/jzon"&gt;Jzon&lt;/a&gt; library (disclosure: I’m the author of Jzon). Here are codecs which do the job for our ingredient list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === RecipeJson.res ===&lt;/span&gt;

&lt;span class="c1"&gt;// This `open` lets refer to DTO fields without prefixes&lt;/span&gt;
&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;RecipeDto&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// A function to convert DTO to a tuple that is friendly to Jzon&lt;/span&gt;
  &lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;product&lt;/span&gt;, &lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
  &lt;span class="c1"&gt;// A function to convert Jzon-friendly tuple back to DTO&lt;/span&gt;
  &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;, &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;: &lt;span class="n"&gt;product&lt;/span&gt;, &lt;span class="n"&gt;quantity&lt;/span&gt;: &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;,
  &lt;span class="c1"&gt;// Enumeration of fields comprising the tuple&lt;/span&gt;
  &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"product"&lt;/span&gt;, &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
  &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"quantity"&lt;/span&gt;, &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// The similar codec, but for another DTO. See Jzon docs for more examples&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;numberOfPortions&lt;/span&gt;, &lt;span class="n"&gt;dto&lt;/span&gt;.&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
  &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;numberOfPortions&lt;/span&gt;, &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;numberOfPortions&lt;/span&gt;: &lt;span class="n"&gt;numberOfPortions&lt;/span&gt;, &lt;span class="n"&gt;items&lt;/span&gt;: &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;,
  &lt;span class="c1"&gt;// here we handle a kebab-case-field-name used in JSON&lt;/span&gt;
  &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"number-of-portions"&lt;/span&gt;, &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
  &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"items"&lt;/span&gt;, &lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredient&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;Aren’t codecs just boilerplate? Indeed, they closely follow the shapes of data types defined in the DTO layer. But some code is anyway required to lift an arbitrary-shaped &lt;code&gt;Js.Json.t&lt;/code&gt; to well-defined DTOs. Someone has to write it down. I’m thinking about a tool to auto-generate Jzon codecs out of types defined in a DTO module. Perhaps it’s possible, but I’d leave it at the level of an idea until some actual demand.&lt;/p&gt;

&lt;p&gt;As I told already, you might use other tools to create the codecs layer. Take &lt;a href="https://github.com/glennsl/bs-json"&gt;&lt;code&gt;bs-json&lt;/code&gt;&lt;/a&gt; if it feels better. Or even force &lt;code&gt;Js.Json.t&lt;/code&gt; to DTO conversion with &lt;code&gt;Obj.magic&lt;/code&gt; if you know what you do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting all together
&lt;/h2&gt;

&lt;p&gt;Finally, all ropes are stretched across the layers. What’s next? We can use it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// === Serialize ===&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;myJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;ingredients&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RecipeDto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ingredientListFromDomain&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodeWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RecipeJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ingredientList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// === Deserialize ===&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ingredientsR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;myJson&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decodeWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RecipeJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ingredientList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;ResultX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;#JsonDecodingError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RecipeDto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ingredientListToDomain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;ingredientsR&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredients&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;/* show recipe to user */&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#JsonDecodingError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="cm"&gt;/* handle low-level error somehow */&lt;/span&gt;
  &lt;span class="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Jzon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;DecodingError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#BadQuantityFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&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;/* handle other errors, e.g. show an error in UI */&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#UnkonwnUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&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;/* handle other errors, e.g. show an error in UI */&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&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="cm"&gt;/* and so on */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Alternatives (or not)
&lt;/h2&gt;

&lt;p&gt;Isn’t this three-layer system too complicated to get a JSON object and just extract some field values? Maybe. However, in a system with many data types required to be serialized/deserialized, such layer separation adds its maintainability points, despite seemingly much boilerplate.&lt;/p&gt;

&lt;p&gt;Anyway, you always have alternatives to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/jeddeloh/rescript-apollo-client"&gt;ReScript Apollo Client&lt;/a&gt; generates type-safe bindings to GraphQL schemas. Nice option if you only develop the front-end part in ReScript and the server provides GraphQL API.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://json-schema.org/"&gt;JSON Schema&lt;/a&gt; might be used to describe data shape along with a validator such as &lt;a href="https://github.com/ajv-validator/ajv"&gt;Ajv&lt;/a&gt; to verify the validity of a JSON. This can save you from creating codec layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And in some quick’n’dirty or straightforward cases, you are free to just use &lt;code&gt;Object.magic&lt;/code&gt; to any-cast between &lt;code&gt;Js.Json.t&lt;/code&gt; and &lt;code&gt;{..}&lt;/code&gt;, then using this object fields directly hoping/knowing the fields are indeed there and have valid types.&lt;/p&gt;

&lt;p&gt;So, it all depends on your project. Pick a strategy and go ahead. You can always “upgrade” if it does not fit your needs later.&lt;/p&gt;




&lt;p&gt;This article was originally published at: &lt;a href="https://fullsteak.dev/posts/rescript-json-typed-strongly"&gt;https://&lt;strong&gt;fullsteak.dev&lt;/strong&gt;/posts/rescript-json-typed-strongly&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rescript</category>
      <category>serialization</category>
      <category>json</category>
      <category>ddd</category>
    </item>
    <item>
      <title>Full-stack ReScript. Architecture Overview</title>
      <dc:creator>Victor N.</dc:creator>
      <pubDate>Fri, 22 Oct 2021 15:03:20 +0000</pubDate>
      <link>https://dev.to/novak_20/full-stack-rescript-architecture-overview-d4j</link>
      <guid>https://dev.to/novak_20/full-stack-rescript-architecture-overview-d4j</guid>
      <description>&lt;p&gt;So, &lt;a href="https://rescript-lang.org/" rel="noopener noreferrer"&gt;ReScript&lt;/a&gt;. I guess you have heard about this beautiful and pragmatic language in the context of reliable and enjoyable web development. If you dive into learning resources around ReScript, you’ll see most of them focus on React/UI/front-end development, leaving the server-side with no attention. But can ReScript also be used to create a full-featured back-end? In this article, I’d try to prove it can and does it with success.&lt;/p&gt;

&lt;p&gt;I have two projects running in production, which are primarily done in ReScript (with some routine JS glue) from the front to the back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://futureco.world/?utm_source=fsd" rel="noopener noreferrer"&gt;Future Corporations&lt;/a&gt; — a multiplayer game for web and mobile platforms&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://figuro.me/?utm_source=fsd" rel="noopener noreferrer"&gt;Figuro&lt;/a&gt; — an on-demand laser cut service where a user uploads his drawing, chooses material, and voilà gets his widget delivered the next day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They both are small-scale, but I’m sure I found some architecture and patterns that would allow me to scale them quickly and easily if it is required. ReScript is one of the few options to do an entire project using the only platform in the functional programming paradigm. A project can be quickly done solo or by a small team, avoiding cognitive context switches, code duplication, etc.&lt;/p&gt;

&lt;p&gt;Let me unwind both project internals to show how they work on the high level leaving specific implementation details out of the scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: There’re infinite ways to shape your project. I’m describing just one possible way. I did not invent this architecture, but I gathered ideas from DDD (Domain Driven Development) and satellite paradigms, then projected them to ReScript. The suggested architecture might not fit your needs, but it works well for the projects I’m talking about.&lt;/p&gt;

&lt;p&gt;To be more specific, the article is not about ReScript. It’s about architecture. The same principles can be easily used with any FP language like F# or PureScript or even in a non-FP platform (JavaScript, TypeScript) if you follow functional programming principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  One message journey
&lt;/h2&gt;

&lt;p&gt;Even though projects use different transports, storage services, and deployment mechanisms, they share the same architecture. The architecture is made up of &lt;em&gt;layers&lt;/em&gt; that are strictly isolated and play different roles on the whole.&lt;/p&gt;

&lt;p&gt;Here’s how a typical user action and its corresponding reaction look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj99zr00yyuv9bcjkv4kw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj99zr00yyuv9bcjkv4kw.png" alt="What if a player pushed a “pew-pew” button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;😲 Quite many arrows and boxes for a single “Pew-pew,” right? Don’t be afraid; this is simplified; there’re more actually. However, every layer here is for a reason, and let’s take a look at them one by one from left to right. Depending on your project, you can omit some layers.&lt;/p&gt;

&lt;p&gt;Let’s walk through the most complex scenario.&lt;/p&gt;

&lt;h2&gt;
  
  
  Front-end
&lt;/h2&gt;

&lt;p&gt;Depicted as a single “React SPA” layer here, it contains more layers inside in practice. But the focus of this article is the server-side, so it is simplified. What’s important is that this layer often initiates requests on behalf of a user and renders responses to present results.&lt;/p&gt;

&lt;p&gt;Such requests are usually sent inside &lt;code&gt;React.useEffect&lt;/code&gt; or triggered by UI event handlers such as &lt;code&gt;onClick&lt;/code&gt;. The requests might be delivered via various transports. For example, in the Figuro web project, they are simple asynchronous HTTP requests. Whereas in the Future Corporations game, they are sent over websocket connection because a persistent connection better serves a real-time game with two-way communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON vs DTO
&lt;/h2&gt;

&lt;p&gt;A request usually contains some useful payload. This payload is sent over the wire, so it should be a basic structure serializable to a string or byte buffer. You know, JSON is a popular format to exchange messages, and I use it as well. However, it might be BSON, XML, protobuf, or a home-grown format.&lt;/p&gt;

&lt;p&gt;In a strongly-typed language such as ReScript (or F#, or PureScript), it is pretty impractical to deal with raw JSON (the &lt;code&gt;Js.Json.t&lt;/code&gt; type), so the first thing to do on a boundary is to convert it to a so-called DTO: data transfer object. DTOs are simple nested strongly-typed records that are trivial to convert to JSON and back. You’ll get no DTOs in JavaScript because JSONs &lt;em&gt;are&lt;/em&gt; DTOs already there, albeit without any checking 🤞&lt;/p&gt;

&lt;p&gt;In ReScript, you’d have another layer (not shown on the diagram for simplicity) to convert JSON to DTO and back. To illustrate the difference, here’s JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"buy-in"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"tax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and here’s DTO type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;buyIn&lt;/span&gt;: &lt;span class="kt"&gt;float&lt;/span&gt;,
  &lt;span class="n"&gt;tax&lt;/span&gt;: &lt;span class="kt"&gt;float&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference might seen minor (it is), but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;(a)&lt;/strong&gt; your can work with DTO fields semantically whereas it’s hardly possible with black-boxed &lt;code&gt;Js.Json.t&lt;/code&gt; (&lt;code&gt;data-&amp;gt;Js.Json.decodeObject-&amp;gt;Option.getExn-&amp;gt;Js.Dict.get("tax")-&amp;gt;Option.getExn-&amp;gt;Js.Json.decodeNumber-&amp;gt;Option.getExn&lt;/code&gt; anyone?),&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(b)&lt;/strong&gt; you can perform trivial invariant validations at the stage of conversion to check whether all fields are present or timestamps are specified in a proper ISO format.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite all fuzz, DTOs are intermediate technical objects that are not interesting to business logic. The business logic wants to work with &lt;code&gt;Money.t&lt;/code&gt; (and not &lt;code&gt;float&lt;/code&gt;) that places much more restrictions on the possible values, has several ways to present the data, etc. The conversion between a DTO and model is the responsibility of further layers. I mention it here to say that checking business rules is not a part of the JSON-to-DTO layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gateway layer
&lt;/h2&gt;

&lt;p&gt;Gateway is a process that listens on a public hostname and ports well-known to the front end. Its role is to route incoming requests further to a proper Server App and then passing responses back, possibly modifying message metadata. A gateway can be a ready-made solution such as NGINX reverse proxy, Kubernetes Ingress, or Traefik. Or it can be a small custom daemon if existing solutions do not fit. Your project will usually have zero or one gateway.&lt;/p&gt;

&lt;p&gt;In the case of the Figuro laser-cut web app, I have no gateway at all because it is a NextJS monolith at the moment, and all requests are sent directly to the Server App. But the Future Corporations game has a custom thin gateway that keeps websocket connections with clients on one side and NATS message queue on the other side. The gateway is some proxy that converts the websocket protocol suitable for clients’ browsers and mobile apps to NATS messages used to talk between server apps. It also does the reverse: looks for some NATS messages interesting to clients and, once found, forwards them to relevant recipients over websocket.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frf3472z225z1p1cnjevi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frf3472z225z1p1cnjevi.png" alt="Gateway"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Server app layer
&lt;/h2&gt;

&lt;p&gt;A server app, also called “service app” or “daemon,” is a thing that defines process boundaries. That is, a server app is a deployment unit. You run this thing as a Docker container, or with &lt;code&gt;pm2&lt;/code&gt;, or straight as &lt;code&gt;systemd&lt;/code&gt; service, whatever deployment strategy you choose.&lt;/p&gt;

&lt;p&gt;You’ll have one server app if you build a monolith or several (dozens, hundreds) if you build mini-/microservices. For example, the Figuro web app has a single app: the NextJS app itself. And the Future Corporations game has seven miniservices at the moment. Each server app is responsible for its own &lt;em&gt;activity&lt;/em&gt;: checking in players for a new online game (searching for opponents), customizing a player profile, holding and advancing running game state, triggering timeouts if a player has gone sleep, tracking statistics for further analytics, and so on.&lt;/p&gt;

&lt;p&gt;The activities themselves are served mainly by other layers: handlers, domain services, and domain models (described below). The primary purpose of the server app itself is to run all these layers and call them when necessary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8oba5ha2sh2qix7edqmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8oba5ha2sh2qix7edqmv.png" alt="Server app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the “App Module” at the chain start. This is the only code that actually belongs to the server app layer. Its mission is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read config (from environment variables, for example)&lt;/li&gt;
&lt;li&gt;Connect to network services, start listening on given ports&lt;/li&gt;
&lt;li&gt;Subscribe to MQ topics of interest or URL paths in case of HTTP&lt;/li&gt;
&lt;li&gt;Engage timers if the app acts as a cron-job rather than a network request handler&lt;/li&gt;
&lt;li&gt;Take requests, deserialize their payload, and forward them to Handler&lt;/li&gt;
&lt;li&gt;Serialize handling results and errors to send them back over HTTP or MQ&lt;/li&gt;
&lt;li&gt;Write logs&lt;/li&gt;
&lt;li&gt;Reply to health checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app layer is hardest to test because you’d have to issue actual HTTP requests or MQ messages and check responses the same way. Luckily, the App Module is easy to make very thin and almost boilerplate. I never cover this layer with tests.&lt;/p&gt;

&lt;p&gt;Summarizing the above, the Server App layer is technically just a container for other layers so that an OS can run the app. All interesting happens further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handler layer
&lt;/h2&gt;

&lt;p&gt;The handler layer knows what to do with requests. The hosting server app provides a handler with such requests in the form of &lt;em&gt;inbound messages&lt;/em&gt; such as “player acted,” “player has gone offline,” “room is full,” “timeout expired,” etc. The job of a handler is to take such message, convert its DTO payload to domain objects, perform actions, interact with a database or other external services, and finally return a list of &lt;em&gt;outbound messages&lt;/em&gt; such as “game updated,” “game finished” so that the caller can make responses. We know the caller is the server app, but the handler itself knows nothing about it.&lt;/p&gt;

&lt;p&gt;The handler layer is the last one that is allowed to perform IO and make side effects. For example, interact with the database, file system, or e-mail sending SaaS. They do it via adapters that are configured and provided by the hosting app module. To be more precise, it &lt;em&gt;is&lt;/em&gt; their primary duty. They act as clerks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decode incoming messages&lt;/li&gt;
&lt;li&gt;Read external storage&lt;/li&gt;
&lt;li&gt;Forward this further to the service layer, which actually makes business decisions&lt;/li&gt;
&lt;li&gt;Get decisions back and record the results in the database&lt;/li&gt;
&lt;li&gt;Encode domain objects back to DTO and return results to a caller&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s an example of check-in app handler interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;InboundMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CheckinMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InboundMessage&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;OutboundMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CheckinMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OutboundMessage&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="c1"&gt;// Possible results&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;handleResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;OutboundMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;ServerError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Room and Profile store are adaptors to interact with data in PostgreSQL database&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RoomStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;ProfileStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="c1"&gt;// The essense of a handler&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;InboundMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;handleResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And implementation outline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;InboundMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CheckinMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;InboundMessage&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;OutboundMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CheckinMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OutboundMessage&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CheckinService&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Command&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Event&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;AxEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Player&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Room&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LobbyDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Room&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;RoomTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LobbyDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RoomTable&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;RoomPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LobbyDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RoomPlayer&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;roomStore&lt;/span&gt;: &lt;span class="nn"&gt;RoomStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;,
  &lt;span class="n"&gt;profileStore&lt;/span&gt;: &lt;span class="nn"&gt;ProfileStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;handleResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;OutboundMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;ServerError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomStore&lt;/span&gt;, &lt;span class="n"&gt;profileStore&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="n"&gt;roomStore&lt;/span&gt;: &lt;span class="n"&gt;roomStore&lt;/span&gt;, &lt;span class="n"&gt;profileStore&lt;/span&gt;: &lt;span class="n"&gt;profileStore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;commandOrQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;//| Query(query); // no queries in this miniservice, only commands&lt;/span&gt;

&lt;span class="c1"&gt;// An inbound message is either a command to do something, or a query to read&lt;/span&gt;
&lt;span class="c1"&gt;// some data. This function interprets an inbound message segregating commands&lt;/span&gt;
&lt;span class="c1"&gt;// and queries. The latter are applied directly to stores skipping further&lt;/span&gt;
&lt;span class="c1"&gt;// processing layers.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;toCommandsAndQueries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt;,
    &lt;span class="n"&gt;inMessage&lt;/span&gt;: &lt;span class="nn"&gt;InboundMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;commandOrQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;, &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;inMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerPresenceUpdated&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;online&lt;/span&gt;: &lt;span class="kc"&gt;false&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;/* ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerPresenceUpdated&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;online&lt;/span&gt;: &lt;span class="kc"&gt;true&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;/* ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerGameStartSubscriptionUpdated&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;subscribed&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nn"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;UpdateWaitMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PlayerId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;, &lt;span class="n"&gt;subscribed&lt;/span&gt; ? &lt;span class="nc"&gt;OnlineAndOffline&lt;/span&gt; : &lt;span class="nc"&gt;OnlineOnly&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;Command&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;just&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nc"&gt;Ok&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;RoomJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;plainRoomAddress&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;/* ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;RoomLeave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&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;/* ... */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// No queries in this miniservice. But if there were a few, this function would&lt;/span&gt;
&lt;span class="c1"&gt;// query DB via store adapters.&lt;/span&gt;
&lt;span class="c1"&gt;//let handleQuery = (handler, query) =&amp;gt; raise(Exn.NotImplementedYet)&lt;/span&gt;

&lt;span class="c1"&gt;// This function reformats domain-level events to publicly consumable&lt;/span&gt;
&lt;span class="c1"&gt;// outbound messages if required&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;toOutboundMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;, &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;OutboundMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;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="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;profileStore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;
  &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;: &lt;span class="nn"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&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;switch&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;RoomCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&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="c1"&gt;// It is OK to not announce some events&lt;/span&gt;
      &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;

    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerJoinedRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nn"&gt;OutboundMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PlayerJoinedRoom&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;playerId&lt;/span&gt;: &lt;span class="n"&gt;playerId&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;PlayerId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toInt&lt;/span&gt;,
        &lt;span class="n"&gt;roomAddress&lt;/span&gt;: &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;,
        &lt;span class="n"&gt;buyin&lt;/span&gt;: &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buyin&lt;/span&gt;,
        &lt;span class="n"&gt;tax&lt;/span&gt;: &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tax&lt;/span&gt;,
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;just&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;

    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerLeftRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nn"&gt;OutboundMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PlayerLeftRoom&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;playerId&lt;/span&gt;: &lt;span class="n"&gt;playerId&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;PlayerId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toInt&lt;/span&gt;,
        &lt;span class="n"&gt;roomAddress&lt;/span&gt;: &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;,
        &lt;span class="n"&gt;refund&lt;/span&gt;: &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buyin&lt;/span&gt;,
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;just&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;

    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;RoomFilledUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomTable&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;/* ... */&lt;/span&gt;

    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;WaitModeUpdated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;, &lt;span class="n"&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="cm"&gt;/* ... */&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="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concatMany&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// React to events by sending update queries to our database&lt;/span&gt;
&lt;span class="c1"&gt;// through LalalaStore adapters. They effectivelly convert&lt;/span&gt;
&lt;span class="c1"&gt;// function calls to SQL expressions and execute them on DB&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;applyEventsToStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;, &lt;span class="n"&gt;events&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="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;roomStore&lt;/span&gt;, &lt;span class="n"&gt;profileStore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;
  &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runInSequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;: &lt;span class="nn"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;RoomCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;roomStore&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RoomStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerJoinedRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;roomStore&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RoomStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addPlayerToRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerLeftRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;roomStore&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RoomStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removePlayerFromRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;RoomFilledUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomTable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;roomStore&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RoomStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;markAsPlaying&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomTable&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RoomTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;WaitModeUpdated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;profileStore&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;ProfileStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;updateWaitMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handleCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;, &lt;span class="n"&gt;command&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;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;, &lt;span class="nn"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;, &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// The happy path: we execute a command, get events (their descriptions),&lt;/span&gt;
    &lt;span class="c1"&gt;// save data to DB and convert them to outbound messages&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;applyEventsToStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;handler&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;toOutboundMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;, &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JoinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomPlayer&lt;/span&gt;, &lt;span class="n"&gt;joinTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;, &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Custom error handling is possible when we express a domain error&lt;/span&gt;
    &lt;span class="c1"&gt;// as a valid scenario with its own message&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;roomAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;joinTarget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;roomAddress&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Existing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomTable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;roomTable&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RoomTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#RoomFull&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;#ALREADY_FULL&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#BadNumberOfPlayers&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;#BAD_ADDRESS&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#RoomDoesNotExist&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;#NOT_EXIST&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nc"&gt;RoomJoinError&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;playerId&lt;/span&gt;: &lt;span class="n"&gt;roomPlayer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;RoomPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;PlayerId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toInt&lt;/span&gt;,
        &lt;span class="n"&gt;roomAddress&lt;/span&gt;: &lt;span class="n"&gt;roomAddress&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;,
        &lt;span class="n"&gt;reason&lt;/span&gt;: &lt;span class="n"&gt;reason&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="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;just&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;, &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Generic error. The caller should log it, send to Sentry,&lt;/span&gt;
    &lt;span class="c1"&gt;// call admin whatever&lt;/span&gt;
    &lt;span class="nc"&gt;ServerError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nn"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stringifyAny&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getWithDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;not serializable error&amp;gt;"&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="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;just&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;, &lt;span class="n"&gt;inMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;toCommandsAndQueries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coqs&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;coqs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coqs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;coqs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runInSequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coq&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;coq&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;handleCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;//| Query(query) =&amp;gt; handler-&amp;gt;handleQuery(query)&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="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;concatMany&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;#BadJoinRoomAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;roomAddress&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;RoomJoinError&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="n"&gt;playerId&lt;/span&gt;: &lt;span class="n"&gt;playerId&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;PlayerId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toInt&lt;/span&gt;,
          &lt;span class="n"&gt;roomAddress&lt;/span&gt;: &lt;span class="n"&gt;roomAddress&lt;/span&gt;,
          &lt;span class="n"&gt;reason&lt;/span&gt;: &lt;span class="nc"&gt;#BAD_ADDRESS&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="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;just&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&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;Handlers are testable, not very convenient, but absolutely doable. The basic idea is to create a dedicated database for unit testing, which is erased and seed with demo data on each test case setup. Then, the test suite plays the role of the server app layer, asks to handle various messages, and checks handle results. Because handlers know nothing about hosting apps, the technique is straightforward. Such tests are slow, but they serve an important role in checking whether all layers are correctly glued and that IO works as expected with actual storage. In my case, handler tests comprise ~20% of all tests.&lt;/p&gt;

&lt;p&gt;In summary, the handler layer is a reusable module that forwards all pure-functional work further to the service layer and, on its own, does the dirty stuff. It converts domain objects to DTO and back, reads storage to prepare input for the service layer, writes storage to save the service layer output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service layer
&lt;/h2&gt;

&lt;p&gt;The service layer, also known as the “domain service layer,” is the first layer in the chain that is purely functional 🥰 It takes &lt;em&gt;commands&lt;/em&gt; along with domain models, applies business logic, and produces &lt;em&gt;events&lt;/em&gt; describing what happened. Here’s an example of such a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="nc"&gt;SimpleTypes&lt;/span&gt;

&lt;span class="c1"&gt;// Services use domain models extensively&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;AxEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Player&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Room&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LobbyDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Room&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;RoomTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LobbyDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RoomTable&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;RoomPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;LobbyDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RoomPlayer&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;joinRoomTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Existing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RoomTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Commands are variants designating desired action.&lt;/span&gt;
  &lt;span class="c1"&gt;// Their parameters contain minimal context to perform this action.&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JoinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RoomPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="n"&gt;joinRoomTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;LeaveAllRooms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RoomPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;UpdateWaitMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="nn"&gt;RoomPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waitMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;GoOffline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RoomPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Command might be rejected if it violates business contract&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#RoomFull&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#BadNumberOfPlayers&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#RoomDoesNotExist&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// If command applied successfully, zero or more events reported&lt;/span&gt;
  &lt;span class="c1"&gt;// as happened. A caller is responsible to record/report these events.&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;RoomCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerJoinedRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlayerLeftRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="nn"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;WaitModeUpdated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="nn"&gt;RoomPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waitMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;RoomFilledUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RoomTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The essense of a service&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;, &lt;span class="nn"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

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

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;: &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JoinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomPlayer&lt;/span&gt;, &lt;span class="nc"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FriendsRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;address&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;/* ... call domain models’ functions ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JoinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomPlayer&lt;/span&gt;, &lt;span class="nc"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GlobalRoomForTwo&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;address&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;/* ... call domain models’ functions ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JoinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomPlayer&lt;/span&gt;, &lt;span class="nc"&gt;Existing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomTable&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;/* ... call domain models’ functions ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;JoinRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;, &lt;span class="nc"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GlobalRoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&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="cm"&gt;/* ... call domain models’ functions ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;UpdateWaitMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerId&lt;/span&gt;, &lt;span class="n"&gt;waitMode&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;/* ... call domain models’ functions ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;GoOffline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomPlayer&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;/* ... call domain models’ functions ... */&lt;/span&gt;

  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;LeaveAllRooms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomPlayer&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;/* ... call domain models’ functions ... */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The services are joyful to test. They have no side effects, neither they have impure dependencies. You make a command, give it to &lt;code&gt;execute&lt;/code&gt;, and check the result. You might quickly craft dozens of tests for all the various flows and edge cases and be sure the business logic is rock solid.&lt;/p&gt;

&lt;p&gt;You might wonder why this layer exists and what the purpose of the long variant switches is. After all, the handler layer might directly call domain models’ functions. The reason is &lt;em&gt;composability&lt;/em&gt;. Different commands might produce the same events or intersecting sets of events. Similarly, various inbound messages can trigger the same commands. If not put in a dedicated service layer, the handler layer is going to blow up. However, if you have done the split this way, the service layer &lt;em&gt;offloads&lt;/em&gt; the handler layer, and the latter is only required to produce commands and handle events.&lt;/p&gt;

&lt;p&gt;Another reason lies in the canonical DDD methodology. What a system can do and what events it can produce is discussed with domain experts (developers talk to business people). The activity is known as “Event Storming.” And even if you don’t arrange such activity, understanding the possible ins and outs is likely to happen before you write an app. So, in practice, you typically create this layer and cover it with tests &lt;em&gt;before&lt;/em&gt; the handler layer even appears.&lt;/p&gt;

&lt;p&gt;In summary, the purpose of the service layer is to define how business works in terms of commands and events. The primary function is &lt;code&gt;execute&lt;/code&gt;, which gets a command, domain models to operate upon, calls necessary domain functions over these models to actually apply business logic, and finally produces output in the form of events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain layer
&lt;/h2&gt;

&lt;p&gt;Finally, the domain layer is a place where the most exciting things happen. A domain is what makes your project do something valuable and unique. It delivers business value. More specifically, it defines objects (aka models) and data types along with functions operating on them that together describe the world your app works with.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you make a game, the domain contains everything related to the rules and objects of the game.
If you make an online store, the domain would include concepts of a cart, order, product, coupons, and functions related to checkout, product comparison, and so on.&lt;/li&gt;
&lt;li&gt;If you make an online graphics editor, the domain would include all GFX math, paint tools, filter algorithms, etc, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's just one module interface from the Future Corporations game to give you a rough idea of how domain objects and functions can look like. It is responsible for a particular game state management; it defines the rules of the game (highly inspired by Monopoly):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 *
 * The central point of game logic engine
 *
 */&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Board&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Cluster&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Timeout&lt;/span&gt;

&lt;span class="c1"&gt;// Creates a new game room&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;
  ~&lt;span class="n"&gt;initialCash&lt;/span&gt;: &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;?,
  ~&lt;span class="n"&gt;initialSalary&lt;/span&gt;: &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;?,
  ~&lt;span class="n"&gt;bonusAmount&lt;/span&gt;: &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;?,
  ~&lt;span class="n"&gt;actionTimeout&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;?,
  ~&lt;span class="n"&gt;bidTimeout&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;?,
  ~&lt;span class="n"&gt;turnMissesBeforeKnockout&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;?,
  ~&lt;span class="n"&gt;skipWelcomeLogEntry&lt;/span&gt;: &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;?,
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="cm"&gt;/* number of players */&lt;/span&gt;,
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getNumberOfPlayers&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="cm"&gt;/*
  Returns a list like [0, 1, 2, 3] where number of elements is defined
  by the number of players in the game.
*/&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;listPlayers&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;countPlayersAt&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getPlayerState&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getWhoTurns&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getActivePlayerNextTo&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getSalary&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getAuction&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Auction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;hasAuction&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getCellOwner&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getMonopolyOwner&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getMortgageLimit&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="c1"&gt;// Returns property upgrade level (0 to 5); returns 0 if not a property&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getPropertyLevel&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;maySellCell&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;mayUpgradeProperty&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;mayDegradeProperty&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;isFinished&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;

&lt;span class="c1"&gt;// Winner goes at index #0, second place at #1, and so on&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getFinalRanks&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getTimeoutId&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getTimeoutDuration&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getTimeoutSettling&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getTimeoutPlayers&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getTurnMissesBeforeKnockout&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="cm"&gt;/* ====================================================================
 *
 * Game log manipulation
 *
 * ================================================================== */&lt;/span&gt;

&lt;span class="cm"&gt;/*
  Forcibly adds a new record to the log. Use to push non-game records and
  to consolidate the log when records are obtained via an alternative
  channel, such as network message
*/&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="cm"&gt;/*
  Steals log from the second game argument into the first inserting it
  before the current records. Useful to hydrate a game update that came
  with partial log only
*/&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;prependLogFrom&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getLog&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;clearLog&lt;/span&gt;: &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="cm"&gt;/* ====================================================================
 *
 * Actions
 *
 * ================================================================== */&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;applyDiceRoll&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;, &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;applyChance&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;passAuction&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;startAuction&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;giveUpAuction&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="cm"&gt;/*
  Makes a bid on the current auction. The bid is expected to be absolute,
  that is offered price, *not* price delta
*/&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bidAuction&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;upgradeProperty&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;degradeProperty&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sellOwnCell&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, &lt;span class="nn"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;acceptChance&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rejectChance&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;resign&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;, ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handleTimeout&lt;/span&gt;:
  &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;,
    &lt;span class="nn"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;,
    ~&lt;span class="n"&gt;roll&lt;/span&gt;: &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;, &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
    ~&lt;span class="n"&gt;takeChance&lt;/span&gt;: &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="c1"&gt;// Alternative interface (used to play with bot)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;act&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;,
  &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;,
  ~&lt;span class="n"&gt;player&lt;/span&gt;: &lt;span class="nn"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;,
  ~&lt;span class="n"&gt;roll&lt;/span&gt;: &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;, &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
  ~&lt;span class="n"&gt;takeChance&lt;/span&gt;: &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;,
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One crucial requirement to everything in the domain layer is functional &lt;em&gt;purity&lt;/em&gt;. In other words, domain layer functions cannot have side effects, perform IO, get the current time, generate random numbers, or do anything which can lead to behavior differences depending on the environment, current time, or process state. Neither they may take impure function arguments or return impure functions. This requirement may sound unreasonably strict, but it is pretty easy to satisfy once you see a pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When a domain function wants a value or object that cannot be obtained purely (say, the current time), add a parameter to this function that brings this value to the function scope (e.g., &lt;code&gt;~now: Js.Date.t&lt;/code&gt;). Let the caller do the dirty work.&lt;/li&gt;
&lt;li&gt;When a domain function wants to perform a side effect, return a simple record/object that &lt;em&gt;describes&lt;/em&gt; the desired effect. Let the caller apply it accordingly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the example provided, take a look at the functions &lt;code&gt;applyDiceRoll&lt;/code&gt; and &lt;code&gt;applyChance&lt;/code&gt;, for example. Instead of implicit random number generation when a player is going to roll a dice or pick a chance card, the engine “waits” for the caller to tell the outcome explicitly.&lt;/p&gt;

&lt;p&gt;Why so? The answer is simple. As long as you keep your domain pure, you can &lt;em&gt;test it effectively&lt;/em&gt;. Pure functions never require mocks, stubs, or any hacks. You literally test what you test, no less, no more. And as the domain layer contains most of the logic intrinsic to your application, keeping it pure makes it easy to have a comprehensive test suite covering all the business scenarios. In my particular case, more than 50% of the test code goes here. This gives you high confidence in your product. Multiply this by the sound and robust type system of ReScript, and you get an unbreakable core!&lt;/p&gt;

&lt;p&gt;A very attentive reader could spot purity violation in functions &lt;code&gt;handleTimeout&lt;/code&gt; and &lt;code&gt;act&lt;/code&gt;. Although they have no side effects, they have impure functions as parameters &lt;code&gt;roll&lt;/code&gt; and &lt;code&gt;takeChance&lt;/code&gt;. Yes, my fault. They were written before all the ideas of layer restrictions were crystallized in my head. As a consequence, this couple often causes pain while testing and composing. If I implement these functions today, instead of taking impure random-generation functions as arguments, I’d provide them with some kind of pure object called “Entropy” that already contains a sequence of a few specific pre-generated values with a knowingly enough length to perform any chain of a single turn game actions.&lt;/p&gt;

&lt;p&gt;In summary, the domain layer is your application heart. It is a collection of types, objects, functions that effectively do the job. The domain layer has no artificial requirements for its interface. You are free to shape and organize it in whatever way that makes more sense. The only vital requirement is functional purity, allowing heavy unit testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared domain
&lt;/h3&gt;

&lt;p&gt;You might note that I put the domain layer out of the “back-end” box on the original diagram. That’s because some portions of domain code can be shared across the back-end and front-end. And that’s where full-stack strategy really shines 🌟&lt;/p&gt;

&lt;p&gt;For example, the server and the mobile app use the same game domain logic in the Future Corporations game. On the server, it is used for multiplayer games (that is, the server updates the games), and in the app, absolutely the same code is used to run offline games against AI or friends in hot-seat mode.&lt;/p&gt;

&lt;p&gt;In the Figuro laser cut service, the same code is used by the client to compute manufacturing price instantly (without hitting a server) as a user uploads a new drawing or chooses another material and on the server at checkout to verify prices and avoid potential fraud.&lt;/p&gt;

&lt;p&gt;Cool eh? 😎 This would be impossible if front and back were developed in different languages.&lt;/p&gt;

&lt;p&gt;I think it’s clear that not all the domain code is reusable on both sides. So, most of the domain code is indeed belongs to the server. I just wanted to emphasize the possibility of uniform client/server-side usage in the cases when it makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back-end overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqoe9q5z6xag8yggyxgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqoe9q5z6xag8yggyxgf.png" alt="Backend summary"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s repeat in short what layers the back-end has and how they communicate.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gateway&lt;/strong&gt;. The only thing available publicly. Forwards messages forth and back between clients and server apps. For web apps, you’d likely use a ready-made solution like NGINX or Traefik. For real-time apps based on websockets, this would probably be a thin OS service connected to some message broker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server app&lt;/strong&gt;. A deployment and replication unit. Hosts all further layers inside itself. The primary responsibility is to listen for messages, convert wire data to DTO and back, perform logging, read configs, keep connections to external services. Hardly testable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handler&lt;/strong&gt;. Communicates to external services and databases, converts DTO to domain objects and back, interprets inbound messages to commands and events to outbound messages. Quite testable using external service stubs and dedicated unit-test databases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt;. Applies commands to domain objects and generates command consequence events. Functionally pure. Directly testable with no hacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain&lt;/strong&gt;. Business domain objects and functions. No restrictions on API. Functionally pure. Directly testable with no hacks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  One sandwich with onion, please
&lt;/h2&gt;

&lt;p&gt;What else besides software architecture have layers? Yep, onions and sandwiches. That’s why they became metaphors for software engineering. And if I happened to explain the concepts clearly, you almost already know what “Onion architecture” and “Impure-pure-impure sandwich” are. These terms are just another view on the things already explained. Let’s repack the concepts so that you can keep the talk with your mates in a bar.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;— We use onion architecture 🤘 &lt;br&gt;&lt;br&gt;
— Me too!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hxag1zuo1cm8muperfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hxag1zuo1cm8muperfd.png" alt="Onion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The point of all buzz around the onion architecture is having well-defined layers with a unified coupling direction. We have this. Domain knows nothing about the service layer; the service layer knows nothing about handlers; the handlers don't know anything about the app layer. Onion done!&lt;/p&gt;

&lt;p&gt;Topics to discuss in a bar: do external services belong to the onion skin, and how deep they might be coupled with outer layers?&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;— We make impure-pure-impure sandwiches 🤤 &lt;br&gt;&lt;br&gt;
— Me too!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9nj2fv8669exsynsad8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9nj2fv8669exsynsad8.png" alt="Sandwich"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The metaphor about the sandwich is all about shifting side effects to an operation boundary so that the middle layer (the stuffing) might be easily testable. We have this. The service app layer is highly impure and hard to test, the handlers are impure too (yet testable), and the service layer, along with the domain layer, is pure, juicy, and easily testable.&lt;/p&gt;

&lt;p&gt;Topics to discuss in a bar: is it OK to say that processing with FFmpeg or ImageMagick may belong to the stuffing layer? Does the answer change if I won’t call them as a subprocess but use NodeJS bindings and make the transform in-process?&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;The architecture described in this article is just one way to do things. You might follow it, or follow it partially, or ignore it and build your project in a completely other fashion. I aimed to describe a possible way to structure code sustainable enough to survive medium-scale. If you’re making a small-scale intranet utility, it is OK to mash all the logic in a single layer. If you’re big and looking for super-hi-load recipes, you don’t read these words. And if you are a solo developer or a small dev team member planning to rule the world, I’d be happy if I helped a little.&lt;/p&gt;

&lt;p&gt;A minute of insolence: if you like the article, I’d appreciate it if you rate &lt;a href="https://play.google.com/store/apps/details?id=world.axfx.futureco" rel="noopener noreferrer"&gt;Future Corporations&lt;/a&gt; on Google Play. It’s my side project, but I put much effort into it. And because I’m stupid in marketing, one ad campaign brought me a pack of 1-star ratings. I would be happy to recover, but only if you really like the game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-post
&lt;/h2&gt;

&lt;p&gt;This post was originally published at &lt;a href="https://fullsteak.dev/posts/fullstack-rescript-architecture-overview" rel="noopener noreferrer"&gt;https://fullsteak.dev/posts/fullstack-rescript-architecture-overview&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rescript</category>
      <category>ddd</category>
      <category>backend</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Mobile game with ReasonML/ReScript and React: my experience</title>
      <dc:creator>Victor N.</dc:creator>
      <pubDate>Wed, 16 Dec 2020 13:00:15 +0000</pubDate>
      <link>https://dev.to/novak_20/mobile-game-with-reasonml-rescript-and-react-my-experience-33j0</link>
      <guid>https://dev.to/novak_20/mobile-game-with-reasonml-rescript-and-react-my-experience-33j0</guid>
      <description>&lt;p&gt;Hello everyone! When the Covid pandemic started, I've got some extra time and decided to use it to create a game for mobile and web platforms. I wanted to resurrect one cool multiplayer remake of a board game that shut down ten years ago. Since a digital tabletop game sounds like something which might be done without fancy 3D graphics, I decided to outwalk traditional tools like Unity and make everything like a web application. The first reason is that I have no experience with Unity, and the second reason is Reason 😄 I mean ReasonML, an emerging strongly typed language tightly integrated with React, which compiles to JavaScript.&lt;/p&gt;

&lt;p&gt;ReasonML has a powerful type system that makes the development really joyful and surprisingly reliable, and bug-free. I've got some experience with ReasonML for classic web development, so it shouldn't take more than 2-3 months of evening/weekend programming to complete the game. Oh, I was mistaken. Nevertheless, the game is released and playable.&lt;/p&gt;

&lt;p&gt;And now I want to share the experience of making a mobile game using &lt;a href="https://docs.expo.io/" rel="noopener noreferrer"&gt;Expo&lt;/a&gt; + &lt;a href="https://reason-react-native.github.io/en/docs/" rel="noopener noreferrer"&gt;React Native&lt;/a&gt; + &lt;a href="https://rescript-lang.org/" rel="noopener noreferrer"&gt;ReasonML/ReScript&lt;/a&gt; + NodeJS stack. I'm writing this article for JavaScript web developers thinking about making a mobile app or a 2D game similar to an app. There are a few roads to choose from, and this article describes my path to hopefully make things a bit clearer.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML and SVG for graphics
&lt;/h2&gt;

&lt;p&gt;Although I have no 3D graphics, the game itself is far from being similar to a web page with text and pictures. The game screen looks like this:&lt;/p&gt;

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

&lt;p&gt;As you may see, there are plenty of elements that would be hard to implement just with HTML + CSS. SVG to the rescue! What's cool is that SVG might be easily embedded into the big HTML picture. So, I'm using HTML for the top-level layout, whereas in tight places, I employ SVG to draw some ellipses, arrows, shines, etc.&lt;/p&gt;

&lt;p&gt;For example, the game board, player stats pane, and action buttons are laid out with HTML flex containers, whereas the elliptic TVs with player avatars and cash counters are rendered with SVG primitives. The use of HTML on the top-level benefits from simple compatibility with various screen sizes and their aspect ratios. And you'll find there's almost an infinite number of screen parameter permutations on Android.&lt;/p&gt;

&lt;p&gt;Does the HTML + SVG combo scale well for any graphic effects? Unfortunately, no. Even in my case, I stumbled upon the absence of a feature to manage raster image colors with a relatively simple scene. By design, a player may change the color of his/her car used as an avatar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs5m8eo3ulerb6b5d35gb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs5m8eo3ulerb6b5d35gb.png" alt="Avatars of different colors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The cars themselves are quite complex art pieces, so they are rasterized before using them in the game. I need to rotate the hue of the color in places denoted by a mask stored in another image. This cannot be done with SVG. The only option I found is going deeper and use OpenGL to solve this particular problem. That is, take the input images, do the required color processing with a low-level fragment shader, and return the result back to the "web world." To be honest, I haven't done partial recoloring yet — the whole car is recolored at the moment — but it does not make a difference in understanding the big picture. Falling back to OpenGL when necessary works but not without some issues. The main problem here is performance: although rendering a frame is blazing fast (10 ms in my case), snapshotting and transferring the frame back to the world of image tags and PNGs introduces a penalty of ~150 ms. It makes it impossible to use OpenGL in this way in real-time. You have to either keep some parts of the screen (or the whole screen) in the OpenGL world forever or use it only to prepare/process some resources once. Now I use the latter and recolor the cars right before the game when players' appearance is known.&lt;/p&gt;

&lt;p&gt;To put summary, the HTML + SVG combo is excellent for graphics if you don't require some unique effects. For anything non-standard, OpenGL could help, but you'd either stick to OpenGL altogether, dropping HTML and SVG, or use it only when a game "level" loads.&lt;/p&gt;

&lt;h2&gt;
  
  
  React as GUI framework
&lt;/h2&gt;

&lt;p&gt;OK, HTML and SVG can make the scene, but how should we translate the current game state to the proper UI tree and UI actions back to game state handlers? One could use vanilla JS, but in the case of a complex app such as the game, it will quickly become quite complicated. At the very best, it would lead to creating a new framework from scratch. It might be interesting but wasn't my purpose.&lt;/p&gt;

&lt;p&gt;The natural choice for me was employing React. As you likely know, React is a declarative UI framework that fits perfectly with the functional programming paradigm. The ReasonML/ReScript language is primarily functional and even includes support for React-style markup (like JSX) right into the language.&lt;/p&gt;

&lt;p&gt;In general, using React Native along with React Native SVG is very productive to get the first results quickly. The whole game is easily split into dozens of well-encapsulated components. In turn, the components might be quickly inspected visually and in various states one by one, without waiting for a proper game situation. Thanks &lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt; for that.&lt;/p&gt;

&lt;p&gt;Of course, nothing can be perfect, and React is not an exception. One of the problems is performance. I'm not saying React is slow, but you can easily make a "mistake," which will cause the whole component tree to re-render. The re-render will happen even if all that has been changed is the color of one hair-width line in the bottom-right corner of a small icon, which is, in fact, hidden by another element right now. These excessive re-renders make the app jerky. You'll have to carefully catch all such moments with React developer tools to analyze why the undesired computational spike has appeared and polish this snatch by properly memoizing some heavy UI parts. Once you've spotted all such moments, the game becomes performant and joyful to play.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Native for mobile
&lt;/h2&gt;

&lt;p&gt;The original React framework is designed to drive in-browser single-page applications. But the applications for Android and iOS are &lt;em&gt;not&lt;/em&gt; web pages. They are freestanding beasts that should be developed natively with Kotlin and Swift. How should a web app appear as a full-fledged mobile app? Here comes React &lt;em&gt;Native&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;React Native is a specific subset of the general React which has &lt;code&gt;&amp;lt;View&amp;gt;&lt;/code&gt;'s instead of &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;'s, &lt;code&gt;&amp;lt;Text&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, no &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;, own CSS-in-JS framework, etc. While it might seem to limit the expressiveness, I didn't suffer from it in practice. At least in the game project where most UI elements are custom and created from scratch in any case. These all are minor problems compared to the HUUUGE benefit: you develop once and build for all the platforms at once: Web (for desktops and mobile without installation), Android, iOS.&lt;/p&gt;

&lt;p&gt;This is what the docs promise. In practice, React Native is buggy, glitchy, scattered, and non-obvious in many places. I'm not blaming anyone. The framework is massive and unprecedented, but it almost made me scream and smash the laptop.&lt;/p&gt;

&lt;p&gt;Here is a fraction of the problems you might face:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No box shadows on Android: do it yourself&lt;/li&gt;
&lt;li&gt;At most one text-shadow may be specified&lt;/li&gt;
&lt;li&gt;Text nested Text does not work on Android if it changes font face&lt;/li&gt;
&lt;li&gt;SVG nested in SVG does not work correctly on Android&lt;/li&gt;
&lt;li&gt;SVG images stored as built-in asset files do not work on Android&lt;/li&gt;
&lt;li&gt;SVG effects are not available: no shadows, no blur, nothing&lt;/li&gt;
&lt;li&gt;Custom fonts do not work in SVG on Android&lt;/li&gt;
&lt;li&gt;SVG interactions do not work&lt;/li&gt;
&lt;li&gt;Preloading of fonts does not work on web&lt;/li&gt;
&lt;li&gt;Preloading of SVG does not work on web&lt;/li&gt;
&lt;li&gt;Linear gradients are not available via styles; however, they are available as a 3-rd party component, but it flickers on the first render&lt;/li&gt;
&lt;li&gt;Radial gradients are not available&lt;/li&gt;
&lt;li&gt;CSS animations are not available&lt;/li&gt;
&lt;li&gt;Hardware-accelerated animations are not available on the web&lt;/li&gt;
&lt;li&gt;SVG stroke opacity animation is broken on Android&lt;/li&gt;
&lt;li&gt;In contrast to the browser, the mobile app can suddenly crash on something as innocent as an arc path with zero radius; hard to find the reason&lt;/li&gt;
&lt;li&gt;Sub-pixel rounding is buggy on Android, causing ±1 pixel gaps and overflows&lt;/li&gt;
&lt;li&gt;Absolute positioning inside a reverse-order flexbox is broken on Android&lt;/li&gt;
&lt;li&gt;Z-index does not work on Android&lt;/li&gt;
&lt;li&gt;etc, etc, etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I haven't touched iOS yet but expect a pile of problems too, extrapolating what I've got with Android. Making the already functional web-version work on Android took me ~30% of the time spent implementing the rest of the game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Animations is a pain
&lt;/h2&gt;

&lt;p&gt;React Native offers its own animation subsystem known as &lt;a href="https://reactnative.dev/docs/animated" rel="noopener noreferrer"&gt;Animated&lt;/a&gt;. So, what's wrong with it? Well, nothing once you get it, but the process of describing the animation is time-consuming and somewhat non-intuitive, especially in cases with long tracks of tricky intermediate keyframes, sequences, and perfect-timing. It's like trying to program an image directly out of your head, bypassing any trial in a graphic editor: doable but complicated. I'm missing the ability to 100% offload some animations to an artist as I can do with illustrations. That's the reason I had to skip implementing most of the animations before the release. Many of them are still on the TODO-list.&lt;/p&gt;

&lt;p&gt;What makes animations even more problematic is the architecture of React Native, which runs them by default on the same thread as the JavaScript code. So, if you do something in JS at the same time when an animation is running, you lose frames, and the app looks snatchy.&lt;/p&gt;

&lt;p&gt;There's a way to offload animation to another "fast" thread. Still, it should be carefully planned, and the only values allowed to animate in this case are non-layout properties such as translation, rotation, scale, and color.&lt;/p&gt;

&lt;p&gt;In summary, animations in React Native are somewhat a bottleneck that can be worked around, but it takes so much development energy.&lt;/p&gt;

&lt;h2&gt;
  
  
  ReasonML/ReScript as language
&lt;/h2&gt;

&lt;p&gt;If I'd been a more mainstream web-developer, I use TypeScript to program the React Native app. But some time ago, I was infected by the ideas of functional programming and saw no road back. One of the project requirements was having a shared codebase for the front (the app) and the back (multiplayer server). Filtering the possible language options (Elm, F#, Dart, PureScript, Haskell) through this matrix, not so many variants were left, and I've chosen RasonML/ReScript.&lt;/p&gt;

&lt;p&gt;Long story short, the exotic language is the most joyful and robust tier in all the technology stack. The strong yet flexible type system, very simple JS interop, FP-first, and built-in React markup syntax is a breath of fresh air compared to the vanilla JS or TypeScript.&lt;/p&gt;

&lt;p&gt;If the project ended up to compile successfully, I'm very confident in the quality of the result. There are no null-pointer exceptions (no exceptions at all if you wish), no forgotten if/else and switch/case paths, no data inconsistency, and fearless refactoring. Any programming should look like this.&lt;/p&gt;

&lt;p&gt;ReasonML/ReScript compiles to JavaScript, so I could write a shared game engine for both: the client app and multiplayer server. The client then is built further with React Native, and the server is running with NodeJS. The project is 95% ReasonML/ReScript. The rest is trivial JavaScript glue.&lt;/p&gt;

&lt;p&gt;One particular outcome of choosing a functional language for the back-end was learning DDD (Domain Driven Development) development and its satellites: the onion architecture, CQRS, and friends. These techniques have initially been formulated using Java but the core ideas a so much better aligned with functional programming. I'm pleased with well-structured and easily extensible services that are simple and intensively tested with almost no mocks, stubs, fakes, and other hacks considered to be "normal" for some reason.&lt;/p&gt;

&lt;p&gt;So, does ReasonML/ReScript is a perfect language? No, unfortunately. And the reason is the slash between the two words. To be more precise, the reasons are political and not technical. ReasonML and its successor (?) ReScript evolve since 2016. ReasonML is a language built on top of OCaml: the niche OCaml's power with the syntax familiar to JS developers. Then, there was a thing called BuckleScript (BS), which compiles OCaml (or ReasonML) to JavaScript. The community targeting the JS platform was fragmented a little: the old school part used OCaml syntax, and the newcomers used ReasonML. This was annoying, but since both languages are just different presentations of the same abstract syntax tree, the library ecosystem was (and is) 100% compatible. Arguably the community center of the mass has slowly moved toward ReasonML, and it got the traction. But recently, the core team made a sudden step and released ReScript: the third syntax in a row that no longer 100% compatible with OCaml AST. At the same time, ReasonML and OCaml BS were deprecated. This happened in a single day, and many people (including me) were left with projects written in deprecated languages. The community was fragmented again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BS OCaml is killed&lt;/li&gt;
&lt;li&gt;ReasonML is forked now and maintained by others, slowly-slowly shifting toward OCaml&lt;/li&gt;
&lt;li&gt;ReScript is the new official, but have a minimal user base&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, there are tools to almost automatically convert ReasonML to ReScript (which look very similar at the bottom line). But I haven't done it because I not sure what else harsh steps the core team might perform, and I have many things to polish before such risky updates. I'm waiting for some clarification and opacity. AFAIK, some Facebook funds are floating around ReScript (formerly around ReasonML), and it can be abandoned if Facebook will stop investing. It might be a good idea to hold on and see the direction of evolution and try to guess Facebook's rationale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expo as app platform
&lt;/h2&gt;

&lt;p&gt;Is React Native enough to get a working app targeted to multiple platforms? Technically it is. But apart from UI, an app is likely to require some other features from the device: the camera, file system, location, or something like this. Here comes &lt;a href="https://docs.expo.io/" rel="noopener noreferrer"&gt;Expo&lt;/a&gt;. It's a platform built on top of React Native, which provides access to APIs mentioned in a cross-platform fashion.&lt;/p&gt;

&lt;p&gt;My game uses the minimum of such APIs (splash screen, local storage, OpenGL interface). Still, even with such small requirements for me, a programmer who develops for mobile for the first time, Expo is very valuable and simplifies the standard tasks.&lt;/p&gt;

&lt;p&gt;API access is cool, but the most critical thing Expo offers is the OTA (Over the Air) updates. Do you realize that mobile apps are much more familiar to the good old desktop apps in the sense of deployment? You publish an update and don't know when a user will update your app and whether they are going to update it at all. Things get worse if your app is a client to some online service: evolving the service, you always have to keep in mind that some clients can use the one-year-old stale version of your app. In the case of Google Play Store, even if the users are eager to get new features, any new version has to pass moderation, which takes some random amount of time between two hours and several days. Albeit not a secret, it might come surprising for a web-developer that the deployment takes days, not seconds.&lt;/p&gt;

&lt;p&gt;OTA updates help a lot here. When you publish an update, an incremental changeset is generated and stored on Expo's CDN (or your CDN if you want). Then, when a user launches your app, it downloads the required updates in the background, and the next time the app is restarted, the user sees its latest version. All this without waiting for Google Play moderators or the mass app update night.&lt;/p&gt;

&lt;p&gt;Another invaluable thing Expo offers is its mobile app to quickly preview what you get on the device without the full build/reinstall/restart cycles. Make a change, wait a few seconds, and you see almost the same result you'll get if you build a stand-alone APK.&lt;/p&gt;

&lt;p&gt;Last but not least, Expo provides its build server facilities to bundle the app for Android or iOS without having the respective toolchains installed. This provides a quick start and simplifies CI configuration. You can build locally if you want, but in my case, at least in theory, the feature will allow building for iOS without having to buy a MacBook (I use Arch, BTW): iPhone stolen from my wife would be enough for tests.&lt;/p&gt;

&lt;p&gt;In summary, Expo adds a lot to the React Native base. It is a for-profit project which introduces another little layer of WTF's and bugs, and at the same time, Expo offers an obvious way to eject if you want to jump off, and the benefits it gives are greatly outweighing the costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version hell
&lt;/h2&gt;

&lt;p&gt;One problem you should be mentally prepared for is package version hell. Do you remember that the ReScript platform (e.g. version 8.4.0) and ReasonML (e.g. version 3.6.0) are different things? To work with React a binding library is required (e.g. &lt;code&gt;reason-react&lt;/code&gt; version 0.9.1 and &lt;code&gt;reason-react-native&lt;/code&gt; version 0.62.3). Expo (e.g. version 39.0.0) has its own expectations on the version of &lt;code&gt;react-native&lt;/code&gt; (e.g. version 0.63.0), which in turn requires a specific version of &lt;code&gt;react&lt;/code&gt; (say, 16.3.1), which can differ from what &lt;code&gt;reason-react&lt;/code&gt; wants. I'm not saying &lt;code&gt;reason-expo&lt;/code&gt;, &lt;code&gt;react-native-svg&lt;/code&gt;, and &lt;code&gt;@reason-react-native/svg&lt;/code&gt; are all separate packages with their own versioning rules and dependency styles 🤯&lt;/p&gt;

&lt;p&gt;Solving this puzzle is not always a trivial task. In one update, I've come to a situation when Yarn refused to install what I asked in the &lt;code&gt;package.json&lt;/code&gt; until I deleted &lt;code&gt;yarn.lock&lt;/code&gt; and started over. Not the most pleasant task to work on but so is reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Is it possible to make a full-stack game using only the web development tools of the JavaScript world? Yes, definitely! Does it worth it? It depends. If you have zero knowledge in web development and game development, go with traditional tools like Unity.&lt;/p&gt;

&lt;p&gt;If you get some web development background, you can succeed with familiar tools. Here's a quick summary of my way:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Am I happy&lt;/th&gt;
&lt;th&gt;Alternatives to consider&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scene Tree&lt;/td&gt;
&lt;td&gt;HTML/SVG/React&lt;/td&gt;
&lt;td&gt;Happy&lt;/td&gt;
&lt;td&gt;OpenGL, Pixi, Three.js&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GUI&lt;/td&gt;
&lt;td&gt;React Native&lt;/td&gt;
&lt;td&gt;Frustrated&lt;/td&gt;
&lt;td&gt;Bare HTML5, Flutter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Functional Language&lt;/td&gt;
&lt;td&gt;ReasonML/ReScript&lt;/td&gt;
&lt;td&gt;Suspicious happiness&lt;/td&gt;
&lt;td&gt;TypeScript, PureScript, Dart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;Expo&lt;/td&gt;
&lt;td&gt;Happy if forget about React Native&lt;/td&gt;
&lt;td&gt;Cordova, Dart&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And have I mentioned my game? I welcome you to the &lt;a href="https://futureco.world/" rel="noopener noreferrer"&gt;Future&lt;/a&gt; if you have a spare hour to kill 😇 I have literally dozens of things to complete yet, but I hope you'll find the game quite playable even in the current state.&lt;/p&gt;

</description>
      <category>functional</category>
      <category>gamedev</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
