<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Demangeon Julien</title>
    <description>The latest articles on Forem by Demangeon Julien (@juliendemangeon).</description>
    <link>https://forem.com/juliendemangeon</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%2F23126%2Ffebc8c23-e61f-438c-81da-df46449acc6b.jpg</url>
      <title>Forem: Demangeon Julien</title>
      <link>https://forem.com/juliendemangeon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/juliendemangeon"/>
    <language>en</language>
    <item>
      <title>Programming A Space Invader In OCaml and OpenGL: Lessons Learned</title>
      <dc:creator>Demangeon Julien</dc:creator>
      <pubDate>Fri, 21 Feb 2020 14:17:43 +0000</pubDate>
      <link>https://forem.com/juliendemangeon/programming-a-space-invader-in-ocaml-and-opengl-lessons-learned-2b0</link>
      <guid>https://forem.com/juliendemangeon/programming-a-space-invader-in-ocaml-and-opengl-lessons-learned-2b0</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: This post was originally posted on &lt;a href="https://marmelab.com/blog/2020/02/21/ocaml-and-opengl-in-practice.html"&gt;marmelab.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;During a &lt;a href="https://marmelab.com/blog/2018/04/09/enjoy-painless-typing-with-reason.html"&gt;previous hackday&lt;/a&gt;, I had the opportunity to try a fairly recent programming language called &lt;a href="https://reasonml.github.io/"&gt;ReasonML&lt;/a&gt;. Amazed by the simplicity and power of ReasonML, I promised myself to get closer to its underlying language to give credit where it is due. Do ReasonML qualities come from &lt;a href="https://caml.inria.fr/pub/docs/manual-ocaml/index.html"&gt;OCaml&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;As an experiment, I took this opportunity to test &lt;strong&gt;OpenGL&lt;/strong&gt; and prove that it is possible to code a humble game in OCaml! Here's what the game looks like at the end, after a few hours of development.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/72ULChMvdvo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The purpose of this article is to determine the magnitude of the differences between ReasonML and OCaml, and to understand &lt;strong&gt;why ReasonML has become so popular&lt;/strong&gt; so quickly, and why OCaml hasn't. The aim is also to determine if it is still useful to use OCaml rather than ReasonML for future projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SntF0AtU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/c43161f8409d18f9fc3f8533cfb79bfe/df77d/reason-and-ocaml.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SntF0AtU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/c43161f8409d18f9fc3f8533cfb79bfe/df77d/reason-and-ocaml.webp" alt="ReasonML vs OCaml"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  OCaml, Powerful But Discreet
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;OCaml&lt;/strong&gt; is the main implementation of &lt;a href="https://en.wikipedia.org/wiki/Caml"&gt;Caml&lt;/a&gt; created in 1996 by a group of researcher from the &lt;a href="https://en.wikipedia.org/wiki/French_Institute_for_Research_in_Computer_Science_and_Automation"&gt;French Institute for Research in Computer Science and Automation (a.k.a. INRIA)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even though it is known for its robustness and its large standard library, its main power lies in its strong &lt;a href="http://www.ffconsultancy.com/ocaml/benefits/type_system.html"&gt;static-typing and type inference&lt;/a&gt; system.&lt;/p&gt;

&lt;p&gt;Although part of the &lt;a href="https://en.wikipedia.org/wiki/ML_(programming_language)"&gt;ML (Meta-Language)&lt;/a&gt; family that is purely &lt;a href="https://en.wikipedia.org/wiki/Functional_programming"&gt;functional-oriented&lt;/a&gt; by nature, OCaml brings many &lt;a href="https://en.wikipedia.org/wiki/Object-oriented_programming"&gt;object-oriented&lt;/a&gt; features that make it special. That's mainly the reason it was named &lt;strong&gt;Objective Caml (aka OCaml)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, it's perfectly possible to work with &lt;a href="https://caml.inria.fr/pub/docs/manual-ocaml/objectexamples.html"&gt;Classes, Objects&lt;/a&gt;, &lt;a href="https://caml.inria.fr/pub/docs/manual-ocaml/objectexamples.html#sec30"&gt;Constructors (named "Initializers")&lt;/a&gt;, &lt;a href="https://caml.inria.fr/pub/docs/manual-ocaml/objectexamples.html#sec34"&gt;Inheritance&lt;/a&gt; and so on.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenGL, The Swiss Army Knife of Rendering
&lt;/h2&gt;

&lt;p&gt;OpenGL (for &lt;strong&gt;Open Graphics Library&lt;/strong&gt;) is a cross-platform and cross-language API that allows to render 2D and 3D vector graphics. It takes care of handling interactions between the source code and the system GPU to benefit from hardware rendering capabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CkzVZ6Ix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/e7c80556d18e5fedfe5ecd60ae1dfefa/df77d/opengl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CkzVZ6Ix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/e7c80556d18e5fedfe5ecd60ae1dfefa/df77d/opengl.webp" alt="OpenGL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OpenGL was developed in 1992 by an old and famous commercial company called &lt;a href="https://en.wikipedia.org/wiki/Silicon_Graphics"&gt;Silicon Graphics&lt;/a&gt;. Since 2006, the project has been managed under a BSD like license by a non-profit consortium called the &lt;a href="https://en.wikipedia.org/wiki/Khronos_Group"&gt;Khronos Group&lt;/a&gt;. This consortium is also responsible of the &lt;a href="https://en.wikipedia.org/wiki/WebGL"&gt;WebGL&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Vulkan_(API)"&gt;Vulkan&lt;/a&gt; standards that are very popular today.&lt;/p&gt;

&lt;p&gt;Vulkan is usually refered to as the &lt;em&gt;OpenGL next&lt;/em&gt; API for graphics rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Case: A Space Invader in OCaml
&lt;/h2&gt;

&lt;p&gt;In this part, I'll give you the most objective feedback about my development experience using OCaml and OpenGL on a concrete project: the &lt;a href="https://en.wikipedia.org/wiki/Space_Invaders"&gt;Space Invader&lt;/a&gt; game.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h_yKYBlN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/83b16ea042f6743940724c1dc4f30d86/df77d/invader.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h_yKYBlN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/83b16ea042f6743940724c1dc4f30d86/df77d/invader.webp" alt="Space Invader"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, I'll explain the intellectual journey that led me to design the project foundation. Then, I'll describe the different stages of project building.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Does it Work? What Do We Need?
&lt;/h3&gt;

&lt;p&gt;As for most programming languages, we need to setup a &lt;em&gt;compiler&lt;/em&gt; which is capable of transforming our OCaml source code to a suite of machine instructions.&lt;/p&gt;

&lt;p&gt;According to the official documentation, the OCaml core distribution provides two compilers, &lt;code&gt;ocamlc&lt;/code&gt; and &lt;code&gt;ocamlopt&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;ocamlc&lt;/code&gt; is the base standard bytecode compiler for OCaml. It produces bytecode files (usualy &lt;code&gt;*.cmi&lt;/code&gt; for interfaces and &lt;code&gt;*.cmo&lt;/code&gt; files for implementations) that can be run using &lt;code&gt;ocamlrun&lt;/code&gt;, the OCaml bytecode runner.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;ocamlopt&lt;/code&gt; is the native code compiler for OCaml. As for &lt;code&gt;ocamlc&lt;/code&gt;, it can take &lt;code&gt;*.ml&lt;/code&gt; (and &lt;code&gt;*.mli&lt;/code&gt;) files as argument and generates an executable (targeting specific architectures according to the provided parameters).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, I do not pretend to give you here the &lt;a href="https://v1.realworldocaml.org/v1/en/html/the-compiler-backend-byte-code-and-native-code.html"&gt;full functionalities&lt;/a&gt; of these tools, which are in fact much more complicated to understand.&lt;/p&gt;

&lt;p&gt;I can already imagine your faces after reading these few lines... but don't go away, I assure you that the rest will be much more exciting!&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;In practice, built-in compilers are almost never directly used on real world projects because they require a lot of work to setup and maintain. It is common to use higher level tools that also facilitate the import of dependencies (including external modules). Among these tools, we can mention &lt;a href="https://dune.readthedocs.io/en/stable/index.html"&gt;Dune&lt;/a&gt;, &lt;a href="https://ocaml.org/learn/tutorials/setting_up_with_oasis.html"&gt;Oasis&lt;/a&gt; and &lt;a href="https://ocaml.org/learn/tutorials/ocamlbuild/"&gt;OCamlBuild&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yRLmsov---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/b3c6fead92e75bb105550b825939352f/df77d/opam.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yRLmsov---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/b3c6fead92e75bb105550b825939352f/df77d/opam.webp" alt="OPAM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my case, I choose a more undisclosed tool (&lt;a href="https://github.com/ocaml-obuild/obuild"&gt;obuild&lt;/a&gt;) because of its simplicity and its brief documentation. So, the first step is to install the &lt;a href="https://opam.ocaml.org/"&gt;OCaml Package Manager (aka opam)&lt;/a&gt; in order to install the &lt;code&gt;obuild&lt;/code&gt; builder.&lt;/p&gt;

&lt;p&gt;As for every new projet, my approach consists in setting up the whole tech stack in &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; so as to avoid overloading my workstation, and to allow other people to participate easily. Therefore, I started looking for a Docker Image that includes &lt;code&gt;opam&lt;/code&gt; on &lt;a href="https://hub.docker.com/"&gt;docker-hub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanksfully, the &lt;a href="https://hub.docker.com/r/ocaml/opam2"&gt;ocaml/opam2&lt;/a&gt; docker image exists, here is my &lt;code&gt;Dockerfile&lt;/code&gt; configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ocaml/opam2:debian-10-ocaml-4.08&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; /app
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; . /app/&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update

&lt;span class="k"&gt;RUN &lt;/span&gt;opam &lt;span class="nb"&gt;install &lt;/span&gt;obuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since I need to work with OpenGL to draw the game, and I won't develop an OpenGL library from scratch, I'll install &lt;a href="http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/lablgl.html"&gt;lablgl&lt;/a&gt; at the same time by adding this line at the end of the &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;opam depext lablgl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;lablgl&lt;/code&gt; is one of the most advanced OpenGL interfaces for OCaml. Despite its lack of documentation, it remains the most talked about library after several minutes spent on search engines...&lt;/p&gt;

&lt;p&gt;Lablgl is based on &lt;a href="https://www.opengl.org/resources/libraries/glut/"&gt;Glut (The OpenGL Utility Toolkit)&lt;/a&gt;. Glut takes care of all the system specific mechanisms to &lt;strong&gt;create windows&lt;/strong&gt;, &lt;strong&gt;initializing OpenGL&lt;/strong&gt; and &lt;strong&gt;capture input events&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now I have all the ingredients, I need to build the application. I create my entry point file in &lt;code&gt;src/main.ml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── Dockerfile
├── ocaml-invader.obuild
└── src
    └── main.ml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I create the obuild config file &lt;code&gt;ocaml-invader.obuild&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ocaml-invader&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.1&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Simple OCaml Invader Game&lt;/span&gt;
&lt;span class="na"&gt;licence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MIT&lt;/span&gt;
&lt;span class="na"&gt;authors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Julien Demangeon &amp;lt;julien@marmelab.com&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;obuild-ver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;homepage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://github.com/marmelab/ocaml-invader&lt;/span&gt;

&lt;span class="s"&gt;executable ocaml-invader&lt;/span&gt;
    &lt;span class="s"&gt;main-is&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main.ml&lt;/span&gt;
    &lt;span class="s"&gt;src-dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src&lt;/span&gt;
    &lt;span class="s"&gt;buildDepends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lablgl, lablgl.glut&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a &lt;code&gt;Makefile&lt;/code&gt; to facilitate development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;BIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; docker run &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;${PWD}&lt;/span&gt;&lt;span class="s2"&gt;:/app"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    ocamlinvader

&lt;span class="nl"&gt;install&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Install dependencies&lt;/span&gt;
    docker build &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ocamlinvader .

&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Build project&lt;/span&gt;
    &lt;span class="nv"&gt;$(BIN)&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"obuild configure &amp;amp;&amp;amp; obuild build"&lt;/span&gt;

&lt;span class="nl"&gt;clean&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Clean project&lt;/span&gt;
    &lt;span class="nv"&gt;$(BIN)&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"obuild clean"&lt;/span&gt;

&lt;span class="nl"&gt;start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Start project&lt;/span&gt;
    &lt;span class="nv"&gt;$(MAKE)&lt;/span&gt; build
    ./ocaml-invader
    &lt;span class="nv"&gt;$(MAKE)&lt;/span&gt; clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, everything is set, I can now start developing the game!&lt;/p&gt;

&lt;h3&gt;
  
  
  Game Architecture
&lt;/h3&gt;

&lt;p&gt;As with most video games, the whole system is based on a &lt;strong&gt;game state&lt;/strong&gt;, some &lt;strong&gt;state mutations&lt;/strong&gt; (through &lt;strong&gt;system inputs&lt;/strong&gt;), and a &lt;strong&gt;rendering engine / loop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PjAmC9GV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/6c8a4ee61598cfda819321406aec0ff6/df77d/game-architecture.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PjAmC9GV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/6c8a4ee61598cfda819321406aec0ff6/df77d/game-architecture.webp" alt="Game Archicture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, I won't have to manage all these components by myself. Indeed, &lt;code&gt;labgl&lt;/code&gt; (through its &lt;code&gt;Glut&lt;/code&gt; module) offers most of these features out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The windowing system through &lt;code&gt;Glut.createWindow&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  The rendering loop through &lt;code&gt;Glut.mainLoop&lt;/code&gt;, &lt;code&gt;Glut.displayFunc&lt;/code&gt; and &lt;code&gt;Glut.idleFunc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Input management through &lt;code&gt;Glut.keyboardFunc&lt;/code&gt; and &lt;code&gt;Glut.specialFunc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  The timers / tickers through &lt;code&gt;Glut.timerFunc&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, I only have to care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The rendering of the game in OpenGL (through the &lt;code&gt;Glmat&lt;/code&gt; and &lt;code&gt;Gldraw&lt;/code&gt; modules)&lt;/li&gt;
&lt;li&gt;  Changing the game state from the input actions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Main Program
&lt;/h3&gt;

&lt;p&gt;Now that the basis of the architecture is established, let's get down to business by expanding the main function in &lt;code&gt;main.ml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="c"&gt;(* main.ml *)&lt;/span&gt;

&lt;span class="c"&gt;(* Declare rendering function, buffering mode, and create window *)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;initDisplay&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;h&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;=&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initDisplayMode&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;double_buffer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initWindowSize&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createWindow&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idleFunc&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;cb&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="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;postRedisplay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;(* Initialize OpenGL rendering options *)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;initView&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;viewport&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;GlMat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="nt"&gt;`projection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;GlMat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_identity&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;GluMat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ortho2d&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;float_of_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;float_of_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nn"&gt;GlMat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="nt"&gt;`modelview&lt;/span&gt;

&lt;span class="c"&gt;(* Create some tickers that send actions to the Game Controller *)&lt;/span&gt;
&lt;span class="c"&gt;(* The GameController uses these actions to mutate the game state each N ms *)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;initTickers&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timerFunc&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invaderTicker&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timerFunc&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bulletTicker&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timerFunc&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collisionCheckTicker&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="c"&gt;(* Map keyboard inputs to game actions *)&lt;/span&gt;
&lt;span class="c"&gt;(* The GameController uses these actions to mutate the game state *)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;initInputs&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keyboardFunc&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gameController&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="n"&gt;specialKeyToAction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;specialFunc&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gameController&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="n"&gt;commonKeyToAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;(* Initialize each part of the game engine *)&lt;/span&gt;
&lt;span class="c"&gt;(* Then, it returns a callable mainLoop *)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;initEngine&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;initDisplay&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;h&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;:&lt;/span&gt; &lt;span class="s2"&gt;"OCaml Invader"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;initView&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;initTickers&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;initInputs&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;displayFunc&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mainLoop&lt;/span&gt;

&lt;span class="c"&gt;(* This is the first function executed by OCaml *)&lt;/span&gt;
&lt;span class="c"&gt;(* We init the game object reference and pass it to the engine *)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;ignore&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt; &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="nn"&gt;Sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&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;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initEngine&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Zoom In The Game Controller
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mutations on the game state are managed by the game controller&lt;/strong&gt;. The game controller is a simple function that associates an action (with pattern matching on it) to a mutation on the game state (the whole game being declared mutable).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="c"&gt;(* game.ml *)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Left&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Right&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Move&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Shoot&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;AdvanceInvaders&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;InvaderShoot&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;AdvanceBullets&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;CheckCollisions&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;over&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;lifes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;invaders&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Invader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invader&lt;/span&gt; &lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;invadersDirection&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;spaceship&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Spaceship&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spaceship&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;bullets&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Bullet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bullet&lt;/span&gt; &lt;span class="kt"&gt;list&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;controller&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;direction&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;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Left&lt;/span&gt; &lt;span class="o"&gt;-&amp;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="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Right&lt;/span&gt; &lt;span class="o"&gt;-&amp;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="k"&gt;in&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;coord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spaceship&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spaceship&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="n"&gt;coord&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;440&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt;
        &lt;span class="n"&gt;game&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Shoot&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;(* ... mutate game ... *)&lt;/span&gt;
        &lt;span class="n"&gt;game&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;InvaderShoot&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;(* ... mutate game ... *)&lt;/span&gt;
        &lt;span class="n"&gt;game&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;CheckCollisions&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;(* ... mutate game ... *)&lt;/span&gt;
        &lt;span class="n"&gt;game&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;AdvanceInvaders&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;(* ... mutate game ... *)&lt;/span&gt;
        &lt;span class="n"&gt;game&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;AdvanceBullets&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;(* ... mutate game ... *)&lt;/span&gt;
        &lt;span class="n"&gt;game&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="n"&gt;game&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The link between the game controller and actions (tickers and keyboard inputs) is declared in the &lt;code&gt;gameController&lt;/code&gt; function of the &lt;code&gt;Main&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="c"&gt;(* main.ml *)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;gameController&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="n"&gt;keyToAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyToAction&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;with&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;action&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;game&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nn"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="n"&gt;action&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="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rendering Logic
&lt;/h3&gt;

&lt;p&gt;The entire rendering logic for the game is located in the &lt;code&gt;Game&lt;/code&gt; module of the &lt;code&gt;game.ml&lt;/code&gt; file. This logic is composed of a switch between two screens, a game screen, and an end screen depending on whether the game is finished or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="c"&gt;(* game.ml *)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;renderHome&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;GlClear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;`color&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;endText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sprintf&lt;/span&gt; &lt;span class="s2"&gt;"YOU WIN"&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="nn"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sprintf&lt;/span&gt; &lt;span class="s2"&gt;"GAME OVER"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="nn"&gt;Utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawString&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BITMAP_TIMES_ROMAN_24&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="mi"&gt;290&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;endText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swapBuffers&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;(* Each module (Score, Life, Invader, Bullet, ...) has its own render *)&lt;/span&gt;
&lt;span class="c"&gt;(* So we clear buffer, draw the game and swap buffers to render it to the screen *)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;renderGame&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;GlClear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;`color&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nn"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;Life&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lifes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;Invader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invaders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;Bullet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bullets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;Spaceship&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spaceship&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;Glut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swapBuffers&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;over&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;renderGame&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;renderHome&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each component of the game (Invader, Spaceship, ...) has its own module and its own &lt;code&gt;render&lt;/code&gt; method, which makes it possible to separate the responsibilities in the code. For example, here are some parts of the &lt;code&gt;Invader&lt;/code&gt; rendering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="c"&gt;(* invader.ml *)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;race&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Octopus&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;ShapeShifting&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Crab&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;invader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;race&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;race&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;renderOctopus&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begins&lt;/span&gt; &lt;span class="nt"&gt;`quads&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertex2&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ends&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;renderCrab&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;0&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="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begins&lt;/span&gt; &lt;span class="nt"&gt;`quads&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertex2&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ends&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;renderShapeShifting&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begins&lt;/span&gt; &lt;span class="nt"&gt;`quads&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertex2&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ends&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;invader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;GlMat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_identity&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;GlMat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;translate3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;invader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;invader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;race&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Octopus&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;renderOctopus&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;ShapeShifting&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;renderShapeShifting&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Crab&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;renderCrab&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  OpenGL In Practice
&lt;/h3&gt;

&lt;p&gt;To summarize quickly, &lt;strong&gt;OpenGL is a large state machine&lt;/strong&gt; on which it is possible to send instructions. Once all rendering instructions have been sent to it, it is possible to trigger the on-screen display using Buffer flush.&lt;/p&gt;

&lt;p&gt;For each rendering, it may be necessary to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Modify state variables (anti-aliasing enabled, ...)&lt;/li&gt;
&lt;li&gt;  Define the textures (aka &lt;code&gt;Materials&lt;/code&gt;) to be used for the display&lt;/li&gt;
&lt;li&gt;  Send geometrical instructions (aka &lt;code&gt;Vertex&lt;/code&gt;) to the Buffer&lt;/li&gt;
&lt;li&gt;  Trigger the Buffer flush&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the example above, for each invader I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Reset the rendering matrix state with &lt;code&gt;GlMat.load_identity()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Place cursor at the invader position with &lt;code&gt;GlMat.translate3(inv.x, inv.y, 0.0);&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Define a color to be used with &lt;code&gt;GlDraw.color&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Declare that I'll draw a quadrilateral with &lt;code&gt;GlDraw.begins `quads&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Send 4 vertices with &lt;code&gt;GlDraw.vertex2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Close the Invader figure (a square in my case) with &lt;code&gt;GlDraw.ends&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the case of the invaders, I used simple squares for lack of time. But I know that &lt;strong&gt;it is possible to make much more complex shapes&lt;/strong&gt;, as in the Spaceship below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;spaceship&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;float&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;renderAt&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;GlMat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_identity&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;GlMat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;translate3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;51&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="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begins&lt;/span&gt; &lt;span class="nt"&gt;`quads&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertex2&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nn"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertex2&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nn"&gt;GlDraw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ends&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;spaceship&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;renderAt&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;spaceship&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;spaceship&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;p&gt;As a result, the game is &lt;strong&gt;very fast&lt;/strong&gt;, &lt;strong&gt;no lag&lt;/strong&gt; and the &lt;strong&gt;compilation time is almost instantaneous&lt;/strong&gt;, what more could you ask for? If you are interested in the code (or want to play), the game is available in open-source on &lt;a href="https://github.com/marmelab/ocaml-invader"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Although confused at first, I am very proud to have achieved this project. This was an opportunity for me to measure the particularities that makes OCaml so intimidating for most developers.&lt;/p&gt;

&lt;p&gt;Indeed, &lt;strong&gt;it is very complicated to install the base stack to develop in OCaml&lt;/strong&gt;. And although some tools exist to make our life easier, they are &lt;strong&gt;poorly documented&lt;/strong&gt;. This lack of documentation also applies to the language itself. The documentation is scattered among many academic and research-oriented sites, making it &lt;strong&gt;very intimidating for a beginner&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Clearly, &lt;strong&gt;it is in OCaml's weaknesses that we find the strength of ReasonML&lt;/strong&gt;. The languages are not so different, but their communities and ways of working are clearly in contrast.&lt;/p&gt;

&lt;p&gt;In my opinion, I would say that &lt;strong&gt;OCaml suffers from its original academic use&lt;/strong&gt;, and that it deserves a little more love from mainstream developers. &lt;strong&gt;It is incredibly fast to compile and run&lt;/strong&gt;, and it competes well with popular languages.&lt;/p&gt;

&lt;p&gt;To conclude, &lt;strong&gt;I would still advise to prefer ReasonML over OCaml&lt;/strong&gt; (as its community keeps growing). This way, you will adopt a functional way of coding that can be used in other derived languages such as &lt;a href="https://en.wikipedia.org/wiki/F_Sharp_(programming_language)"&gt;F#&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Scala_(programming_language)"&gt;Scala&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ocaml</category>
      <category>reason</category>
      <category>opengl</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build Your Own Design System With StencilJS</title>
      <dc:creator>Demangeon Julien</dc:creator>
      <pubDate>Fri, 06 Dec 2019 13:39:20 +0000</pubDate>
      <link>https://forem.com/juliendemangeon/build-your-own-design-system-with-stenciljs-1jfg</link>
      <guid>https://forem.com/juliendemangeon/build-your-own-design-system-with-stenciljs-1jfg</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: This post was originally posted on &lt;a href="https://marmelab.com/blog/2019/12/06/build-your-own-design-system-with-stenciljs.html"&gt;marmelab.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this post, we will define &lt;strong&gt;what StencilJS&lt;/strong&gt; is and &lt;strong&gt;how we can use it&lt;/strong&gt; to build a Design System. As a pre-requisite, you should know that &lt;a href="https://stenciljs.com/"&gt;StencilJS&lt;/a&gt; is not a framework. &lt;strong&gt;It's a compiler that produces reusable Web Components&lt;/strong&gt; that can be embedded anywhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Design System?
&lt;/h2&gt;

&lt;p&gt;Many publishers have a &lt;strong&gt;graphic charter&lt;/strong&gt; defining a set of rules about their visual identity.&lt;/p&gt;

&lt;p&gt;Given the technological developments in our societies, &lt;strong&gt;these rules increasingly and largely concern digital media&lt;/strong&gt;, particularly the web.&lt;/p&gt;

&lt;p&gt;In the last few years, a consensus has emerged in the world of web development. Indeed, &lt;strong&gt;most javascript frameworks are largely based on components&lt;/strong&gt;. Components offer many advantages such as logic reusability, centralized style and easy testing. Their use provides a rich and uniform browsing experience far away from the early 21th century.&lt;/p&gt;

&lt;p&gt;As a result, a new trend has emerged, merging the principles of graphical charter and standalone UI components: that's the &lt;strong&gt;Design System&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4xVncqSF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/78bb146d4c30e8b4c6ce3be5025fff34/e0b4a/designsystem.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4xVncqSF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/78bb146d4c30e8b4c6ce3be5025fff34/e0b4a/designsystem.jpg" alt="Design System"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is StencilJS?
&lt;/h2&gt;

&lt;p&gt;As previously said, &lt;strong&gt;StencilJS is not another web framework such as ReactJS or VueJS&lt;/strong&gt;. &lt;strong&gt;StencilJS is a toolchain&lt;/strong&gt; that facilitates the building of reusable and scalable Design Systems based on the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components"&gt;Web Component&lt;/a&gt; standard. It was created by the &lt;a href="https://ionicframework.com/"&gt;Ionic Framework&lt;/a&gt; team especially for this purpose.&lt;/p&gt;

&lt;p&gt;Although totally different from a frontend framework, StencilJS uses many well-known concepts and technologies from frontend development - and that's often confusing for a developer. So, StencilJS provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A virtual DOM&lt;/li&gt;
&lt;li&gt;JSX (like in ReactJS)&lt;/li&gt;
&lt;li&gt;Reactive Data (like AngularJS $watch)&lt;/li&gt;
&lt;li&gt;Async rendering (inspired by React Fiber)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt; support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By combining all these features, StencilJS is able to generate &lt;strong&gt;standard-compliant&lt;/strong&gt; components. Moreover, StencilJS automatically adds the polyfill required to &lt;strong&gt;support older browsers&lt;/strong&gt;. Here is the browser support grid provided by the StencilJS website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jIGrd2yL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/a86f73bc6b71b6bac88d0b104d5e2dd7/624ba/browser_support.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jIGrd2yL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/a86f73bc6b71b6bac88d0b104d5e2dd7/624ba/browser_support.png" alt="Browser Support"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, to sum up, using StencilJS allows you to &lt;strong&gt;build a Design System that is ready for the future&lt;/strong&gt; thanks to its compliance with upcoming standards, its automatic polyfill and its advanced API.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple Case Study
&lt;/h2&gt;

&lt;p&gt;In this section, I will detail the creation of a Design System from scratch using StencilJS. For the example, I will create a design system for Marmelab called &lt;code&gt;mml&lt;/code&gt;. Here is the initialisation process below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2NCxDa6I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://marmelab.com/4de6bb6a70aeeb00bf9f35909c5d1211/mml.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2NCxDa6I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://marmelab.com/4de6bb6a70aeeb00bf9f35909c5d1211/mml.gif" alt="Marmelab Design System"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a component
&lt;/h3&gt;

&lt;p&gt;Once our project is set up, we can create our first component, in our case a "Github Card". StencilJS provides a special npm script command for that purpose, &lt;code&gt;generate&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;julien@julien-P553UA:~/Projets/marmelab/mml&lt;span class="nv"&gt;$ &lt;/span&gt;npm run generate
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mml@0.0.1 generate /home/julien/Projets/marmelab/mml
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; stencil generate

✔ Component tag name &lt;span class="o"&gt;(&lt;/span&gt;dash-case&lt;span class="o"&gt;)&lt;/span&gt;: … github-card
✔ Which additional files &lt;span class="k"&gt;do &lt;/span&gt;you want to generate? › Stylesheet, Spec Test, E2E Test

&lt;span class="nv"&gt;$ &lt;/span&gt;stencil generate github-card

The following files have been generated:
 - src/components/github-card/github-card.tsx
 - src/components/github-card/github-card.css
 - src/components/github-card/github-card.spec.ts
 - src/components/github-card/github-card.e2e.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;StencilJS has generated all the required files&lt;/strong&gt; to create our component, even the test files! Here are the generated files from that command (excluding tests).&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="c1"&gt;// ./src/components/github-card/github-card.css&lt;/span&gt;

&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ./src/components/github-card/github-card.tsx&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stencil/core&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;github-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;github-card.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;GithubCard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;render&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Host&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/slot&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Host&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you might think: We're supposed to use StencilJS, how come this command has generated Angular code? Well, although it looks like Angular code, it's actually StencilJS. And I agree, the annotations at the beginning of the module can be confusing. But don't worry, you're on the right track ;)&lt;/p&gt;

&lt;p&gt;So, the &lt;code&gt;@Component&lt;/code&gt; annotation allows us to declare a StencilJS component, which can be configured using several options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tag&lt;/code&gt;: name of the tag on which our component will be registered.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;styleUrl&lt;/code&gt;: relative url to the corresponding style file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shadow&lt;/code&gt;: enable the browser &lt;a href="https://developer.mozilla.org/fr/docs/Web/Web_Components/Using_shadow_DOM"&gt;Shadow DOM&lt;/a&gt; encapsulation&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stenciljs.com/docs/component#component-options"&gt;other options...&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;render&lt;/code&gt; method, the &lt;code&gt;Host&lt;/code&gt; component represents the root of the component, the tag itself. Within it, the &lt;code&gt;slot&lt;/code&gt; allows to inject children in our custom element as described below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;github-card&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;I'm a children, and i'll replace the &lt;span class="c"&gt;&amp;lt;!-- &amp;lt;slot&amp;gt;--&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/github-card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we use Shadow DOM, only the styles inside our &lt;code&gt;github-card.css&lt;/code&gt; tag will have an impact on the display of our &lt;code&gt;github-card&lt;/code&gt;. The special &lt;code&gt;:host&lt;/code&gt; selector refers to the tag itself (aka &lt;code&gt;Host&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Then, our component exists and we're able to see it (not much at the moment) in the browser using &lt;code&gt;yarn start&lt;/code&gt; (aka &lt;code&gt;stencil build --dev --watch --serve&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If we inspects the DOM using chrome &lt;code&gt;devtools&lt;/code&gt;, this is what we'll see.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SCnYfXlj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/3b306b1d4880b454db19232614772e2c/c3508/dom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SCnYfXlj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/3b306b1d4880b454db19232614772e2c/c3508/dom.png" alt="StencilJS DOM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a few minutes in the shoes of an integrator, &lt;strong&gt;here is what I get from some html and css&lt;/strong&gt;. Sadly, everything is static for the moment, and I have much less than 42 followers in real-life ^^.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I4Ne7bw4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/947737eab8eb32e4869c011bbca7d083/3d9f8/basecard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I4Ne7bw4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/947737eab8eb32e4869c011bbca7d083/3d9f8/basecard.png" alt="HTML Github Card"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next chapter, I'll explain how to &lt;strong&gt;configure which user is displayed&lt;/strong&gt; using a special &lt;code&gt;login&lt;/code&gt; attribute on our custom element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;github-card&lt;/span&gt; &lt;span class="na"&gt;login=&lt;/span&gt;&lt;span class="s"&gt;"jdemangeon"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/github-card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Passing Props To A Component
&lt;/h3&gt;

&lt;p&gt;Like &lt;a href="https://reactjs.org/"&gt;ReactJS&lt;/a&gt;, StencilJS provides &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;props&lt;/code&gt; and &lt;code&gt;lifecycle hooks&lt;/code&gt;. So, the first step is to declare a &lt;code&gt;login&lt;/code&gt; prop and an &lt;code&gt;user&lt;/code&gt; state in our component. Whereas &lt;code&gt;login&lt;/code&gt; will receive the name of the GitHub user, &lt;code&gt;user&lt;/code&gt; will receive the user object coming from the GitHub API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- import { Component, Host, h } from "@stencil/core";
&lt;/span&gt;&lt;span class="gi"&gt;+ import { Component, Host, h, Prop, State } from "@stencil/core";
&lt;/span&gt;

&lt;span class="err"&gt;@Component({&lt;/span&gt;
  tag: "github-card",
  styleUrl: "github-card.css",
  shadow: true
&lt;span class="err"&gt;})&lt;/span&gt;
export class GithubCard {
&lt;span class="gi"&gt;+  @Prop() login: string;
+  @State() user: any;
&lt;/span&gt;
  render() {
    ...
&lt;span class="gd"&gt;-     &amp;lt;a class="avatar" href={`https://github.com/jdemangeon`}&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+     &amp;lt;a class="avatar" href={`https://github.com/${this.login}`}&amp;gt;
&lt;/span&gt;    ...
  }
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contrary to React, there's no &lt;code&gt;this.props&lt;/code&gt; object to access props with StencilJS. Prop values are directly attached to the &lt;code&gt;this&lt;/code&gt; instance. So we can access &lt;code&gt;login&lt;/code&gt; using &lt;code&gt;this.login&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, our links are up to date, and point to the right profile according to the &lt;code&gt;login&lt;/code&gt; prop. Other data such as the number of followers, repositories, etc... are not dynamic and require a call to the Github API.&lt;/p&gt;

&lt;h3&gt;
  
  
  External And Internal APIs
&lt;/h3&gt;

&lt;p&gt;I don't really want to expose my GitHub popularity in the spotlight... But it's the lottery, honey! So, in this section we'll explore how to call the GitHub API from the component, and display real values based on the response.&lt;/p&gt;

&lt;p&gt;First, &lt;strong&gt;we will declare a function that calls Github&lt;/strong&gt; and assigns values to our user. And in a second step, we will &lt;strong&gt;call this function when mounting the component&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;
export class GithubCard {
  @Prop() login: string;
  @State() user: any;

+ async componentWillLoad() {
&lt;span class="gi"&gt;+   return this.fetchUser(this.login);
+ }
&lt;/span&gt;
+ async fetchUser(login: string) {
&lt;span class="gi"&gt;+   const response = await fetch(`https://api.github.com/users/${login}`);
+
+   if (response.status === 200) {
+     this.user = await response.json();
+   } else {
+     this.user = null;
+   }
+ }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we are able to use the user information inside the &lt;code&gt;render()&lt;/code&gt; method. If the user doesn't exist or is not retrieved yet, we'll return &lt;code&gt;null&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  render() {
&lt;span class="gi"&gt;+   if (!this.user) {
+     return null;
+   }
&lt;/span&gt;
    return (
      &amp;lt;Host&amp;gt;
        &amp;lt;div class="card"&amp;gt;
          &amp;lt;div class="header" /&amp;gt;
          &amp;lt;a class="avatar" href={`https://github.com/${this.login}`}&amp;gt;
&lt;span class="gd"&gt;-           &amp;lt;img src="https://avatars0.githubusercontent.com/u/1064780" alt={this.login} /&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+           &amp;lt;img src={this.user.avatar_url} alt={this.login} /&amp;gt;
&lt;/span&gt;          &amp;lt;/a&amp;gt;
          &amp;lt;div&amp;gt;
&lt;span class="gd"&gt;-           &amp;lt;h1&amp;gt;Julien Demangeon&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+           &amp;lt;h1&amp;gt;{this.user.name}&amp;lt;/h1&amp;gt;
&lt;/span&gt;            &amp;lt;ul&amp;gt;
              &amp;lt;li&amp;gt;
                &amp;lt;a
                  target="_blank"
                  href={`https://github.com/${this.login}?tab=repositories`}
                &amp;gt;
&lt;span class="gd"&gt;-                 &amp;lt;strong&amp;gt;42&amp;lt;/strong&amp;gt;Repos
&lt;/span&gt;&lt;span class="gi"&gt;+                 &amp;lt;strong&amp;gt;{this.user.public_repos}&amp;lt;/strong&amp;gt;Repos
&lt;/span&gt;                &amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
              ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like props, state attributes are directly attached to the instance through &lt;code&gt;this&lt;/code&gt;. So you have to be very careful with naming to avoid conflicts between state and props.&lt;/p&gt;

&lt;p&gt;So yeah, it works. But what happens if I update the &lt;code&gt;login&lt;/code&gt; attribute?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- &amp;lt;github-card login="jdemangeon"&amp;gt;&amp;lt;/github-card&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ &amp;lt;github-card login="marmelab"&amp;gt;&amp;lt;/github-card&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, my component doesn't change... but why? Because the &lt;code&gt;componentWillLoad&lt;/code&gt; lifecycle method which is used is called only once, just before the component mounts to the DOM. To reflect prop (and state) changes, we must implement &lt;code&gt;componentWillUpdate&lt;/code&gt;, too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;export class GithubCard {
&lt;/span&gt;  @Prop() login: string;
  @State() user: any;

  async componentWillLoad() {
    return this.fetchUser(this.login);
  }

+ async componentWillUpdate() {
&lt;span class="gi"&gt;+   return this.fetchUser(this.login);
+ }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;componentWillLoad&lt;/code&gt;, &lt;code&gt;componentWillUpdate&lt;/code&gt; and &lt;code&gt;componentWillRender&lt;/code&gt; lifecycle methods are special. They can return a &lt;a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Promise"&gt;Promise&lt;/a&gt; that can be used to wait for the next render.&lt;/p&gt;

&lt;p&gt;YES! Our component no shows user information, and changes when the &lt;code&gt;login&lt;/code&gt; prop changes. What if we want to allow developers  to display other information? To achieve this goal, we'll use a &lt;code&gt;slot&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;   return (
      &amp;lt;Host&amp;gt;
        &amp;lt;div class="card"&amp;gt;
          &amp;lt;div class="header" /&amp;gt;
          &amp;lt;a class="avatar" href={`https://github.com/${this.login}`}&amp;gt;
            &amp;lt;img src={this.user.avatar_url} alt={this.login} /&amp;gt;
          &amp;lt;/a&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;{this.user.name}&amp;lt;/h1&amp;gt;
&lt;span class="gi"&gt;+           &amp;lt;slot /&amp;gt;
&lt;/span&gt;            &amp;lt;ul&amp;gt;
              &amp;lt;li&amp;gt;
              ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A little change in the html...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- &amp;lt;github-card login="jdemangeon"&amp;gt;&amp;lt;/github-card&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ &amp;lt;github-card login="jdemangeon"&amp;gt;
+   &amp;lt;span&amp;gt;I like Pastis!&amp;lt;/span&amp;gt;
+ &amp;lt;/github-card&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And tada! Isn't life beautiful? In this case there's only one &lt;code&gt;slot&lt;/code&gt;, but you need to be aware that multiple &lt;code&gt;slots&lt;/code&gt; can be used thanks to &lt;a href="https://stenciljs.com/docs/templating-jsx#slots"&gt;named slots&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7zKP1vTC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/d83f40b3a9d4ae86a0bdb4da8cf80a38/c39d3/ilikepastis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7zKP1vTC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/d83f40b3a9d4ae86a0bdb4da8cf80a38/c39d3/ilikepastis.png" alt="I like Paris"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In reality, if you apply the example as it is, you will see the text "I like pastis" blinking before the rest of the component. This is quite normal, since we use "normal" html tags and because the browser will show the text before javascript execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fe0u_-vy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://marmelab.com/5b661110fad1a04d3fcee8786f97a8bc/cloak.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fe0u_-vy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://marmelab.com/5b661110fad1a04d3fcee8786f97a8bc/cloak.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To avoid this problem, StencilJS will apply an &lt;code&gt;hydrated&lt;/code&gt; class on the components once they are mounted. So it's necessary to declare the style below to avoid the problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;github-card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nt"&gt;github-card&lt;/span&gt;&lt;span class="nc"&gt;.hydrated&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've already used &lt;a href="https://vuejs.org/"&gt;VueJS&lt;/a&gt;, you probably already known the &lt;a href="https://medium.com/vuejs-tips/v-cloak-45a05da28dc4"&gt;v-cloak&lt;/a&gt; attribute, which is based on the same principle. The same applies to AngularJS with &lt;code&gt;ng-cloak&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The StencilJS API provides a &lt;a href="https://stenciljs.com/docs/decorators"&gt;lot of features&lt;/a&gt; that would be difficult to cover completely here. I can't recommend enough that you take a look at the official documentation, which is very extensive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Composing Components
&lt;/h3&gt;

&lt;p&gt;We have built a standalone component. &lt;strong&gt;How can we interact with it from other components?&lt;/strong&gt; We're going to create a user selector, which allows us to change the user in the card.&lt;/p&gt;

&lt;p&gt;So, we use the same &lt;code&gt;generate&lt;/code&gt; command with a &lt;code&gt;github-card-selector&lt;/code&gt; this time. And here is the finalized component below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/components/github-card-selector/github-card-selector.tsx&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@stencil/core&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-card-selector&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-card-selector.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;GithubSelector&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;handleLoginChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UIEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&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;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Host&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
          &lt;span class="nx"&gt;onChange&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;handleLoginChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&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;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Github username&lt;/span&gt;&lt;span class="dl"&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;github&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="nx"&gt;login&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;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Host&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, the code is simple enough to be readable. However, it presupposes that the &lt;code&gt;github-card&lt;/code&gt; html tag is already registered on the browser (thankfully, StencilJS takes care of that when the mml library is loaded). &lt;strong&gt;There is no explicit import.&lt;/strong&gt; Of course, since we use &lt;code&gt;TypeScript&lt;/code&gt;, everything is typed, even &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/UIEvent"&gt;UIEvent&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement"&gt;HTMLInputElement&lt;/a&gt; browser events.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zl05E7MT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://marmelab.com/0de8a57dd9da48e9a92a0e9a4bf430db/githubselector.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zl05E7MT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://marmelab.com/0de8a57dd9da48e9a92a0e9a4bf430db/githubselector.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the project sources at the following address: &lt;a href="https://github.com/marmelab/mml"&gt;https://github.com/marmelab/mml&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Component Testing
&lt;/h2&gt;

&lt;p&gt;There are 2 different test types in StencilJS: &lt;strong&gt;Unit Tests&lt;/strong&gt; and &lt;strong&gt;End-To-End&lt;/strong&gt; (e2e). StencilJS uses &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; for unit tests and &lt;a href="https://github.com/GoogleChrome/puppeteer"&gt;Puppeteer&lt;/a&gt; for e2e tests. If you already know these two excellent tools, you won't be lost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DeuDn2NW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/a4ddc82556f1da2bfdef127ab01f6324/624ba/jestpuppeteer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DeuDn2NW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/static/a4ddc82556f1da2bfdef127ab01f6324/624ba/jestpuppeteer.png" alt="Jest And Puppeteer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to Puppeteer, it is &lt;strong&gt;possible to fine-tune the configuration of browser tests&lt;/strong&gt;. This includes &lt;code&gt;touch management&lt;/code&gt;, or &lt;code&gt;landscape mode&lt;/code&gt;, up to &lt;code&gt;viewport emulation&lt;/code&gt;. Using unit tests, it is also possible to mock many features such as &lt;code&gt;HTTP Referer&lt;/code&gt;, &lt;code&gt;Cookies&lt;/code&gt;, &lt;code&gt;Url&lt;/code&gt;, and so on.&lt;/p&gt;

&lt;p&gt;In fact, I didn't find any significant difference between these two test modes. One is just slower because it passes through Puppeteer, but does not bring any added value. I think &lt;strong&gt;it's better to focus on e2e tests once the component is integrated into the final application&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For more information on testing with StencilJS, the documentation can be found &lt;a href="https://stenciljs.com/docs/testing-overview"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework interoperability
&lt;/h2&gt;

&lt;p&gt;As already explained, StencilJS is not a framework, it's just a web-components compiler. Although dedicated to this unique task, &lt;strong&gt;StencilJS's underlying objective is to enable end-to-end development of web applications&lt;/strong&gt; based on the new standards.&lt;/p&gt;

&lt;p&gt;It's still difficult to build a complex application entirely with StencilJS. For this reason, &lt;strong&gt;StencilJS provides a set of functions that allow components to be injected directly into existing web applications&lt;/strong&gt;. Here is an example with ReactJS below.&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;applyPolyfills&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defineCustomElements&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;your-design-system-lib&amp;gt;/loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;applyPolyfills&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;defineCustomElements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&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;Not all frameworks allow easy integration of custom elements (web-components). &lt;a href="https://custom-elements-everywhere.com/"&gt;A website&lt;/a&gt; lists the compatibility rate for each of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design System Target
&lt;/h2&gt;

&lt;p&gt;One of the greatest feature of StencilJS is that it can generate various builds at the same time to cover all expected needs and targets.&lt;/p&gt;

&lt;p&gt;So, StencilJS can generate both the &lt;a href="https://en.wikipedia.org/wiki/ECMAScript#5th_Edition"&gt;ES5&lt;/a&gt; and &lt;a href="https://medium.com/passpill-project/files-with-mjs-extension-for-javascript-modules-ced195d7c84a"&gt;ECMAScript Modules (esm)&lt;/a&gt; versions for each component. It can also generate the corresponding documentation in &lt;code&gt;markdown&lt;/code&gt; or &lt;code&gt;json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can configure that targets through the &lt;code&gt;stencil.config.js&lt;/code&gt; 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stencil/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;outputTargets&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;esmLoaderPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../loader&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docs-readme&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;www&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the &lt;code&gt;www&lt;/code&gt; output target folder, we can directly test our component by serving it. You can test it directly in the &lt;a href="https://marmelab.com/blog/2019/12/06/build-your-own-design-system-with-stenciljs.html#design-system-target"&gt;original blog post&lt;/a&gt;. Type your Github username, press Enter, and Voilà!&lt;/p&gt;

&lt;p&gt;Here is the &lt;a href="https://stenciljs.com/docs/output-targets"&gt;output target&lt;/a&gt; documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;StencilJS cannot replace web frameworks&lt;/strong&gt; such as ReactJS or VueJS. Indeed, Web Components are unable to receive complex attribute data (aka &lt;code&gt;prop&lt;/code&gt; in component terms). Like any html tag, they can only receive scalar / textual data (aka &lt;code&gt;attribute&lt;/code&gt;).  This makes their use very limited.&lt;/p&gt;

&lt;p&gt;Some have used &lt;a href="https://github.com/alesgenova/stenciljs-in-react#appendix-attribute-vs-prop"&gt;hacks&lt;/a&gt; to get around this limitation, but I'm not sure the game is worth it.&lt;/p&gt;

&lt;p&gt;Therefore, &lt;strong&gt;StencilJS is a very good choice if you want to create graphical components without logic&lt;/strong&gt; (dumb components) in an application or if you want to create widgets that can be integrated out of context everywhere.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>CouchDB, The Open-Source Cloud Firestore Alternative?</title>
      <dc:creator>Demangeon Julien</dc:creator>
      <pubDate>Wed, 25 Sep 2019 14:29:47 +0000</pubDate>
      <link>https://forem.com/juliendemangeon/couchdb-the-open-source-cloud-firestore-alternative-2gc0</link>
      <guid>https://forem.com/juliendemangeon/couchdb-the-open-source-cloud-firestore-alternative-2gc0</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: This post was originally posted on &lt;a href="https://marmelab.com/blog/2019/09/25/couchdb_pouchdb_serious_firebase_alternative.html" rel="noopener noreferrer"&gt;marmelab.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;During one of our last customer projects, we used &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Firebase&lt;/strong&gt;&lt;/a&gt;, a backend-as-a-service by Google, as our backend. Althought satisfied by this "all-included" suite as a whole, we remained disappointed by its proprietary aspect.&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%2Fmarmelab.com%2Fstatic%2F0f8a741fb7fd02afba2b32f07a1362a4%2Ff711f%2Ffirebaselogo.webp" 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%2Fmarmelab.com%2Fstatic%2F0f8a741fb7fd02afba2b32f07a1362a4%2Ff711f%2Ffirebaselogo.webp" alt="Firebase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's why I took the initiative to &lt;strong&gt;look for an open-source alternative to Firebase&lt;/strong&gt; that could cover all our needs without depending on a third party service.&lt;/p&gt;

&lt;p&gt;The first step in this quest is to find a substitute to the &lt;a href="https://firebase.google.com/docs/firestore" rel="noopener noreferrer"&gt;&lt;strong&gt;Cloud Firestore&lt;/strong&gt;&lt;/a&gt; realtime NoSQL database for the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Do We Need?
&lt;/h2&gt;

&lt;p&gt;Using Firestore rather than a more classic database is not trivial. It often results from the need to quickly develop an application with the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Offline First&lt;/strong&gt;, client writes to local database that is synchronized with remote one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realtime&lt;/strong&gt;, remote changes must be in sync with our local database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some solutions exist to cover this need, most of them are based on &lt;strong&gt;NoSQL databases&lt;/strong&gt; such as &lt;a href="https://www.mongodb.com/fr" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt;, &lt;a href="http://cassandra.apache.org/" rel="noopener noreferrer"&gt;Cassandra&lt;/a&gt;, &lt;a href="https://www.rethinkdb.com/" rel="noopener noreferrer"&gt;RethinkDB&lt;/a&gt;, &lt;a href="https://gun.eco" rel="noopener noreferrer"&gt;Gun&lt;/a&gt; or others MongoDB based solutions like &lt;a href="https://docs.meteor.com/api/collections.html" rel="noopener noreferrer"&gt;Minimongo&lt;/a&gt;, &lt;a href="https://turtle-db.github.io/" rel="noopener noreferrer"&gt;turtleDB&lt;/a&gt; or &lt;a href="https://github.com/turtle-DB/tortoiseDB" rel="noopener noreferrer"&gt;tortoiseDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our case, we're going to give &lt;a href="http://couchdb.apache.org/" rel="noopener noreferrer"&gt;CouchDB&lt;/a&gt; (and &lt;a href="https://pouchdb.com/" rel="noopener noreferrer"&gt;PouchDB&lt;/a&gt; for the frontend) a try, because it's the more robust and best known solution from our point of view.&lt;/p&gt;

&lt;h2&gt;
  
  
  CouchDB &amp;amp; PouchDB
&lt;/h2&gt;

&lt;p&gt;CouchDB is an &lt;strong&gt;open-source&lt;/strong&gt; / &lt;strong&gt;cross-platform&lt;/strong&gt; document oriented database software. It is developed on the basis of the &lt;strong&gt;concurrency-oriented&lt;/strong&gt; &lt;a href="https://en.wikipedia.org/wiki/Erlang_(programming_language)" rel="noopener noreferrer"&gt;Erlang&lt;/a&gt; language, allowing it to benefit from an high scalability. It uses &lt;strong&gt;JSON&lt;/strong&gt; to store its data, and an &lt;strong&gt;HTTP API&lt;/strong&gt; to expose it.&lt;/p&gt;

&lt;p&gt;CouchDB was born in 2005. Since 2008, CouchDB became an &lt;strong&gt;Apache Software Foundation project&lt;/strong&gt;, which allows it to benefit from a lot of support and a large communauty.&lt;/p&gt;

&lt;p&gt;Here are the main features of CouchDB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Version&lt;/strong&gt; Concurrency Control (which lets you build offline-first solutions easily)&lt;/li&gt;
&lt;li&gt;Distributed Architecture with &lt;strong&gt;Replication&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Document Storage&lt;/li&gt;
&lt;li&gt;HTTP / REST API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since &lt;strong&gt;CouchDB runs on the server&lt;/strong&gt;, many client library allows to communicate with it thanks to the HTTP interface it offers.&lt;/p&gt;

&lt;p&gt;The most known CouchDB client library for the web is called PouchDB. &lt;strong&gt;PouchDB is an open-source Javascript database&lt;/strong&gt; that is designed to run within the browser. This way, it allows to &lt;strong&gt;store data locally&lt;/strong&gt; offline, and sync it with the remote CouchDB server when the user comes back online.&lt;/p&gt;

&lt;h2&gt;
  
  
  CouchDB &amp;amp; PouchDB in Practice
&lt;/h2&gt;

&lt;p&gt;Enough introduction, let's get practical! In this section, I'll describe the development of a &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;ReactJS&lt;/a&gt; application using CouchDB and PouchDB as database system, step by step. Meanwhile, I'll try, as much as I can, to compare the CouchDB implementation to the Firestore one.&lt;/p&gt;

&lt;p&gt;Also, I'll present you some of my latest loves in terms on Javascript librairies: &lt;a href="https://github.com/final-form/final-form" rel="noopener noreferrer"&gt;Final-Form&lt;/a&gt;, &lt;a href="https://elastic.github.io/eui/" rel="noopener noreferrer"&gt;ElasticUI&lt;/a&gt; and &lt;a href="https://github.com/poppinss/indicative" rel="noopener noreferrer"&gt;Indicative&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this project, I'm going to create a beer registry, which allows users to keep track of their beer stocks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;In order to keep this tutorial as simple as possible, I'll create a ReactJS application using &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;create-react-app&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;create-react-app reactive-beers &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;reactive-beers

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-S&lt;/span&gt; pouchdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application skeleton looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;julien@julien-P553UA:~/Projets/marmelab/reactive-beers&lt;span class="nv"&gt;$ &lt;/span&gt;tree &lt;span class="nt"&gt;-L&lt;/span&gt; 1
&lt;span class="nb"&gt;.&lt;/span&gt;
├── node_modules
├── package.json
├── package-lock.json
├── public
├── README.md
└── src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, since I don't want to install CouchDB directly on my machine, I'll use &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;. So, the first step is to configure a &lt;code&gt;docker-compose.yml&lt;/code&gt; file and the associated &lt;code&gt;Makefile&lt;/code&gt; to improve developer experience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;// ./docker-compose.yml&lt;/span&gt;

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.1"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;couchdb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;couchdb:2.3.0&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5984:5984"&lt;/span&gt;

  &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:10&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm start&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/app"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.:/app"&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4242:3000"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;couchdb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ./Makefile&lt;/span&gt;

USER_ID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;shell &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
GROUP_ID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;shell &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;UID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;USER_ID&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;GID &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;GROUP_ID&lt;span class="si"&gt;)&lt;/span&gt;

DOCKER_COMPOSE_DEV &lt;span class="o"&gt;=&lt;/span&gt; docker-compose &lt;span class="nt"&gt;-p&lt;/span&gt; reactive-beers

&lt;span class="nb"&gt;help&lt;/span&gt;: &lt;span class="c"&gt;## Display available commands&lt;/span&gt;
    @fgrep &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="s2"&gt;"##"&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;MAKEFILE_LIST&lt;span class="si"&gt;)&lt;/span&gt; | fgrep &lt;span class="nt"&gt;-v&lt;/span&gt; fgrep | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'&lt;/span&gt;

&lt;span class="nb"&gt;install&lt;/span&gt;: &lt;span class="c"&gt;## Install docker stack&lt;/span&gt;
    &lt;span class="si"&gt;$(&lt;/span&gt;DOCKER_COMPOSE_DEV&lt;span class="si"&gt;)&lt;/span&gt; run &lt;span class="nt"&gt;--rm&lt;/span&gt; node bash &lt;span class="nt"&gt;-ci&lt;/span&gt; &lt;span class="s1"&gt;'npm install'&lt;/span&gt;

start: &lt;span class="c"&gt;## Start all the stack&lt;/span&gt;
    &lt;span class="si"&gt;$(&lt;/span&gt;DOCKER_COMPOSE_DEV&lt;span class="si"&gt;)&lt;/span&gt; up &lt;span class="nt"&gt;-d&lt;/span&gt;

stop: &lt;span class="c"&gt;## Stop all the containers&lt;/span&gt;
    &lt;span class="si"&gt;$(&lt;/span&gt;DOCKER_COMPOSE_DEV&lt;span class="si"&gt;)&lt;/span&gt; down

log: &lt;span class="c"&gt;## Show logs&lt;/span&gt;
    &lt;span class="si"&gt;$(&lt;/span&gt;DOCKER_COMPOSE_DEV&lt;span class="si"&gt;)&lt;/span&gt; logs &lt;span class="nt"&gt;-f&lt;/span&gt; node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we're now ready to start our complete stack using &lt;code&gt;make install start&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;julien@julien-P553UA:~/Projets/marmelab/reactive-beers&lt;span class="nv"&gt;$ &lt;/span&gt;docker ps
CONTAINER ID        IMAGE            COMMAND                  CREATED       STATUS       PORTS                                        NAMES
6884f92c5341        node:10          &lt;span class="s2"&gt;"npm start"&lt;/span&gt;              3 hours ago   Up 3 hours   0.0.0.0:4242-&amp;gt;3000/tcp                       reactive-beers_node_1
21897f166ce4        couchdb:2.3.0    &lt;span class="s2"&gt;"tini -- /docker-ent…"&lt;/span&gt;   3 hours ago   Up 3 hours   4369/tcp, 9100/tcp, 0.0.0.0:5984-&amp;gt;5984/tcp   reactive-beers_couchdb_1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is launched. You may have noticed that the &lt;code&gt;5984&lt;/code&gt; port is exposed in our &lt;code&gt;docker-compose.yml&lt;/code&gt; file, it's the CouchDB api. Then, if you open &lt;code&gt;localhost:5984&lt;/code&gt; in the browser, you'll see something similar to the following.&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;"couchdb"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Welcome"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&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.3.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"git_sha"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"07ea0c7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"49f4e7520f0e110687dcbc8fbbb5409c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"features"&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="s2"&gt;"pluggable-storage-engines"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scheduler"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vendor"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Apache Software Foundation"&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;h2&gt;
  
  
  Accessing The Document Store
&lt;/h2&gt;

&lt;p&gt;OK, our server is up and running. But, is there an &lt;strong&gt;interface to visualise / supervise&lt;/strong&gt; CouchDB just like Firestore does? The answer is YES! CouchDB already includes an administration interface called &lt;code&gt;Fauxton&lt;/code&gt;. We can browse it at &lt;code&gt;http://localhost:5984/_utils/&lt;/code&gt;.&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%2Fmarmelab.com%2Fstatic%2Ffdcdf33d6e0063a5389376d90d9ba863%2F5e3ff%2Ffirestore.webp" 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%2Fmarmelab.com%2Fstatic%2Ffdcdf33d6e0063a5389376d90d9ba863%2F5e3ff%2Ffirestore.webp" alt="Firestore interface"&gt;&lt;/a&gt;&lt;br&gt;Firestore Admin Interface
  &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%2Fmarmelab.com%2Fstatic%2Fc378a34f9c75a0d001af9b8ae2a31db7%2F5e3ff%2Ffauxton.webp" 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%2Fmarmelab.com%2Fstatic%2Fc378a34f9c75a0d001af9b8ae2a31db7%2F5e3ff%2Ffauxton.webp" alt="Fauxton interface"&gt;&lt;/a&gt;&lt;br&gt;Fauxton Admin Interface
  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Fauxton&lt;/code&gt; interface allows to access databases, setup nodes and clusters, configure replication, setup permissions, etc. Although practical, &lt;strong&gt;it is still preferable to automate these administration tasks with dedicated scripts&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Kicks In
&lt;/h2&gt;

&lt;p&gt;Now, we can start to develop our first PouchDB powered interface. Then, here are our main &lt;code&gt;App.js&lt;/code&gt; entry point and the &lt;code&gt;Home.js&lt;/code&gt; start screen.&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="c1"&gt;// ./src/App.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./screens/Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Home&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&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;App.js&lt;/code&gt; file has no interest for the moment. It'll certainly become useful when we need to add more routes and screens in the future.&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="c1"&gt;// ./src/screens/Home.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addBeer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getBeers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onBeersChange&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../api/beers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;beers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBeers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refreshBeers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getBeers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setBeers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// We fetch beers the first time (at mounting)&lt;/span&gt;
    &lt;span class="nf"&gt;refreshBeers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Each change in our beers database will call refreshBeers&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;onBeersChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refreshBeers&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Don't forget to unsubscribe our listener at unmounting&lt;/span&gt;
        &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;addBeer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Beer X&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* beer._id is an unique id generated by CouchDB */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;beers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&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="nx"&gt;beer&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CouchDB Requires More Requests Than Firestore
&lt;/h2&gt;

&lt;p&gt;As you see, in this example we use a combination of a listener (&lt;code&gt;onBeersChange&lt;/code&gt;) and a a query (&lt;code&gt;getBeers&lt;/code&gt;) to get the initial beers list and refresh it when a change is issued in the database.&lt;/p&gt;

&lt;p&gt;This operation is not optimal compared to the one Firestore offers. Indeed, while &lt;strong&gt;pouchdb is not able to return both changes and data&lt;/strong&gt; to us, Firestore is able to do so thanks to a &lt;code&gt;QuerySnapshot&lt;/code&gt; system, thereby reducing server trips back and forth. See by yourself with the Firestore example below:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anything&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="nf"&gt;onSnapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;querySnapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;querySnapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// This forEach loop is executed at first execution&lt;/span&gt;
          &lt;span class="c1"&gt;// And executed each time the query result changes&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;So, if we had used Firestore instead, here's what it would have looked like:&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="c1"&gt;//...&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;beers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBeers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beers&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="nf"&gt;onSnapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;querySnapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapBeers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
          &lt;span class="nx"&gt;querySnapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;snapBeers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;

          &lt;span class="nf"&gt;setBeers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snapBeers&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;unsubscribe&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="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's also possible to use &lt;code&gt;.map&lt;/code&gt; on the &lt;code&gt;querySnapshot.docs&lt;/code&gt; attribute to retrieve all the documents in a "non-imperative" way. Unfortunately, this functionality is not sufficiently covered by the official documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Model
&lt;/h2&gt;

&lt;p&gt;Just like in backend development, I like to separate the model logic from the view logic in my frontend apps. So here is the API file for our beers below:&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="c1"&gt;// ./src/api/beers.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PouchDB&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pouchdb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// We declare a PouchDB instance that is "remote only"&lt;/span&gt;
&lt;span class="c1"&gt;// There's no "offline" capability for the moment, everything is sync&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beersDatabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PouchDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:5984/beers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// If the beers database does not already exist&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; The database is automatically created when an object is added to it&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addBeer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;beer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;beersDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Here, we list all the documents from our beers database&lt;/span&gt;
&lt;span class="c1"&gt;// A lot of options exists. Eg: we can paginate using "startKey", "endKey" or "limit"&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getBeers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;beersDatabase&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allDocs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;include_docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;descending&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// We listen all the changes that happen since now&lt;/span&gt;
&lt;span class="c1"&gt;// We can also apply a "limit" option to this method&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onBeersChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;beersDatabase&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;since&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;now&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;live&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the result of our first CouchDB application in action. As you can see, everything is in sync between multiple windows.&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%2Fmarmelab.com%2Fsync-beers-b5961268f0dda773642fcd11173a5715.gif" 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%2Fmarmelab.com%2Fsync-beers-b5961268f0dda773642fcd11173a5715.gif" alt="PouchDB sync"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Offline Sync
&lt;/h3&gt;

&lt;p&gt;Sadly, our actual version only works when the internet access is up and running. In other cases, such as a bloated network or packet loss, beers will never (or slowwwwly...) be added in the beers list because of the "remote only" sync.&lt;/p&gt;

&lt;p&gt;The right way to avoid this problem is to keep a &lt;strong&gt;local first&lt;/strong&gt; approach. It means that we must achieve all our database operations on the local database, then synchronize it with the remote one when internet access comes back.&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%2Fmarmelab.com%2Fstatic%2Ff10e78636cdc43ba0a8ab24292528975%2F5443b%2Fnointernet.webp" 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%2Fmarmelab.com%2Fstatic%2Ff10e78636cdc43ba0a8ab24292528975%2F5443b%2Fnointernet.webp" alt="Internet Offline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, the first step is to declare a new PouchDB instance with a database name instead of a remote database url. This way, PouchDB automatically detects that we want to instantiate a local database.&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PouchDB&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pouchdb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Declare local database&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beersDatabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PouchDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Declare remote database&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remoteBeersDatabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PouchDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`http://localhost:5984/beers`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Keep local and remote databases in sync&lt;/span&gt;
&lt;span class="nx"&gt;PouchDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beersDatabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteBeersDatabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;live&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// replicate changes in live&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// disable timeout&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// retry sync if fail&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;PouchDB.sync&lt;/code&gt; instruction is the equivalent of a bidirectionnal &lt;code&gt;PouchDB.replicate&lt;/code&gt; instruction between local and remote databases.&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;PouchDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beersDatabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remoteBeersDatabase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;PouchDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remoteBeersDatabase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;beersDatabase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, PouchDB uses &lt;a href="https://developers.google.com/web/ilt/pwa/working-with-indexeddb" rel="noopener noreferrer"&gt;IndexedDB&lt;/a&gt; as local database (just like Firestore by the way). So, now that our setup is done, we can take a look at our local database using the Chrome console.&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%2Fmarmelab.com%2Fstatic%2Ff43455cb45fcdd00845ea719ce4ee1fd%2F5e3ff%2Findexeddbcapture.webp" 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%2Fmarmelab.com%2Fstatic%2Ff43455cb45fcdd00845ea719ce4ee1fd%2F5e3ff%2Findexeddbcapture.webp" alt="Indexed DB"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we find the complete list of beers we've created. Each one is uniquely identified by a &lt;code&gt;key&lt;/code&gt; that is built from &lt;code&gt;_id&lt;/code&gt; and &lt;code&gt;_rev&lt;/code&gt; CouchDB attributes.&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_id&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;0c2738a3-d363-405f-b9bb-0ab6f5ec9655&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;_rev&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;3-b90bd9d62fbe04e36fe262a267efbd42&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;title&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;Beer X&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whereas the &lt;code&gt;_id&lt;/code&gt; represents an unique document, the &lt;code&gt;_rev&lt;/code&gt; represents the &lt;strong&gt;revision&lt;/strong&gt; identifier of it. In fact, each modification of a document implies a new version of it which then makes it possible to manage conflicts.&lt;/p&gt;

&lt;p&gt;Unlike CouchDB, Firestore documents do not have a &lt;strong&gt;revision&lt;/strong&gt; id. So, the only way not to struggle with conflicts using Firestore is to use &lt;a href="https://firebase.google.com/docs/firestore/manage-data/transactions" rel="noopener noreferrer"&gt;&lt;strong&gt;transactions&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Moreover, since CouchDB records every submitted change, &lt;strong&gt;it is possible to return back or resolve conflict in a second time&lt;/strong&gt;, which is essential in order not to risk losing data.&lt;/p&gt;

&lt;p&gt;For more information on conflict management using PouchDB, check &lt;a href="https://pouchdb.com/guides/conflicts.html" rel="noopener noreferrer"&gt;the PouchDB Conflict documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we are able to communicate with both local and remote databases, we can focus on the business logic and on the user interface.  Moreover, it'll allow us to benefit from &lt;strong&gt;optimistic rendering&lt;/strong&gt; while making our application &lt;strong&gt;more flexible in addressing network issues&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forms &amp;amp; Validation
&lt;/h2&gt;

&lt;p&gt;In this section, we will implement a form to be able to add new beers. To do that, I'm going to use &lt;code&gt;final-form&lt;/code&gt; (and &lt;code&gt;react-final-form&lt;/code&gt;, an adapter for ReactJS).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-S&lt;/span&gt; final-form react-final-form
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we can create a simple form to handle user input.&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="c1"&gt;// ./src/components/BeerForm.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Field&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-final-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BeerForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Form&lt;/span&gt;
    &lt;span class="nx"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({})}&lt;/span&gt;
    &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{({&lt;/span&gt;
      &lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;hasValidationErrors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;pristine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;invalid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;submitErrors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;submitting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;form&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="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&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;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Field&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Field&lt;/span&gt;
              &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;textarea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tape your description here...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pristine&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;hasValidationErrors&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;submitting&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;Submit&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;submitErrors&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;submitErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;submitErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;Then, we can replace our action button by the form in our home screen.&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="c1"&gt;// ./src/screens/Home.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addBeer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getBeers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onBeersChange&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../api/beers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;beers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBeers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

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

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BeerForm&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addBeer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* beer._id is an unique id generated by CouchDB */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;beers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&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="nx"&gt;beer&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Data Validation With Indicative
&lt;/h2&gt;

&lt;p&gt;So, we have a form, but there's no data validation for the moment. Users can send anything they want at this time. That's why we're going to set up a data validator using &lt;code&gt;indicative&lt;/code&gt;, a library that I've just discovered and that I want to give a try.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-S&lt;/span&gt; indicative
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Indicative API is very simple. It consists of a &lt;code&gt;Validator&lt;/code&gt; object that uses a set of validation rules and a &lt;code&gt;formatter&lt;/code&gt;. Here is a usage example:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Validator&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;indicative/builds/validator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Vanilla&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;VanillaFormatter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;indicative/builds/formatters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;indicative/builds/validations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Validator&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;VanillaFormatter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required|email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required&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="s1"&gt;{{ field }} field is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// This message works for all required rules&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email.required&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="s1"&gt;You must provide an email!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// This message is specific for required email&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email.email&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="s1"&gt;The email adress is invalid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bad email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Validator.validate is async&lt;/span&gt;

&lt;span class="nx"&gt;validator&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="cm"&gt;/* everything is ok! */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;errors&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="cm"&gt;/*
      [
        { field: 'name', message: 'name field is required!' },
        { field: 'email', message: 'The email adress is invalid' },
      ]
    */&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is our custom implementation for &lt;code&gt;BeerForm.js&lt;/code&gt;.&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="c1"&gt;// ./src/components/BeerForm.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Field&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-final-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Vanilla&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;indicative/builds/formatters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Validator&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;indicative/builds/validator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;indicative/builds/validations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Validator&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;Vanilla&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title.required&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="s1"&gt;Beer title is required&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="s1"&gt;description.required&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="s1"&gt;Beer description is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;validator&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="p"&gt;({}))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errors&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;return&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;acc&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final Form needs an object as error model, so we format errors in the &lt;code&gt;catch&lt;/code&gt; using a &lt;code&gt;reduce&lt;/code&gt;. Alternatively, it would have been possible to use a &lt;a href="https://indicative.adonisjs.com/docs/formatters#_creating_your_own" rel="noopener noreferrer"&gt;Custom Indicative Formatter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, now we have our custom validation function, we can replace our empty validate function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;export const BeerForm = ({ onSubmit }) =&amp;gt; (
&lt;/span&gt;  &amp;lt;Form
&lt;span class="gd"&gt;-  validate={() =&amp;gt; ({})}
&lt;/span&gt;&lt;span class="gi"&gt;+  validate={validate}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And tadaaa! Our validated form is up and running and we are ready to play with it.&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%2Fmarmelab.com%2Ffinalformexample-01ec0a572c0ec1fa17489fca7b68df3e.gif" 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%2Fmarmelab.com%2Ffinalformexample-01ec0a572c0ec1fa17489fca7b68df3e.gif" alt="Final Form Indicative"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Make It Beautiful!
&lt;/h2&gt;

&lt;p&gt;To summarize, we can display beers, we can add beers, everything works offline and is in sync with a remote server. But right now, it's not very aesthetic, and I wouldn't dare present it to my mother-in-law. So, how about making it a little prettier?&lt;/p&gt;

&lt;p&gt;In this section, I'll use the &lt;a href="https://elastic.github.io/eui/" rel="noopener noreferrer"&gt;Elastic UI&lt;/a&gt; framework (aka &lt;code&gt;eui&lt;/code&gt;) that is in use at &lt;a href="https://www.elastic.co/fr/" rel="noopener noreferrer"&gt;Elastic&lt;/a&gt;, the company that develops ElasticSearch.&lt;/p&gt;

&lt;p&gt;I think we all agree that we must remove this despicable list and replace it with a nice grid. Fortunately, Eui allows it easily.&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%2Fmarmelab.com%2Fstatic%2Fe8d11cc732ffe9172914a6b8b72c0d93%2F5e3ff%2Fbeergridfull.webp" 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%2Fmarmelab.com%2Fstatic%2Fe8d11cc732ffe9172914a6b8b72c0d93%2F5e3ff%2Fbeergridfull.webp" alt="Beer Grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we took the opportunity to add editing and deleting beers right from the grid. We'll also put the form in a sliding panel from the right of the page. This way, we can directly add a beer from a "+" button in the navbar, or edit a beer directly from the grid, without changing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Image Attachments
&lt;/h2&gt;

&lt;p&gt;I don't know about you, but seeing all these grey beer cans breaks my heart. So it's time to allow image upload in the form.&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="c1"&gt;// ./src/components/BeerForm.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleIllustration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;files&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&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;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&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="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&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;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_image&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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;EuiFormRow&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Beer Illustration&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EuiFilePicker&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleIllustration&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/EuiFormRow&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This custom &lt;code&gt;_image&lt;/code&gt; attribute that I just added to the beer object is then handled by our beer api, and considered as a &lt;a href="https://pouchdb.com/guides/attachments.html" rel="noopener noreferrer"&gt;&lt;strong&gt;PouchDB attachement&lt;/strong&gt;&lt;/a&gt;.&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="c1"&gt;// ./src/api/queries.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveBeer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beers&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="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;beer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rev&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;// if an "_image" attribute is present, we put an attachement to the document&lt;/span&gt;
        &lt;span class="nx"&gt;_image&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="nx"&gt;store&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beers&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="nf"&gt;putAttachment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getBeers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;store&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beers&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="nf"&gt;allDocs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;include_docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;descending&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;attachments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// We include images in the output, so we can display them&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;doc&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;In CouchDB, every file can directly be attached to its corresponding document as an &lt;code&gt;attachement&lt;/code&gt;. This concept does not exist in Firestore. It is then preferable to use &lt;a href="https://firebase.google.com/docs/storage" rel="noopener noreferrer"&gt;Firebase Storage&lt;/a&gt; (Google Cloud Storage) through its bucket system to store files and store paths in Firestore.&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%2Fmarmelab.com%2Fbeerregistry-24aa02cf340233c71fdb4429a3d8851e.gif" 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%2Fmarmelab.com%2Fbeerregistry-24aa02cf340233c71fdb4429a3d8851e.gif" alt="Final Application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The final result of my beer registry application is available on GitHub  at the following address: &lt;a href="https://github.com/marmelab/reactive-beers" rel="noopener noreferrer"&gt;github.com/marmelab/reactive-beers&lt;/a&gt;. Feel free to comment and improve!&lt;/p&gt;

&lt;p&gt;While I was doubtful about the power of CouchDB at first, I was quickly conquered by its stability and the ease of use of its API.&lt;/p&gt;

&lt;p&gt;Since I have not yet deployed this type of application in production, I am not in a position to comment on the ease of maintenance of this type of database. Nevertheless, I would rather recommend using &lt;strong&gt;Firestore for POCs&lt;/strong&gt;, and a &lt;strong&gt;third-party service like &lt;a href="https://www.couchbase.com/products/data-platform" rel="noopener noreferrer"&gt;Couchbase&lt;/a&gt; or &lt;a href="https://www.ibm.com/cloud/cloudant" rel="noopener noreferrer"&gt;IBM Cloudant&lt;/a&gt; for critical applications&lt;/strong&gt; in the first place.&lt;/p&gt;

&lt;p&gt;Although this experience allowed me to balance the pros and cons of the main features of each database, it was not possible for me to go as far as I had expected.&lt;/p&gt;

&lt;p&gt;Indeed, I didn't have time to cover many crucial points such as &lt;em&gt;document access security&lt;/em&gt;, &lt;em&gt;rights management&lt;/em&gt;, &lt;em&gt;server-side document validation&lt;/em&gt;, &lt;em&gt;data pagination&lt;/em&gt; or &lt;em&gt;deployment&lt;/em&gt;. But no matter what, I am determined to write more articles on these topics.&lt;/p&gt;

&lt;p&gt;So, Stay tuned!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>offline</category>
      <category>realtime</category>
    </item>
    <item>
      <title>Build Augmented Reality Applications With React-Native</title>
      <dc:creator>Demangeon Julien</dc:creator>
      <pubDate>Thu, 25 Apr 2019 12:32:35 +0000</pubDate>
      <link>https://forem.com/juliendemangeon/build-augmented-reality-applications-with-react-native-3g73</link>
      <guid>https://forem.com/juliendemangeon/build-augmented-reality-applications-with-react-native-3g73</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: This post was originally posted on &lt;a href="https://marmelab.com/blog/2019/04/25/react-native-augmented-reality.html" rel="noopener noreferrer"&gt;marmelab.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Augmented Reality is one of the most important trends currently. So, after &lt;a href="https://marmelab.com/blog/2017/06/19/augmented-reality-html5.html" rel="noopener noreferrer"&gt;our trial using the browser&lt;/a&gt; over 1 year ago, I wanted to test a framework offering the possibility to &lt;strong&gt;create native augmented reality experiences&lt;/strong&gt;. Read on to see how I developed a reversi game application on mobile using React-Native.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/316986012" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Augmented Reality?
&lt;/h2&gt;

&lt;p&gt;As the "Artificial Intelligence" term can be mixed up with other related concepts, &lt;strong&gt;Augmented Reality&lt;/strong&gt; (AR) is quite often mistaken with &lt;strong&gt;Virtual Reality&lt;/strong&gt; (VR). In fact, &lt;strong&gt;VR&lt;/strong&gt; and &lt;strong&gt;AR&lt;/strong&gt; are not the same at all. While VR is a projection of a virtual world to our eyes, AR is a &lt;em&gt;blended&lt;/em&gt; projection of a virtual object in the real world.&lt;/p&gt;

&lt;p&gt;I invite you to check a more detailed description of these concepts in our previous blog post about &lt;a href="https://marmelab.com/blog/2017/06/19/augmented-reality-html5.html#what-is-augmented-reality" rel="noopener noreferrer"&gt;AR in the browser&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Augmented Reality In Javascript With Native Performance
&lt;/h2&gt;

&lt;p&gt;At Marmelab, we are absolute fans of React and its ecosystem. That's why we develop &lt;a href="https://github.com/marmelab/" rel="noopener noreferrer"&gt;a lot of open-source tools&lt;/a&gt; and &lt;a href="https://marmelab.com/fr/showcase/" rel="noopener noreferrer"&gt;projects&lt;/a&gt; for our customers using this technology.&lt;/p&gt;

&lt;p&gt;I don't pretend to be a good Java, Kotlin, CSharp or Swift developer. But I also want to have good performance on mobile, so using a web framework like React is out of the question. So I started looking for a native framework which lets me develop iOS and Android apps with both Javascript and React.&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%2Fmarmelab.com%2Fstatic%2F6949bbe5488350d751c835ed3f4873fc%2Fdcb89%2Fviro.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%2Fmarmelab.com%2Fstatic%2F6949bbe5488350d751c835ed3f4873fc%2Fdcb89%2Fviro.png" alt="Viro"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After several minutes of research, the only obvious choice was to use &lt;a href="https://viromedia.com/viroreact" rel="noopener noreferrer"&gt;ViroReact&lt;/a&gt;. Under the hood, this framework is based on two APIs that dominate the world of Augmented and Virtual Reality for mobile phones: &lt;strong&gt;ARKit for iOS&lt;/strong&gt; and &lt;strong&gt;ARCore for Android&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ARKit&lt;/strong&gt; is actually the biggest existing AR platform. It allows to develop rich immersive experiences on Apple devices having at least an A9 chip and iOS 11.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ARCore&lt;/strong&gt; is more or less the same, except that it supports a &lt;a href="https://developers.google.com/ar/discover/supported-devices" rel="noopener noreferrer"&gt;short list of devices&lt;/a&gt; that are considered to be powerful enough to run the API at its best. And also iOS devices, &lt;a href="https://developers.google.com/ar/develop/ios/overview" rel="noopener noreferrer"&gt;apparently?&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The rather limited support of devices is the major weakness of these APIs for the moment. Over time, phones will become more and more powerful, which will make it possible to use them more often.&lt;/p&gt;

&lt;h2&gt;
  
  
  Viro, The Outsider
&lt;/h2&gt;

&lt;p&gt;Viro is a free AR/VR development platform that allows building cross-platform applications using React-Native, and fully native Android applications using Java. It supports multiple platforms and APIs such as ARKit, ARCore, Cardboard, Daydream or GearVR.&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%2Fmarmelab.com%2Fstatic%2Fb2dd8be5a48c6d852e8eb4781b281f58%2Fdcb89%2Fviro-devices.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%2Fmarmelab.com%2Fstatic%2Fb2dd8be5a48c6d852e8eb4781b281f58%2Fdcb89%2Fviro-devices.png" alt="Viro Supported Platforms"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As previously said, Viro allows building both fully native application and React-Native ones. That's why Viro provides two distinct packages: &lt;a href="https://virocore.viromedia.com/" rel="noopener noreferrer"&gt;ViroCore&lt;/a&gt; and &lt;a href="https://docs.viromedia.com/" rel="noopener noreferrer"&gt;ViroReact&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To use it, you're still required to sign up&lt;/strong&gt;. The API key which is provided following registration is mandatory to be able to use the platform.&lt;/p&gt;

&lt;p&gt;Sadly, &lt;strong&gt;Viro is not open-source but (only) free to use&lt;/strong&gt; with no limits on distribution. According to the ViroMedia CEO, the API key is used for internal analytics and to guard against possible &lt;a href="https://docs.viromedia.com/docs/license" rel="noopener noreferrer"&gt;license&lt;/a&gt; violations.&lt;/p&gt;

&lt;blockquote&gt;VIRO reserves the right, at any time, to modify, suspend, or discontinue the Software, or change access requirements, with or without notice.&lt;/blockquote&gt;

&lt;p&gt;Regarding the license note above, it is therefore necessary to remain vigilant regarding its use since &lt;strong&gt;we have no guarantee on the evolution of the platform&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Contact With ViroReact
&lt;/h2&gt;

&lt;p&gt;In this section, I'll cover the major parts of the Viro Framework with a simple use case: a 3D projection of the Marmelab logo !&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/cxT63CxU-ag"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;First, we need to create a 3D mesh to be able to include it in our project. Special thanks to &lt;a href="https://github.com/jpetitcolas" rel="noopener noreferrer"&gt;@jpetitcolas&lt;/a&gt; who created the Marmelab logo using blender a few years ago.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Before using Viro, we need to install some npm dependencies. Viro requires &lt;code&gt;react-native-cli&lt;/code&gt; and &lt;code&gt;react-viro-cli&lt;/code&gt; as global packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; react-native-cli
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; react-viro-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we can initialize a Viro project using the special command &lt;code&gt;react-viro init&lt;/code&gt;, followed by the project name. A folder with the same name is then created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;react-viro init marmelab_for_real
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, what can we see in this project? Well, the folder structure is quite similar to the usual ones we encounter with React-Native, no surprise on this point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── android
├── bin
├── ios
├── js
├── node_modules
├── App.js
├── app.json
├── index.android.js
├── index.ios.js
├── index.js
├── metro.config.js
├── package.json
├── rn-cli.config.js
├── setup-ide.sh
└── yarn.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Developer Experience
&lt;/h3&gt;

&lt;p&gt;Once the project is initialized, we just have to launch it using the &lt;code&gt;npm start&lt;/code&gt; command. Viro will automatically create an &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;ngrok tunnel&lt;/a&gt;, which can be used by any phone connected to the internet around the globe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;julien@julien-laptop /tmp/foo &lt;span class="nv"&gt;$ &lt;/span&gt;npm start

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; foo@0.0.1 prestart /tmp/foo
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ./node_modules/react-viro/bin/run_ngrok.sh

 &lt;span class="nt"&gt;----------------------------------------------------------&lt;/span&gt;
|                                                          |
| NGrok Packager Server endpoint: http://32a5a3d7.ngrok.io |
|                                                          |
 &lt;span class="nt"&gt;----------------------------------------------------------&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; foo@0.0.1 start /tmp/foo
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; node node_modules/react-native/local-cli/cli.js start

┌──────────────────────────────────────────────────────────────────────────────┐
│                                                                              │
│  Running Metro Bundler on port 8081.                                         │
│                                                                              │
│  Keep Metro running &lt;span class="k"&gt;while &lt;/span&gt;developing on any JS projects. Feel free to        │
│  close this tab and run your own Metro instance &lt;span class="k"&gt;if &lt;/span&gt;you prefer.               │
│                                                                              │
│  https://github.com/facebook/react-native                                    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To access the application, we just have to use the special &lt;a href="https://play.google.com/store/apps/details?id=com.viromedia.viromedia" rel="noopener noreferrer"&gt;TestBed application&lt;/a&gt; from Viro with the corresponding tunnel or local ip (if you're connected locally). On those aspects, Viro reminds me of &lt;a href="https://expo.io/" rel="noopener noreferrer"&gt;Expo&lt;/a&gt;. Then, we're able to access the test application:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/326854583" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In addition to these running facilities, Viro also offers hot-reloading, live-reloading, error messages &amp;amp; warnings directly on the device, just like any React-Native application does.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing a Scene Navigator
&lt;/h3&gt;

&lt;p&gt;Depending on the type of project you want, Viro provides 3 distinct &lt;code&gt;SceneNavigator&lt;/code&gt; components which are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ViroVRSceneNavigator: For VR Applications&lt;/li&gt;
&lt;li&gt;ViroARSceneNavigator: For AR Applications&lt;/li&gt;
&lt;li&gt;Viro3DSceneNavigator: For 3D (not AR/VR) Applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This components are used as entry points for our application. You must choose one depending on what you want to do, in our case &lt;code&gt;ViroARSceneNavigator&lt;/code&gt; for Augmented Reality.&lt;/p&gt;

&lt;p&gt;Each &lt;code&gt;SceneNavigator&lt;/code&gt; requires two distinct props which are &lt;code&gt;apiKey&lt;/code&gt; and &lt;code&gt;initialScene&lt;/code&gt;. The first one comes from your registration on the Viro website, the second one is an object with a &lt;code&gt;scene&lt;/code&gt; attribute with our scene component as value.&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="c1"&gt;// App.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StyleSheet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ViroARSceneNavigator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-viro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;VIROAPIKEY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native-dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PlayScene&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/PlayScene&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StyleSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#fff&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;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&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;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ViroARSceneNavigator&lt;/span&gt;
            &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;VIROAPIKEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;initialScene&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PlayScene&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we want to keep our Viro &lt;code&gt;apiKey&lt;/code&gt; private, we use the &lt;code&gt;react-native-dotenv&lt;/code&gt; package in conjunction with a &lt;code&gt;.env&lt;/code&gt; file at the root of our project folder.&lt;/p&gt;

&lt;p&gt;To make it psosible, just install this package with &lt;code&gt;yarn add -D react-native-dotenv&lt;/code&gt; and create a &lt;code&gt;.env&lt;/code&gt; file with &lt;code&gt;VIROAPIKEY=&amp;lt;YOUR-VIRO-API-KEY&amp;gt;&lt;/code&gt; in it.&lt;/p&gt;

&lt;p&gt;The last step is to add the preset to babel has described below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// .babelrc
&lt;span class="err"&gt;
&lt;/span&gt;{
  "presets": [
    "module:metro-react-native-babel-preset",
&lt;span class="gi"&gt;+   "module:react-native-dotenv"
&lt;/span&gt;  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding a Scene
&lt;/h3&gt;

&lt;p&gt;Now that the bootstrap is done, it's time to develop our first scene!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.viromedia.com/docs/scenes" rel="noopener noreferrer"&gt;Viro Scenes&lt;/a&gt; act as containers for all our UI Objects, Lights and 3D objects. There are 2 types of Scene components: &lt;code&gt;ViroScene&lt;/code&gt; and &lt;code&gt;ViroARScene&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each &lt;code&gt;Scene&lt;/code&gt; contains a hierarchical tree structure of nodes that are managed by a full-featured 3D scene graph engine. &lt;code&gt;ViroScene&lt;/code&gt; children are positioned through &lt;code&gt;ViroNode&lt;/code&gt; components that represent &lt;strong&gt;positions&lt;/strong&gt; and &lt;strong&gt;transformations&lt;/strong&gt; in 3D space.&lt;/p&gt;

&lt;p&gt;So, almost every object under the tree has a &lt;code&gt;position&lt;/code&gt;, &lt;code&gt;rotation&lt;/code&gt; and &lt;code&gt;scale&lt;/code&gt; prop that accept an array of coordinates/vector (x, y, z) as described below.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ViroNode&lt;/span&gt;
    &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&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="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="nx"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
 &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we know how it works, we can create our first &lt;code&gt;ViroARScene&lt;/code&gt; (aka &lt;code&gt;PlayScene&lt;/code&gt;).&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="c1"&gt;// src/PlayScene.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ViroARScene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Viro3DObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ViroAmbientLight&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-viro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MarmelabLogo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Viro3DObject&lt;/span&gt;
        &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../assets/marmelab.obj&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../assets/marmelab.mtl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]}&lt;/span&gt;
        &lt;span class="nx"&gt;highAccuracyEvents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&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="mi"&gt;0&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="c1"&gt;// we place the object in front of us (z = -1)&lt;/span&gt;
        &lt;span class="nx"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="c1"&gt;// we reduce the size of our Marmelab logo object&lt;/span&gt;
        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OBJ&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PlayScene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ViroARScene&lt;/span&gt; &lt;span class="nx"&gt;displayPointCloud&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ViroAmbientLight&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MarmelabLogo&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ViroARScene&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PlayScene&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous code, we've introduced 2 new Viro Components that are &lt;code&gt;Viro3DObject&lt;/code&gt; and &lt;code&gt;ViroAmbiantLight&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Viro3DObject&lt;/code&gt; allows creating 3D objects from 3D structure / textures files that can be placed on our Viro &lt;code&gt;Scene&lt;/code&gt;. In our case, we declare a component using our previously blended Marmelab logo object.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ViroAmbientLight&lt;/code&gt; introduce some lighting in our &lt;code&gt;Scene&lt;/code&gt;. Without that light, no object is visible.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/331017433" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The final result is really amazing, especially since we spent very little time on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level Up: Developing A Reversi In AR
&lt;/h2&gt;

&lt;p&gt;After this little exploration, it's time for us to develop a more tangible application using this technology. Since I don't want to do modeling or coding business logic this time, I'll reuse an existing codebase and blended objects (disks) from a previous projects I worked on during a hackday. It's a &lt;a href="https://marmelab.com/blog/2017/06/15/animate-you-world-with-threejs-and-tweenjs.html" rel="noopener noreferrer"&gt;Reversi Game using ThreeJS&lt;/a&gt;.&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%2Fmarmelab.com%2Fstatic%2Fbae5d3a3e2917b6c1cfd1bf5d14a465a%2Fdcb89%2Farcoretarget.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%2Fmarmelab.com%2Fstatic%2Fbae5d3a3e2917b6c1cfd1bf5d14a465a%2Fdcb89%2Farcoretarget.png" alt="Anchor &amp;amp; Target"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Reversi PlayScene
&lt;/h3&gt;

&lt;p&gt;According to our previous experiment, we're going to replace our &lt;code&gt;PlayScene&lt;/code&gt; to include a new &lt;code&gt;Game&lt;/code&gt; component that contains a &lt;code&gt;Board&lt;/code&gt; that itself contains &lt;code&gt;Disk&lt;/code&gt; object components.&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="c1"&gt;// src/PlayScene.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ViroARScene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ViroAmbientLight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-viro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Game&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Game&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;createGame&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./reversi/game/Game&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;createPlayer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./reversi/player/Player&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TYPE_BLACK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TYPE_WHITE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./reversi/cell/Cell&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultGame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createGame&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;createPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TYPE_BLACK&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;createPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Charly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TYPE_WHITE&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PlayScene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultGame&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ViroARScene&lt;/span&gt; &lt;span class="nx"&gt;displayPointCloud&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ViroAmbientLight&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Game&lt;/span&gt; &lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ViroARScene&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PlayScene&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/components/Game.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Board&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Board&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getCurrentPlayer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../reversi/game/Game&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;game&lt;/span&gt; &lt;span class="p"&gt;}&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="nx"&gt;state&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Board&lt;/span&gt;
                &lt;span class="nx"&gt;board&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;board&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;currentCellType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;cellType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;onCellChange&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;handleCellChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Game relies on a Board and a Disk component:&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="c1"&gt;// src/components/Board.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prop-types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ViroNode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-viro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Disk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Disk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TYPE_WHITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TYPE_EMPTY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../reversi/cell/Cell&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Board&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="nx"&gt;renderCellDisk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Disk&lt;/span&gt;
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&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="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&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="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mf"&gt;0.03&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.03&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
            &lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;TYPE_WHITE&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;180&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="mi"&gt;0&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;opacity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;TYPE_EMPTY&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mf"&gt;0.15&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="nx"&gt;onClick&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="nf"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;board&lt;/span&gt; &lt;span class="p"&gt;}&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="nx"&gt;props&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ViroNode&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&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="nx"&gt;board&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cells&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&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="nx"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&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="nf"&gt;map&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;renderCellDisk&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ViroNode&lt;/span&gt;&lt;span class="err"&gt;&amp;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="nx"&gt;Board&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;propTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;onCellChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isRequired&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;currentCellType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isRequired&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;board&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Board&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Disk.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Viro3DObject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-viro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Disk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Viro3DObject&lt;/span&gt;
        &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../assets/disk.obj&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../assets/disk.mtl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]}&lt;/span&gt;
        &lt;span class="nx"&gt;highAccuracyEvents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&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="mi"&gt;0&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="nx"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mf"&gt;0.0007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0007&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OBJ&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Disk&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 working! However, I think we all agree that it is not possible to play Reversi on a floating board... That's why we're going to define an &lt;a href="https://docs.viromedia.com/docs/ar-tracking-and-anchors" rel="noopener noreferrer"&gt;Anchor&lt;/a&gt; on which we can place our &lt;code&gt;Game&lt;/code&gt; / &lt;code&gt;Board&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Placing Objects in Real-World
&lt;/h3&gt;

&lt;p&gt;In Augmented Reality terminology, the concept of &lt;em&gt;attaching virtual objects to a real-world point&lt;/em&gt; is called &lt;strong&gt;Anchoring&lt;/strong&gt;. According to that word, &lt;strong&gt;Anchors&lt;/strong&gt; are used to achieve this task.&lt;/p&gt;

&lt;p&gt;Anchors are &lt;strong&gt;vertical or horizontal planes&lt;/strong&gt;, or &lt;strong&gt;images&lt;/strong&gt; (often markers) found in the real world by the AR system (ARCore or ARKit) on which we can rely to build a virtual world. &lt;/p&gt;

&lt;p&gt;With Viro, Anchors are represented by an &lt;code&gt;Anchor&lt;/code&gt; object which can be found through &lt;strong&gt;Targets&lt;/strong&gt; using different detection methods, as described below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ViroARPlane&lt;/code&gt;: This component allows to use either "manual" (though an "anchorId") or "automatic" detection of a plane in the real-world to place objects on it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ViroARPlaneSelector&lt;/code&gt;: This component shows all the available planes discovered by the system and allows the user to select one.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ViroARImageMarker&lt;/code&gt;: This component allows to use an illustrated piece of paper as a physic anchor for our virtual objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my case, I've chosen the &lt;code&gt;ViroARImageMarker&lt;/code&gt; anchoring system because it seems more stable and performs better (at first glance).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ViroARImageMarker&lt;/code&gt; has a mandatory prop called &lt;code&gt;target&lt;/code&gt;. This prop which must contain the name of a registered target which has previously been declared using &lt;code&gt;ViroARTrackingTargets&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;The first thing to do is to create our target using the &lt;code&gt;createTargets&lt;/code&gt; function. In our case, we declare an image target named &lt;code&gt;marmelabAnchor&lt;/code&gt; (yes, I'm very corporate...) because I used the Marmelab logo as an anchor.&lt;/p&gt;

&lt;p&gt;Then, we can use this anchor name directly as anchor prop value of our new &lt;code&gt;ViroARImageMarker&lt;/code&gt; element around our &lt;code&gt;Game&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// src/PlayScene.js
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;import React from 'react';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;    ViroARScene,
    ViroAmbientLight,
&lt;span class="gi"&gt;+   ViroARTrackingTargets,
+   ViroARImageMarker,
&lt;/span&gt;} from 'react-viro';
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;import Game from './components/Game';
import { create as createGame } from './reversi/game/Game';
import { create as createPlayer } from './reversi/player/Player';
import { TYPE_BLACK, TYPE_WHITE } from './reversi/cell/Cell';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const defaultGame = createGame([
&lt;/span&gt;    createPlayer('John', TYPE_BLACK),
    createPlayer('Charly', TYPE_WHITE),
]);
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const PlayScene = () =&amp;gt; {
&lt;/span&gt;    const [game] = useState(defaultGame);
&lt;span class="err"&gt;
&lt;/span&gt;    return (
        &amp;lt;ViroARScene displayPointCloud&amp;gt;
            &amp;lt;ViroAmbientLight color="#fff" /&amp;gt;
&lt;span class="gi"&gt;+           &amp;lt;ViroARImageMarker target={'marmelabAnchor'}&amp;gt;
&lt;/span&gt;                &amp;lt;Game game={game} /&amp;gt;
&lt;span class="gi"&gt;+           &amp;lt;/ViroARImageMarker&amp;gt;
&lt;/span&gt;        &amp;lt;/ViroARScene&amp;gt;
    );
};
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ ViroARTrackingTargets.createTargets({
+     marmelabAnchor: {
+         type: 'Image',
+         source: require('./assets/target.jpg'), // source of the target image
+         orientation: 'Up', // desired orientation of the image
+         physicalWidth: 0.1, // with of the target in meters (10 centimeters in our case)
+     },
+ });
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;export default PlayScene;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All &lt;code&gt;children&lt;/code&gt; that are declared under the &lt;code&gt;ViroARImageMarker&lt;/code&gt; element in the tree are placed relatively to it. In our case, the &lt;code&gt;Game&lt;/code&gt; component is then placed over the &lt;code&gt;ViroARImageMarker&lt;/code&gt; target.&lt;/p&gt;

&lt;h3&gt;
  
  
  Animating The Scene
&lt;/h3&gt;

&lt;p&gt;Now the AR reversi game is working better. But it lacks a little bit of animation. So, how can we add the same disk flip effects as we made in our previous ThreeJS project?&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%2Fmarmelab.com%2Fdisk-flip-7216a5c65182c405694040170d061d68.gif" 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%2Fmarmelab.com%2Fdisk-flip-7216a5c65182c405694040170d061d68.gif" alt="Disk Flip"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To fill this usual need, ViroReact provides a global animation registry called &lt;strong&gt;ViroAnimations&lt;/strong&gt; that can be used everywhere in conjunction with any component that accepts an &lt;code&gt;animation&lt;/code&gt; prop.&lt;/p&gt;

&lt;p&gt;In our case, we're gonna &lt;strong&gt;compose transformations&lt;/strong&gt; together to create a complete disk flipping effect. Here is the desired scenario over time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;0 - 300ms&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;Move Up&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;300 - 600ms&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;Move Down&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;150 - 350ms&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;Rotate (during disk reaches the top)&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;First, we're gonna register an animation according to this transformation timeline.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ViroAnimations&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-viro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;span class="nx"&gt;ViroAnimations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerAnimations&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;moveUp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;positionY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+=0.03&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;easing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EaseInEaseOut&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="na"&gt;moveDown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;positionY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-=0.03&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;easing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EaseInEaseOut&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="na"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+=180&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;easing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EaseInEaseOut&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;flipDisk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;moveUp&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="s1"&gt;moveDown&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flip&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;As you see, we declare 3 distinct animations, and compose them using the fourth one, &lt;code&gt;flipDisk&lt;/code&gt;. &lt;code&gt;moveUp&lt;/code&gt; and &lt;code&gt;moveDown&lt;/code&gt; are in the same array because they are executed one after the other. &lt;code&gt;flip&lt;/code&gt; runs in parallel to these two transformations.&lt;/p&gt;

&lt;p&gt;Secondly, we just need to use this registered animation in our &lt;code&gt;Disk&lt;/code&gt; component using the &lt;code&gt;animation&lt;/code&gt; prop, as follows:&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="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="nx"&gt;renderCellDisk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flipping&lt;/span&gt; &lt;span class="p"&gt;}&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="nx"&gt;state&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Disk&lt;/span&gt;
                &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&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="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&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="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mf"&gt;0.03&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.03&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
                &lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;TYPE_WHITE&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;180&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="mi"&gt;0&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;opacity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;TYPE_EMPTY&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mf"&gt;0.15&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="nx"&gt;onClick&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="nf"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
                &lt;span class="nx"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flipDisk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;flipping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hasSamePosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                    &lt;span class="na"&gt;onFinish&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="nf"&gt;handleEndFlip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;}}&lt;/span&gt;
            &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;animation&lt;/code&gt; prop accepts an object of the following structure:&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;            &lt;span class="c1"&gt;// name of the animation&lt;/span&gt;
    &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;           &lt;span class="c1"&gt;// number of ms before animation starts&lt;/span&gt;
    &lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;              &lt;span class="c1"&gt;// animation can loop?&lt;/span&gt;
    &lt;span class="nx"&gt;onFinish&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;          &lt;span class="c1"&gt;// end callback of the animation&lt;/span&gt;
    &lt;span class="nx"&gt;onStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;           &lt;span class="c1"&gt;// start callback of the animation&lt;/span&gt;
    &lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;               &lt;span class="c1"&gt;// animation is active or not?&lt;/span&gt;
    &lt;span class="nx"&gt;interruptible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;     &lt;span class="c1"&gt;// can we change animation when running?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our case, we've just used &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, and &lt;code&gt;onFinish&lt;/code&gt; attributes to define which disk is currently flipping, and remove it from the flipping list when the animation ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using ViroReact for building an Augmented Reality project was a great choice for many reasons. Whereas it was my first experience in this domain, &lt;strong&gt;I haven't faced any difficulties at any time&lt;/strong&gt;. Quite the contrary, Viro has helped me to explore this world with confidence.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;developer experience is rich&lt;/strong&gt; as it offers ReactJS binding, hot-reload and unambiguous documentation. Nevertheless, &lt;strong&gt;I don't recommend to use it for complex / performance-based applications&lt;/strong&gt; because of the React-Native javascript thread which can lead to event congestion and lags. So, in case performance matters, I'd recommend full-native solutions instead.&lt;/p&gt;

&lt;p&gt;By the way, Google is constantly adding augmented reality features within its applications, like &lt;a href="https://mashable.com/article/google-maps-ar-augmented-reality-walking-navigation/?europe=true#_pEnJI2JUaqE" rel="noopener noreferrer"&gt;on Google Map&lt;/a&gt;. &lt;strong&gt;Augmented Reality has never been so expanding&lt;/strong&gt;. So, don't miss it.&lt;/p&gt;

&lt;p&gt;Many other features remain to be explored, such as &lt;a href="https://docs.viromedia.com/docs/animation#section-skeletal-animation" rel="noopener noreferrer"&gt;Skeletal animations&lt;/a&gt;, &lt;a href="https://docs.viromedia.com/docs/particle-effects" rel="noopener noreferrer"&gt;particles effects&lt;/a&gt;, &lt;a href="https://docs.viromedia.com/docs/physics" rel="noopener noreferrer"&gt;physics&lt;/a&gt;, &lt;a href="https://docs.viromedia.com/docs/video" rel="noopener noreferrer"&gt;video&lt;/a&gt; and &lt;a href="https://docs.viromedia.com/docs/audio" rel="noopener noreferrer"&gt;sounds&lt;/a&gt;. Don't be shy, &lt;strong&gt;share your experiences though comments&lt;/strong&gt; ;)&lt;/p&gt;

&lt;p&gt;You can find the final code on GitHub, in &lt;a href="https://github.com/marmelab/virothello" rel="noopener noreferrer"&gt;the marmelab/virothello repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>mobile</category>
      <category>3d</category>
      <category>react</category>
    </item>
    <item>
      <title>Get Rid Of Toxic Bugs On Your Apps With Detox!</title>
      <dc:creator>Demangeon Julien</dc:creator>
      <pubDate>Tue, 05 Jun 2018 19:56:03 +0000</pubDate>
      <link>https://forem.com/juliendemangeon/get-rid-of-toxic-bugs-on-your-apps-with-detox-l6j</link>
      <guid>https://forem.com/juliendemangeon/get-rid-of-toxic-bugs-on-your-apps-with-detox-l6j</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: This post was originally posted on &lt;a href="https://marmelab.com/blog/2018/06/05/get-rid-of-toxic-bugs-on-your-apps-with-detox.html"&gt;marmelab.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;During the &lt;a href="https://marmelab.com/blog/2017/05/24/minutes-of-react-europe-2017.html"&gt;React Europe Conference&lt;/a&gt; last year, I discovered a promising E2E testing framework for mobile apps called &lt;a href="https://github.com/wix/detox"&gt;Detox&lt;/a&gt;. Since then, I've kept in mind the will to give it a try. Recently, I developed an &lt;a href="https://github.com/marmelab/beerexplorer-detox"&gt;example app&lt;/a&gt; just for that purpose. It allowed me to see what's under the hood of Detox. Here is my feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are End-to-End Tests?
&lt;/h2&gt;

&lt;p&gt;In software development, we list &lt;strong&gt;3 distinct kinds of automated tests&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit Tests&lt;/strong&gt;: As their name suggest, they test functions individually, &lt;strong&gt;in isolation from the rest&lt;/strong&gt; of the codebase. They're used to prevent unexpected code changes and to ensure that functions do what they are supposed to do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Tests&lt;/strong&gt; (or &lt;strong&gt;Service Tests&lt;/strong&gt;) are responsible for the proper connection between code parts and APIs. They test the application components altogether from a technical perspective.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-To-End Tests (E2E)&lt;/strong&gt;: They allow to test the application as a whole, &lt;strong&gt;in its execution environment&lt;/strong&gt;, as a human could do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to &lt;a href="https://martinfowler.com"&gt;Martin Fowler&lt;/a&gt;, all these kinds of tests can be classified into a &lt;a href="https://martinfowler.com/bliki/TestPyramid.html"&gt;Test Pyramid&lt;/a&gt; from the slowest / most expensive to the fastest / least expensive. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iHr4tMss--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/test_pyramid.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iHr4tMss--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/test_pyramid.png" alt="Test Pyramid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the bottom of the pyramid, &lt;strong&gt;Unit-Tests&lt;/strong&gt; must be the most common tests. Utopically, each function must be tested. Some integration tests and a bit less E2E tests are needed to ensure that the entire stack is working well.&lt;/p&gt;

&lt;p&gt;Whereas E2E tests are very important, some people sometimes go too far with an excessive E2E test coverage. Another diagram called &lt;a href="https://medium.com/@fistsOfReason/testing-is-good-pyramids-are-bad-ice-cream-cones-are-the-worst-ad94b9b2f05f"&gt;Ice-Cream Cone&lt;/a&gt; represents this anti-pattern as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bCmYtscp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/icecream.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bCmYtscp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/icecream.png" alt="Ice Cream Cone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But everyone agrees that writing and debugging E2E tests is a &lt;strong&gt;tedious task&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Detox
&lt;/h2&gt;

&lt;p&gt;Detox was first released in 2016 by &lt;a href="https://twitter.com/koltal"&gt;Tal Kol&lt;/a&gt; and &lt;a href="https://twitter.com/rotemmiz"&gt;Rotem Mizrachi-Meidan&lt;/a&gt;, 2 engineers working at &lt;a href="https://wix.com/"&gt;Wix&lt;/a&gt;. Wix is a cloud-based platform which allows non-technical users to create their own website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pWKXfkla--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/wixengineering.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pWKXfkla--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/wixengineering.png" alt="Wix Engineering"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Detox defines itself as &lt;strong&gt;a Gray Box End-To-End testing automation framework for mobile apps&lt;/strong&gt;. That means that it brings the same context aware test capabilities we're already using in browser apps through &lt;a href="https://www.seleniumhq.org/"&gt;Selenium&lt;/a&gt;. This way, Detox allows to break off from manual &lt;a href="https://en.wikipedia.org/wiki/Quality_assurance"&gt;Quality Insurance&lt;/a&gt; test processes, which are time-consuming and incomplete.&lt;/p&gt;

&lt;p&gt;Contrary to &lt;a href="https://github.com/appium/appium"&gt;Appium&lt;/a&gt;, its the main competitor, Detox uses JavaScript both on the server side and on the client side. Despite this strong requirement, Detox allows using Jest, Mocha, AVA, or any other JavaScript test runner you like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gray Box Testing vs Black Box Testing
&lt;/h2&gt;

&lt;p&gt;As a Gray Box test framework, Detox shares both White and Black Box capabilities. Let's see together what it means.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Black-box_testing"&gt;Black Box test frameworks&lt;/a&gt; allows to take over an execution context (a browser, a software, mobile apps, etc) and send control commands to them.&lt;/p&gt;

&lt;p&gt;This test methodology does not allow to access to the internal state of the application though. That's why it's necessary to manually check the existence of elements to ensure test the state after a transition.&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;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`http://localhost/#/login`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;until&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elementLocated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#loginform&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;Gray Box frameworks are extending &lt;a href="https://en.wikipedia.org/wiki/White-box_testing"&gt;White Box test frameworks&lt;/a&gt; capabilities. This way, they do the same thing as Black Box frameworks, except that they access the internal state of the execution context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LPQZCTFh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/blackgreywhitebox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LPQZCTFh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/blackgreywhitebox.png" alt="Black Box vs Grey Box"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Accessing the internal state of the execution context permits to know when the application is idle, and to synchronize operations adequately. That's why Detox is more powerful than most classic E2E test frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Less Flakiness
&lt;/h2&gt;

&lt;p&gt;If you've already used an E2E test framework before, you've certainly encountered some strange, random and unexpected errors. These errors are therefore called "flakiness errors". As you encounter them, you feel like our good old Harold and it's not very funny.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xf6QxutK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/harold.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xf6QxutK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/harold.jpg" alt="E2E Flakiness is not so funny"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To mitigate this behavior, we usually add some &lt;code&gt;sleep&lt;/code&gt; (or &lt;code&gt;timeouts&lt;/code&gt;) calls into the test suite, to ensure that the application is in an idle state before resuming the test process. Even though this "hack" works, it results in slower tests, without really solving the problem because on a slow test system, the sleep delay can sometimes be not enough.&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;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findElement&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;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loginButton&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&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;Thankfully, as a Grey Box Framework, Detox is able to &lt;strong&gt;access the application state&lt;/strong&gt; and then to determine if the application is in an idle state or not. To achieve this &lt;code&gt;idle&lt;/code&gt; synchronization task, Detox rely on 2 natives Grey Box drivers called &lt;a href="https://github.com/google/EarlGrey"&gt;EarlGrey&lt;/a&gt; (for iOS) and &lt;a href="https://developer.android.com/training/testing/ui-testing/espresso-testing.html"&gt;Espresso&lt;/a&gt; (for Android).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T9mOacOg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/earlgrey_espresso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T9mOacOg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/detox/earlgrey_espresso.png" alt="Detox Inner Working"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because &lt;strong&gt;Detox runs in JavaScript&lt;/strong&gt;, it communicates with drivers using a JSON based protocol to invoke control commands on devices.&lt;/p&gt;

&lt;p&gt;A special synchronization mechanism has also be developed for React-Native apps, so Detox supports React Native&lt;/p&gt;

&lt;h2&gt;
  
  
  A Concrete Use Case
&lt;/h2&gt;

&lt;p&gt;As already said in the introduction, I've developed a dedicated application to give Detox a try. Since I'm a beer lover, I couldn't resist creating a simple beer registry app called &lt;a href="https://github.com/marmelab/beerexplorer-detox"&gt;beerexplorer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rV3Ggo6x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://marmelab.com/images/blog/detox/detox.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rV3Ggo6x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://marmelab.com/images/blog/detox/detox.gif" alt="Detox Example App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most blog posts about Detox build applications with &lt;a href="https://facebook.github.io/react-native/"&gt;React-Native&lt;/a&gt;, this one is no exception. Still, it's important to know that Detox is fully cross-platform and supports both iOS and Android.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detox Setup
&lt;/h2&gt;

&lt;p&gt;I've tried to setup Detox to run it on my own Android phone. Despite all my efforts, I've not been able to make it work. So I went back to an iOS emulator.&lt;/p&gt;

&lt;p&gt;The Detox setup is relatively simple. It consists of installing the &lt;a href="https://www.npmjs.com/package/detox"&gt;detox&lt;/a&gt; npm package, then calling 2 commands: &lt;code&gt;detox build&lt;/code&gt; and &lt;code&gt;detox test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, Detox uses an existing configuration defined in &lt;code&gt;package.json&lt;/code&gt; to determine which test runner and configuration it should use. All available devices configurations are stored under the "detox.configurations" key. Android and iOS device configurations can be mixed.&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="cm"&gt;/* package.json */&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&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;beerexplorer&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;detox&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test-runner&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;jest&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;runner-config&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;e2e/config.json&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;configurations&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ios.sim.debug&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;binaryPath&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;ios/build/Build/Products/Debug-iphonesimulator/beerexplorer.app&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;build&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;xcodebuild -project ios/beerexplorer.xcodeproj -scheme beerexplorer -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build&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;type&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;ios.simulator&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;name&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;iPhone 7&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I call the &lt;code&gt;detox test&lt;/code&gt; command, Detox looks in the &lt;code&gt;runner-config&lt;/code&gt; configuration file for the &lt;code&gt;setupTestFrameworkScriptFile&lt;/code&gt; to execute before running tests. I've called this file &lt;code&gt;init.js&lt;/code&gt;.&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="c1"&gt;// e2e/config.json&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;setupTestFrameworkScriptFile&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;./init.js&lt;/span&gt;&lt;span class="dl"&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 is the test init file:&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="c1"&gt;// e2e/init.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;detox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;detox&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&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;await&lt;/span&gt; &lt;span class="nx"&gt;detox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&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;await&lt;/span&gt; &lt;span class="nx"&gt;detox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cleanup&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;Tests can either run on a local emulator, a hidden emulator, or even on a distant CI like &lt;a href="https://travis-ci.org/"&gt;Travis&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Detox Usage
&lt;/h2&gt;

&lt;p&gt;Out of the box, Detox provides a small but powerful set of tools, that allows to control the device, select elements in the UI, and execute actions on these elements.&lt;/p&gt;

&lt;p&gt;Detox tools are asynchronous. Therefore you have to use Promises, or, like in my code below, ES6 async/await.&lt;/p&gt;

&lt;h3&gt;
  
  
  Device
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;device&lt;/code&gt; object allows to control the device directly, without relying on the tested application. Here are some examples of usages from &lt;a href="https://github.com/wix/detox/blob/master/docs/APIRef.DeviceObjectAPI.md"&gt;the documentation&lt;/a&gt;.&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="c1"&gt;// Launch app with specific permissions&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launchApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;calendar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YES&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Simulate "home" button click &lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendToHome&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Simulate geolocation&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;32.0853&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;34.7818&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some &lt;code&gt;device&lt;/code&gt; functions are specific to a given platform, such as &lt;code&gt;device.reloadReactNative&lt;/code&gt; for React-Native and &lt;code&gt;device.shake&lt;/code&gt; for iOS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Selectors / Matchers
&lt;/h3&gt;

&lt;p&gt;As with other test frameworks, Detox gives the possibility to match UI elements in different ways.&lt;/p&gt;

&lt;p&gt;The easiest (and recommended) way to match elements is to use ids. Sadly, this technique is only available on React-Native.&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="c1"&gt;// id declaration&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Touchable&lt;/span&gt; &lt;span class="nx"&gt;testID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BeerListItem&lt;/span&gt;&lt;span class="dl"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Touchable&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// element selection&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BeerListItem&lt;/span&gt;&lt;span class="dl"&gt;'&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 also possible to match elements with other methods like &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;label&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt; or &lt;code&gt;traits&lt;/code&gt;. More informations on the corresponding &lt;a href="https://github.com/wix/detox/blob/master/docs/APIRef.Matchers.md#byidid"&gt;matchers documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actions And Expectation
&lt;/h3&gt;

&lt;p&gt;Once selected, it's possible to &lt;a href="https://github.com/wix/detox/blob/master/docs/APIRef.ActionsOnElement.md"&gt;trigger actions&lt;/a&gt; and &lt;a href="https://github.com/wix/detox/blob/master/docs/APIRef.Expect.md"&gt;execute assertions&lt;/a&gt; on elements. As an example, here is a test suite from the homepage of the "beerexplorer" project.&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;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&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;await&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reloadReactNative&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should have a list of beers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&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;await&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BeerList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nx"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should go to detail on beer touch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&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;await&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BeerListItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;atIndex&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;tap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DetailBackground&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nx"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should show all beers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&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;await&lt;/span&gt; &lt;span class="nx"&gt;waitFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lindemans Kriek&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nx"&gt;toExist&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;whileElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BeerList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;scroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lindemans Kriek&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nx"&gt;toExist&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;As you can see, tests are very expressive and easy to read. There's no need to add  more test about the existence of an element between transitions, thanks to the idle state synchronization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Although satisfied by Detox at the end, I'm still disappointed by the difficulty of setting up an E2E test suite on Android. Because of my poor experience on mobile application tests, I don't pretend to give you the more accurate opinion. But I still think this framework (and its documentation) still to be improved for Android.&lt;/p&gt;

&lt;p&gt;Apart from that, the developer experience with Detox is very pleasant. I never found myself in difficulty when writing tests. Also, live preview in the emulator is very empowering.&lt;/p&gt;

&lt;p&gt;Nevertheless, If you're testing your application on iOS only, feel free to give it a try. You won't take many risks, except to be greatly satisfied by the clarity and the stability of the tests.&lt;/p&gt;

&lt;p&gt;If you want to read more on the subject by other authors, I recommend the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html"&gt;The Practical Test Pyramid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hackernoon.com/detox-gray-box-End-To-End-testing-framework-for-mobile-apps-196ccd9564ce"&gt;Detox: Gray Box End to End Testing Framework for Mobile Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pillow.codes/testing-in-react-native-jest-detox-d7b3b79a166a"&gt;Testing in React-Native - Jest &amp;amp; Detox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reqtest.com/testing-blog/grey-box-testing/"&gt;Gray Box vs Black Box&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>e2e</category>
      <category>tdd</category>
      <category>javascript</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Enjoy Painless Typing With ReasonML!</title>
      <dc:creator>Demangeon Julien</dc:creator>
      <pubDate>Mon, 09 Apr 2018 15:17:03 +0000</pubDate>
      <link>https://forem.com/juliendemangeon/enjoy-painless-typing-with-reasonml-298j</link>
      <guid>https://forem.com/juliendemangeon/enjoy-painless-typing-with-reasonml-298j</guid>
      <description>&lt;p&gt;Note: This post was originally posted on &lt;a href="https://marmelab.com/blog/2018/04/09/enjoy-painless-typing-with-reason.html"&gt;marmelab.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For one of our regular hackdays at Marmelab, I wanted to learn a language I've kept in the back of my head since I heard of it at &lt;a href="https://marmelab.com/blog/2017/05/24/minutes-of-react-europe-2017.html"&gt;React Europe 2017&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This language, which is called &lt;a href="https://reasonml.github.io/"&gt;Reason&lt;/a&gt; (shortcut for ReasonML), is in fact a syntax and a toolchain overlay for &lt;a href="https://ocaml.org/index.fr.html"&gt;OCaml&lt;/a&gt;, a language that is known for its robustness, its strong static typing, and its ubiquitous functional paradigm approach.&lt;/p&gt;

&lt;p&gt;According to the Reason website, its main goal is to provide a friendly syntax / environment to JavaScript developers looking for performance, consistency, and type safety.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reason can almost be considered as a solidly statically typed, faster and simpler cousin of JavaScript, minus the historical crufts, plus the features of ES2030 you can use today, and with access to both the JS and the OCaml ecosystem!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By the way, I think that this simple example should suffice to illustrate its power, and whet your appetite for further reading.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type schoolPerson = Teacher | Director | Student(string);

let greeting = (stranger) =&amp;gt;
  switch (stranger) {
  | Teacher =&amp;gt; "Hey professor!"
  | Director =&amp;gt; "Hello director."
  | Student("Richard") =&amp;gt; "Still here Ricky?"
  | Student(anyOtherName) =&amp;gt; "Hey, " ++ anyOtherName ++ "."
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To explore this language in practice, I've coded a &lt;a href="https://marmelab.com/reversi-reason/"&gt;reversi game&lt;/a&gt; running in the browser. I'll use it to give an overview of Reason capabilities, and explain why I think that it opens a whole new horizon on the JavaScript ecosystem.&lt;/p&gt;

&lt;p&gt;But before going into technical details, let me introduce Reason from an historical and practical point of view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reason Is OCaml Made Easier
&lt;/h2&gt;

&lt;p&gt;As I previously said, Reason is based on OCaml. This way, it benefits from all the OCaml strengths, like polymorphic / infered typing, pattern matching, garbage collector, sophisticated module system, and so on.&lt;/p&gt;

&lt;p&gt;OCaml is the main implementation of Caml. Caml is a safe, reliable, and expressive programming language created in 1985 by a French research institute in Computer Science called &lt;a href="https://www.inria.fr/"&gt;INRIA&lt;/a&gt;. But, what's wrong with OCaml? Why not use it directly? Indeed, the question deserves to be asked. &lt;/p&gt;

&lt;p&gt;OCaml is based on complex principles, and uses an awkward syntax. Here is an example of OCaml code, which adds values recursively from a list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;rec&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;xs'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="n"&gt;xs'&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;

&lt;span class="c"&gt;(* sum [1;2;3;4;5] =&amp;gt; 15 *)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: As a matter of fact, it's not really necessary to use recursive functions for this kind of purpose, because the &lt;a href="https://caml.inria.fr/pub/docs/manual-ocaml/libref/index.html"&gt;Core Standard Library&lt;/a&gt; has many built-in functions covering most needs.&lt;/p&gt;

&lt;p&gt;The complexity of OCaml explains why OCaml it confined to academic projects for a long time.&lt;/p&gt;

&lt;p&gt;Until a few years ago, &lt;a href="https://twitter.com/jordwalke"&gt;Jordan Walke&lt;/a&gt;, who works at Facebook, created the famous &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; library &lt;a href="https://www.reactiflux.com/transcripts/jordan-walke/"&gt;using SML&lt;/a&gt; (a derived OCaml language), and created ReasonML. Shortly after, he made the decision to migrate ReactJS to plain JavaScript for a wider adoption.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d5NRHyeS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/react.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d5NRHyeS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/react.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  BuckleScript Brings OCaml to the Web
&lt;/h2&gt;

&lt;p&gt;In fact, Reason does not directly compile to JavaScript. For that purpose, it maintains a strong dependency to another library called &lt;a href="https://bucklescript.github.io/"&gt;BuckleScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;BuckleScript defines itself as a "sister" project of Reason. In fact, &lt;strong&gt;both share the same community&lt;/strong&gt; (they have the same &lt;a href="https://discord.gg/reasonml"&gt;Discord&lt;/a&gt;), and the same purpose: bringing OCaml's capabilities to the browser. Moreover, the documentation between the two projects is very complementary.&lt;/p&gt;

&lt;p&gt;Here is a little schema of the compilation workflow from Reason to JavaScript. Under the hood, reason files (&lt;code&gt;.re&lt;/code&gt;) are transformed to plain OCaml &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;AST&lt;/a&gt; through an &lt;a href="https://github.com/reasonml/reason-cli"&gt;OCaml preprocessor for Reason&lt;/a&gt;. This OCaml AST is then processed by the &lt;a href="https://github.com/BuckleScript/bucklescript"&gt;BuckleScript compiler&lt;/a&gt; called &lt;code&gt;bsc&lt;/code&gt;, which produces plain JS Files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PxtHLvAg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/reasontojs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PxtHLvAg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/reasontojs.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The compilation process is a bit more complex than explained here. To understand it in more details, I suggest you take a look at &lt;a href="https://github.com/chenglou/intro-to-reason-compilation"&gt;this excellent repository&lt;/a&gt; owned by &lt;a href="https://github.com/chenglou"&gt;chenglou&lt;/a&gt;, the speaker who introduced me to Reason at &lt;a href="https://www.react-europe.org/"&gt;React Europe&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not TypeScript Or Flow?
&lt;/h2&gt;

&lt;p&gt;JavaScript is an untyped language, but large projects often require additional programming safety throught types. That's why many tools have been created on top of JavaScript to fill this gap. Among them, the most popular are probably &lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt; and &lt;a href="https://flow.org/"&gt;Flow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OItHXieg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/tsvsflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OItHXieg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/tsvsflow.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript&lt;/strong&gt; is an open-source programming language developed by Microsoft. It acts as a strict &lt;strong&gt;syntaxic superset of JavaScript&lt;/strong&gt; that adds static typing to it. It is also considered as first class language for &lt;a href="https://angular.io/"&gt;Angular&lt;/a&gt; development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flow&lt;/strong&gt; is an open-source static type checker for JavaScript developed by Facebook. It acts as a &lt;strong&gt;specific syntax (kind of annotations) which adds types&lt;/strong&gt; over an existing code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How does Reason compare to those two? In fact, Reason is not a new syntax for JavaScript, or a simple typing overlay. &lt;strong&gt;Reason is a complete language&lt;/strong&gt;. It introduces new control structures that you'll never find in TypeScript or Flow. Reason is built with typing at its core, and just &lt;em&gt;compiles&lt;/em&gt; to JavaScript. &lt;/p&gt;

&lt;p&gt;If you need strong types, I think that the only valid reason to use TypeScript or Flow is to port an existing JavaScript codebase. If you need strong types without an existing codebase, prefer a real typed language like Reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reason Can Compile To Other Platforms
&lt;/h2&gt;

&lt;p&gt;Reason uses OCaml as an intermediate language, and it's BuckleScript's job to translate that OCaml code into JavaScript. &lt;/p&gt;

&lt;p&gt;But there are other toolchains for running OCaml code in other platforms. For instance, OCaml can be compiled to native code, thanks to the &lt;a href="http://caml.inria.fr/pub/docs/manual-ocaml-4.00/manual025.html"&gt;ocamlopt compiler&lt;/a&gt;. In this respect, there are some successful &lt;a href="https://jaredforsyth.com/posts/making-a-cross-platform-mobile-game-in-reason-ocaml/"&gt;cross-platform projects&lt;/a&gt; written in Reason that are compiled to native, browser, Android and iOS.&lt;/p&gt;

&lt;p&gt;From my point of view, this unexpected possibility opens up a whole new development horizon. Above all, this opportunity allows to move away from the "all JavaScript" trend, which I think is dangerous. We should never lock ourselves with a single technology.&lt;/p&gt;

&lt;p&gt;OK, enough with the introduction of the language. Let's see some code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Bindings And Expressions
&lt;/h2&gt;

&lt;p&gt;Unlike JavaScript, there's only &lt;strong&gt;one way to declare / assign variables&lt;/strong&gt; in Reason. Indeed, because everything is immutable by nature, the only assignation keyword is &lt;code&gt;let&lt;/code&gt;. Therefore, the assignment action is called a "let binding".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let message = "hello world";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Immutability" means that a value can't change over time - it doesn't means that you can't create a new binding with the same name to replace an existing one. That's why &lt;code&gt;let&lt;/code&gt; is called a &lt;em&gt;binding&lt;/em&gt; and not an &lt;em&gt;assignment&lt;/em&gt;. &lt;strong&gt;A binding gives a name to a value&lt;/strong&gt;, it doesn't change the value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let message = "hello";
print_endline(message); /* Prints "hello" */
/* totally legal */
let message = "world";
print_endline(message); /* Prints "world" */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To effectively change an already bound "value", you must use a &lt;code&gt;ref&lt;/code&gt;. This topic is discussed later in the "An Imperative Way Out" section.&lt;/p&gt;

&lt;p&gt;Bindings can also be scoped into a "block" scope (&lt;code&gt;{}&lt;/code&gt;). In that case, the last expression of the block is implicitly returned. There's no explicit &lt;code&gt;return&lt;/code&gt; in Reason. As in JavaScript, &lt;strong&gt;bindings are only available in theirs respective scopes.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let message = {
    let part1 = "hello";
    let part2 = "world";
    part1 ++ " " ++ part2
};

/* part1 &amp;amp; part2 not availables here */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic Types
&lt;/h2&gt;

&lt;p&gt;Like most other programming languages, Reason supports all basic types such as booleans, numbers, strings and chars. Since Reason is a statically typed language, &lt;strong&gt;types can be manually defined, or can be infered at compile time&lt;/strong&gt; from the program AST.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let score = 10; /* type is infered */
let score: int = 10; /* type is manually defined */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Reason, just like with Python, there's no implicit type casting. &lt;strong&gt;Developers must use explicit type conversion functions&lt;/strong&gt; (like &lt;code&gt;string_of_int&lt;/code&gt; or &lt;code&gt;string_of_bool&lt;/code&gt;) to switch from one type to another. These functions are part of &lt;a href="https://reasonml.github.io/api/Pervasives.html"&gt;Pervasives&lt;/a&gt;, which is the initially opened module at the beginning of each compilation. It provides all the basic operations over the built-in types. &lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Types
&lt;/h2&gt;

&lt;p&gt;As in OCaml, it is also possible to create your own types with Reason. In this respect, here are 2 different kinds of types from the reversi "Cell" module. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;color&lt;/code&gt; type is called a &lt;a href="https://reasonml.github.io/docs/en/variant.html"&gt;Variant&lt;/a&gt;. A Variant is a kind of &lt;strong&gt;group of possible constants&lt;/strong&gt;. These constants, which are called "constructors" or "tags", are separated by "|" bars. Variants are, from my point of view, the key feature of Reason. They allow us to carry values (as arguments), and enable pattern matching.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* cell.re */
type color = White | Black;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;cell&lt;/code&gt; type is called a &lt;a href="https://reasonml.github.io/docs/en/record.html"&gt;Record&lt;/a&gt;. In other languages, it's usually called a &lt;code&gt;struct&lt;/code&gt;. Objects created based on a Record are immutable, fixed, and very fast. Records needs a strong type definition. That's why each field is explicitly typed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* cell.re */
type cell = {
    x: int,
    y: int,
    color: option(color),
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see for the &lt;code&gt;color&lt;/code&gt; field of the &lt;code&gt;cell&lt;/code&gt; type, a type can contains another type. It allows to create &lt;a href="http://2ality.com/2017/12/variants-reasonml.html#self-recursive-data-structures-via-variants"&gt;complex recursives data structures&lt;/a&gt; (like trees) quickly and easily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type intTree =
  | Empty
  | Node(int, intTree, intTree);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Parameterized And Special Types
&lt;/h2&gt;

&lt;p&gt;In one of the previous example, you may have asked yourself about the &lt;code&gt;option(color)&lt;/code&gt; function call. In fact, &lt;code&gt;option&lt;/code&gt; is not a function, it's a parameterized Variant, which is directly exposed by the &lt;a href="https://reasonml.github.io/api/index.html"&gt;standard library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since there's no &lt;code&gt;null&lt;/code&gt; values in Reason (and therefore no null pointer exceptions), &lt;code&gt;option&lt;/code&gt; allows to mimic the absence of value for anything. It can either be &lt;code&gt;None&lt;/code&gt; (&lt;code&gt;null&lt;/code&gt; equivalent) or &lt;code&gt;Some(value)&lt;/code&gt;. It can be compared to the famous &lt;a href="https://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe"&gt;Maybe&lt;/a&gt; Monad.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type option('a) =
    | None
    | Some('a);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does the &lt;code&gt;'a&lt;/code&gt; mean? In Reason, &lt;strong&gt;every type can accept parameters&lt;/strong&gt;. The unique quote means "a value of any type". This is very useful to create generic type structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lists And Arrays
&lt;/h2&gt;

&lt;p&gt;In Reason, one of the most used Type is &lt;a href="https://reasonml.github.io/docs/en/list-and-array.html#list"&gt;List&lt;/a&gt;. As its name suggests, a List is a collection of elements that are of the same type.&lt;/p&gt;

&lt;p&gt;Lists are represented as &lt;a href="https://en.wikipedia.org/wiki/Linked_list"&gt;linked lists&lt;/a&gt; underneath (even &lt;a href="https://reasonml.github.io/en/try.html?reason=DYUwLgBAJglgTiAxmGB7AdgZwgXggbQCgISIAKABgBoIBGAShogHoAqCAZRNeeNMpoBaBjTYQAct16lytGhUYkxAUSl8SZOXUUt2HVT3W6IAOjMRDAXQDcQA"&gt;in the transpiled JavaScript!&lt;/a&gt;). Because of that, they're &lt;strong&gt;dynamically sized and immutable&lt;/strong&gt; by nature, and they allow to add or remove elements very quickly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* board.re */
let directions = [
    (0, 1),  /* S  */
    (0, -1), /* N  */
    (1, 0),  /* E  */
    (1, 1),  /* SE */
    /* ... */
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lists are very fast for updates, but very slow for access. Read operation speed is proportional to the size of the List (&lt;strong&gt;O(n) complexity&lt;/strong&gt;). That's why Reason also provide an &lt;a href="https://reasonml.github.io/docs/en/list-and-array.html#array"&gt;Array&lt;/a&gt; Type.&lt;/p&gt;

&lt;p&gt;Contrary to Lists, &lt;strong&gt;Arrays are fixed-size collections&lt;/strong&gt;, which are mutable and fast for read operations (&lt;strong&gt;O(1) complexity&lt;/strong&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let myArray = [|"hello", "world", "how are you"|];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In brief, Lists are better for dynamic and medium sized collections that do not require fast access. Array are better for fixed and large sized collections that require fast access.&lt;/p&gt;

&lt;p&gt;You'll find more information about Lists and Arrays in the &lt;a href="http://reasonmlhub.com/exploring-reasonml/ch_arrays.html#lists-vs.arrays"&gt;Exploring ReasonML online book&lt;/a&gt;, which is very complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern Matching And Destructuring
&lt;/h2&gt;

&lt;p&gt;I've introduced Types and Variants so that I can talk about one of the most interesting feature of Reason: pattern matching.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_nGrjtdI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/matching.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_nGrjtdI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/matching.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In brief, pattern matching allows both to check and to extract data from structures. It's a kind of mix between &lt;a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/RegExp/test"&gt;RegExp.test&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/RegExp/exec"&gt;RegExp.exec&lt;/a&gt; from JavaScript, but for all types of data, and anywhere (bindings and function args).&lt;/p&gt;

&lt;p&gt;In the following example, I use the &lt;code&gt;switch&lt;/code&gt; expression to test the &lt;code&gt;color&lt;/code&gt; value against multiple patterns. When a pattern matches, the value just after the &lt;code&gt;=&amp;gt;&lt;/code&gt; is then returned and assigned to "identifier".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* cell.re */
let identifier = switch (color) {
    | Some(Black) =&amp;gt; "black"
    | Some(White) =&amp;gt; "white"
    | None =&amp;gt; ""
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example is of course the simplest one. You can also match one part of the value, use it afterwards, and even match on an exception!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* board.re */
let getCell = (x, y, cells) =&amp;gt;
    switch (List.find(cell =&amp;gt; cell.x == x &amp;amp;&amp;amp; cell.y == y, cells)) {
        | ({ color }) =&amp;gt; color /* color is extracted from the cell record */
        | exception Not_found =&amp;gt; None
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Naturally, matching also comes with &lt;a href="https://reasonml.github.io/docs/en/destructuring.html"&gt;destructuring&lt;/a&gt;. That's why it's even possible to extract parts of data structures easily, even from functions args!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* board.re */
let init = (width, height) =&amp;gt; {
    let (mw, mh) = (width / 2, height / 2); /* tuple destructuring */
    /* ... */
};

let isOutOfBound = ({ width, height }, (x, y)) =&amp;gt; /* function args destructuring */
    x &amp;lt; 0 || y &amp;lt; 0 || x &amp;gt; (width - 1) || y &amp;gt; (height - 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a lot of things to say about pattern matching, far too much to cover everything here. I advise you to take a look at &lt;a href="http://2ality.com/2017/12/pattern-matching-reasonml.html"&gt;this article&lt;/a&gt;, which is very comprehensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions
&lt;/h2&gt;

&lt;p&gt;As you may have understood, Reason is fully focused on the functional paradigm. In this regard, it highlights a lot of concepts like &lt;strong&gt;higher-order functions&lt;/strong&gt;, &lt;strong&gt;recursivity&lt;/strong&gt;, &lt;strong&gt;partial application&lt;/strong&gt; (via currying), and so on. The Reason function syntax is very close to the &lt;a href="http://exploringjs.com/es6/index.html"&gt;ES6&lt;/a&gt; one. It uses the famous "arrow / body" pair.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let add = (first, second) =&amp;gt; first + second;
add(1,2); /* 3 */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Reason, every function takes at least one argument, even if you don't declare / notice it! When you declare a function without any argument, under the hood, Reason adds a &lt;a href="https://reasonml.github.io/docs/en/function.html#no-argument"&gt;unit&lt;/a&gt; argument to it. In the example below, the pair of brackets &lt;code&gt;()&lt;/code&gt; after &lt;code&gt;locationReload&lt;/code&gt; is a &lt;code&gt;unit&lt;/code&gt;. So, in reality, you effectively call &lt;code&gt;locationReload&lt;/code&gt; with an argument without even realizing it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let locationReload = () =&amp;gt; {
  /* ... */
};
locationReload();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may be disappointed by this "unit", but you must known that it's a normal value. Above all, you must not confuse "unit" with an "option". Whereas an "option" represents "a value or an empty value", a "unit" represents an absence of value (think about &lt;code&gt;undefined&lt;/code&gt; or "nothing").&lt;/p&gt;

&lt;h2&gt;
  
  
  Currying
&lt;/h2&gt;

&lt;p&gt;Reason offers built-in &lt;a href="https://reasonml.github.io/docs/en/function.html#currying"&gt;currying&lt;/a&gt; of all functions. That means that every function with one or more arguments is transformed into a series of functions with one argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let add = (first, second) =&amp;gt; first + second;
add(1)(2); /* 3 */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may think that it's a waste of resources to create additional function calls, but it's not. OCaml optimizes the output to avoid unnecessary function allocation if partial functions are never called in your program (&lt;a href="https://reasonml.github.io/en/try.html?reason=DYUwLgBAhgJjEF4IAoAeBKRA+FBPTCOqEA1BLgNwBQVA9AFQTAD2zA1tJGABYgTMBXMAAchAQmhwAYgEsAbnxkBnaBAD6SmQDsA5qDUQAZgK0BjMDOZaIpqMGAT6tKqEiwYshYkkxkAVnRqF3AITWIkd08QZABGQKA"&gt;see this example&lt;/a&gt;). This way, OCaml provides out of the box currying without any performance penalty.&lt;/p&gt;

&lt;p&gt;Here is another example of currying, where I take advantage of partial application for my &lt;code&gt;getCountForColor&lt;/code&gt; function from the reversi &lt;code&gt;Board&lt;/code&gt; module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let getCountForColor = (board, color) =&amp;gt;
    board.cells
        |&amp;gt; List.filter(c =&amp;gt; c.color == color)
        |&amp;gt; List.length;

let countForColorFromMyBoard = getCountForColor(myBoard);

let countWhite = countForColorFromMyBoard(Some(White));
let countBlack = countForColorFromMyBoard(Some(Black));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipe operator &lt;code&gt;|&amp;gt;&lt;/code&gt; (also called "reverse-application operator") allows to pass the result of an expression as the first argument of the following expression. Think of the Linux pipe. Given that functions natively allow partial application, it works like a charm!&lt;/p&gt;

&lt;h2&gt;
  
  
  Labeled Arguments
&lt;/h2&gt;

&lt;p&gt;Reason functions also work with named arguments (called &lt;a href="https://reasonml.github.io/docs/en/function.html#labeled-arguments"&gt;labeled arguments&lt;/a&gt;). They are compatible with currying as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let add = (~first, ~second) =&amp;gt; first + second;
let addFirst = add(~second=1);
addFirst(~first=2);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To take full advantage of partial application, it's recommended to place args that change most often at the end of the function, or to use labeled args.&lt;/p&gt;

&lt;p&gt;Labeled arguments can also be optional. For that purpose, you just have to add a question mark as default value, like in the example below. This way, the corresponding argument is automatically provided as an option type, described earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let addOptional = (~first, ~second=?) =&amp;gt; first + switch(second) {
  | None =&amp;gt; 0
  | Some(nb) =&amp;gt; nb
};

let addDefault = (~first, ~second=0) =&amp;gt; first + second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It would be possible to write an entire book about functional paradigms and Reason. A lot of concepts were deliberately bypassed in this section.&lt;/p&gt;

&lt;p&gt;For more informations about functors, recursivity, mutual recursivity, I suggest you to take a look at &lt;a href="http://2ality.com/2017/12/functions-reasonml.html"&gt;2ality - ReasonML Functions&lt;/a&gt; and &lt;a href="http://2ality.com/2018/01/functors-reasonml.html"&gt;2ality - ReasonML Functors&lt;/a&gt;. If you're interested about functional programming, I also advise you to read this &lt;a href="https://marmelab.com/blog/2018/03/14/functional-programming-1-unit-of-code.html"&gt;Marmelab blog post&lt;/a&gt; by my colleague Thiery :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a Reason Project
&lt;/h2&gt;

&lt;p&gt;During my hack day, the first step was to setup the whole Reason stack inside &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;, like we do for all our projects at Marmelab. Using Docker allows us to share projects across various environments with an easy installation.&lt;/p&gt;

&lt;p&gt;To be honest, this setup experience was the worst I had in a long time. It took me about one hour to deal with many permission issues &lt;a href="https://github.com/BuckleScript/bucklescript/issues/2051"&gt;[1]&lt;/a&gt; &lt;a href="https://github.com/BuckleScript/bucklescript/issues/1972"&gt;[2]&lt;/a&gt;. The recommended global install from the &lt;a href="https://reasonml.github.io/docs/en/global-installation.html"&gt;official setup guide&lt;/a&gt; seems to be at the core of the problem.&lt;/p&gt;

&lt;p&gt;Nevertheless, I'm pretty sure that the community will find solutions to make this first step easier. By the way, I'm &lt;a href="https://blog.hasura.io/how-i-deployed-a-reasonml-react-app-with-docker-29dd2ce6de82"&gt;not the only one&lt;/a&gt; who struggled with that. Using the "node:6" docker image seems to do the job for the moment...&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience First!
&lt;/h2&gt;

&lt;p&gt;Once installed, the Reason developer experience is just &lt;em&gt;amazing&lt;/em&gt;. The underlying BuckleScript compiler is quite fast, it builds &lt;a href="https://reasonml.github.io/blog/2017/09/08/messenger-50-reason.html"&gt;mosts projects&lt;/a&gt; in less than 100ms, incrementally.&lt;/p&gt;

&lt;p&gt;Moreover, the error reporter (based on &lt;a href="https://github.com/ocaml/merlin"&gt;Merlin&lt;/a&gt;) is just perfect. It gives a detailed explanation of all possible mistakes thanks to the 100% type coverage of OCaml. Syntax errors are a little bit less clear but still give a good feedback. Here are two little examples to give you a preview of these powers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N8o250DX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/error1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N8o250DX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/error1.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kQ3LwvAJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/error2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kQ3LwvAJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/error2.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  A React App In Seconds!
&lt;/h2&gt;

&lt;p&gt;Because of its history, Reason maintains a strong relationship with React. In this regard, it is quite easy to setup a React project with Reason. I was able to confirm that during my reversi project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/facebook/create-react-app"&gt;create-react-app&lt;/a&gt; allows to focus on functionalities without worrying about toolchain configuration. So I took the decision to use it in association with &lt;a href="https://github.com/reasonml-community/reason-scripts"&gt;reason-scripts&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create-react-app reversi-reason --scripts-version reason-scripts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the install step, I found myself with this familiar folder structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;reversi-reason/
  README.md
  node_modules/
  package.json
  bsconfig.json
  .gitignore
  public/
    favicon.ico
    index.html
  src/
    index.re
    index.css
    app.re
    app.css
    logo.svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only difference with classic JS projects are files with a &lt;code&gt;.re&lt;/code&gt; extension (which are, as you probably guessed, Reason files), and the &lt;code&gt;bsconfig.json&lt;/code&gt; file, which is the BuckleScript configuration.&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reversi-reason"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sources"&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="s2"&gt;"src"&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;"bs-dependencies"&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="s2"&gt;"reason-react"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"bs-jest"&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;"reason"&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;"react-jsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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;"bsc-flags"&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="s2"&gt;"-bs-super-errors"&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;"refmt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&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;The BuckleScript configuration is a kind of mix between a linter config (like &lt;a href="https://eslint.org/docs/user-guide/configuring"&gt;.eslintrc&lt;/a&gt;), and a compiler config (like &lt;a href="https://babeljs.io/docs/usage/babelrc/"&gt;.babelrc&lt;/a&gt;). It's quite normal because BuckleScript fulfills these 2 missions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain Driven Design Made Easy
&lt;/h2&gt;

&lt;p&gt;When I start a fresh new project, I always try to define the &lt;a href="https://martinfowler.com/bliki/UbiquitousLanguage.html"&gt;ubiquitous language&lt;/a&gt; and the associated &lt;a href="https://en.wikipedia.org/wiki/Domain-driven_design"&gt;domain objects&lt;/a&gt; before starting to code. For this project, I already knew my domain, because the reversi game is my favorite project to learn a new language, and I've already written a lot of code around it.&lt;/p&gt;

&lt;p&gt;So, my domain objects are the following: &lt;strong&gt;Game&lt;/strong&gt;, &lt;strong&gt;Player&lt;/strong&gt;, &lt;strong&gt;Board&lt;/strong&gt; and &lt;strong&gt;Cell&lt;/strong&gt;. My first step was to create one &lt;a href="https://reasonml.github.io/docs/en/module.html"&gt;module&lt;/a&gt; per object, with the associated test file. You can see them find them in &lt;a href="https://github.com/marmelab/reversi-reason/tree/master/src"&gt;the reversi-reason Github repository&lt;/a&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── app.re
├── app_test.re
├── board.re
├── board_test.re
├── cell.re
├── cell_test.re
├── game.re
├── game_test.re
├── index.css
├── index.re
├── player.re
└── player_test.re
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In OCaml / Reason, every file maps to a module; this built-in capability empowers most projects with an &lt;strong&gt;out of the box Domain Driven Design architecture&lt;/strong&gt; and a strong expressivity.&lt;/p&gt;

&lt;p&gt;There's no need for &lt;code&gt;require&lt;/code&gt;, &lt;code&gt;use&lt;/code&gt;, or &lt;code&gt;import&lt;/code&gt; to use a module in Reason. Just call the module directly. This way, all the domain objects I talked before are automatically available through their names.&lt;/p&gt;

&lt;p&gt;It's also possible to manually create modules using the &lt;code&gt;module&lt;/code&gt; keyword. So, you can nest and access them using the dot notation (eg: &lt;code&gt;MyModuleFile.MyModule.MySubModule.myFunction&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* MyModuleFile.re */
module MyModule = {
  module MySubModule = {
    let myFunction = () =&amp;gt; "hello";
  };
};

/* ... in another file ... */

let message = MyModuleFile.MyModule.MySubModule.myFunction;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In fact, you don't have to use the dot notation every time you want to access a value in a module. The Module definition can be opened both locally and globally to avoid this repetition.&lt;/p&gt;

&lt;p&gt;An example "local" opening is the &lt;code&gt;applyCellClick&lt;/code&gt; function below. The &lt;code&gt;Board.({ ... })&lt;/code&gt; call exposes &lt;code&gt;applyCellChange&lt;/code&gt; and &lt;code&gt;getCountForColor&lt;/code&gt; from the &lt;code&gt;Board&lt;/code&gt; module without having to repeat the module name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* game.re */
let applyCellClick = (game, x, y) =&amp;gt; Board.({
    let color = Some(currentPlayer(game).color);
    let board = applyCellChange(game.board, { x, y, color });

    switch(getCountForColor(board, None)) {
        | 0 =&amp;gt; { ...game, finished: true }
        | _ =&amp;gt; switchPlayer({ ...game, board })
    };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This "local" opening could have been replaced by a "global" opening at the top of the &lt;code&gt;Game&lt;/code&gt; module. Nevertheless, using global open &lt;a href="https://reasonml.github.io/docs/en/module.html#open-ing-a-module"&gt;is not advised&lt;/a&gt; and must be used sparingly because it can break reasoning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* game.re */
open Board;

let applyCellClick = (game, x, y) =&amp;gt; {
    /* ... */
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  An Imperative Way Out
&lt;/h2&gt;

&lt;p&gt;Reason uses a lot of concepts that are not always easy to handle (recursivity, currying, ...). Fortunately, it isn't as strict as &lt;a href="https://www.haskell.org/"&gt;Haskell&lt;/a&gt;, and it makes it possible to use some imperative and unsafe code when needed. This pragmatic approach is well highlighted in the Reason website.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reason has great traditional imperative &amp;amp; mutative programming capabilities. You should use these features sparingly, but sometimes they allow your code to be more performant and written in a more familiar pattern.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is one of the "ugliest" code snippets from my reversi-reason project. This function collects all flipped cells in a predefined direction. It's the most suitable example because it uses a lot of "legacy" (hear "not functional") capabilities that are allowed by Reason.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* board.re */
let flippedCellsInDirection = (board, cell, (dirx, diry)) =&amp;gt; {
    let cells = ref([]);
    let cursor = ref((cell.x + dirx, cell.y + diry));
    let break = ref(false);

    while (! break^) {
        cells := switch(cursor^) {
            | cursor when isOutOfBound(board, cursor) =&amp;gt; break := true; []
            | (x, y) =&amp;gt; switch(getCell(x, y, board.cells)) {
                | None =&amp;gt; break := true; []
                | color when (color == cell.color) =&amp;gt; break := true; cells^
                | _ =&amp;gt; {
                    cursor := (x + dirx, y + diry);
                    [{ x, y, color: cell.color }, ...cells^]
                }
            }
        };
    };

    cells^
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you look at this code, the first thing that stands out is the usage of the well-known &lt;code&gt;while&lt;/code&gt; loop. Effectively, Reason (&lt;a href="https://realworldocaml.org/v1/en/html/imperative-programming-1.html#for-and-while-loops-1"&gt;as well as OCaml&lt;/a&gt;) allows the usage of &lt;a href="https://reasonml.github.io/docs/en/imperative-loops.html"&gt;imperative loops&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, to be able to break a while loop, I had to use a mutable flag. In Reason, all variables are immutable by nature. To be able to mutate a value, I had to wrap it with a &lt;a href="https://reasonml.github.io/docs/en/mutation.html"&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/a&gt; that acts like a box.&lt;/p&gt;

&lt;p&gt;Afterward, to retrieve the underlying &lt;code&gt;ref&lt;/code&gt; value, the postfix &lt;code&gt;^&lt;/code&gt; operator is used. The truth is that &lt;code&gt;ref&lt;/code&gt; is &lt;a href="https://reasonml.github.io/docs/en/mutation.html#tip-tricks"&gt;just a syntatic sugar&lt;/a&gt; for a predefined mutable record type. &lt;a href="https://reasonml.github.io/en/try.html?reason=DYUwLgBAZg9jEF4IG8DGMB2YRYM4C4IBWAXwG4AoUSKASwDcRFo4A6dLHMXS2GdzNjzMAbGSA"&gt;Test by yourself!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next sections, I'll try to cover how strong the link between Reason and React is. First, talking about &lt;a href="https://reasonml.github.io/reason-react/"&gt;ReasonReact&lt;/a&gt;, and then talking about the associated tests with &lt;a href="https://github.com/airbnb/enzyme"&gt;Enzyme&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built-in JSX support
&lt;/h2&gt;

&lt;p&gt;Before going further, you should know that Reason natively includes &lt;a href="https://reasonml.github.io/docs/en/jsx.html"&gt;JSX support&lt;/a&gt;. In fact, JSX only acts as a syntaxic sugar which is translated to normal function calls wrapped into expressions.&lt;/p&gt;

&lt;p&gt;JSX translates to a &lt;code&gt;make&lt;/code&gt; function call on the same module name as the JSX tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Becomes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;([@JSX] MyComponent.make(~foo=bar, ~children=[], ()));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's why it's necessary to properly name modules. If you wish, you can still create multiple components in the same file thanks to &lt;a href="https://reasonml.github.io/docs/en/module.html"&gt;nested modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Reason JSX syntax is not exactly the same as the JavaScript one. Indeed, there's no props spread but children spread. i.e. you can't do &lt;code&gt;&amp;lt;Foo {...bar} /&amp;gt;&lt;/code&gt; but you can do &lt;code&gt;&amp;lt;Foo&amp;gt; ...baz &amp;lt;/Foo&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  ReasonReact As Cornerstone
&lt;/h2&gt;

&lt;p&gt;How to create React components in Reson? Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* player.re */

let component = ReasonReact.statelessComponent("Player");

let make = (~player, _children) =&amp;gt; {
    ...component,
    render: (_self) =&amp;gt; 
        &amp;lt;div className=("player")&amp;gt;
            (stringToElement(player.name))
        &amp;lt;/div&amp;gt;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I created the component template in combination with the &lt;code&gt;statelessComponent&lt;/code&gt; function from the &lt;a href="https://reasonml.github.io/reason-react/"&gt;ReasonReact&lt;/a&gt; module. Spreading &lt;code&gt;...component&lt;/code&gt; is a bit like saying my component "inherits" from &lt;code&gt;statelessComponent&lt;/code&gt;, except that&lt;br&gt;
 &lt;a href="https://reactjs.org/docs/react-component.html"&gt;class components&lt;/a&gt; don't exist in Reason.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;"Player"&lt;/code&gt; string passed to &lt;code&gt;statelessComponent&lt;/code&gt; primarily acts as a debug marker, it's the ReactJS equivalent of &lt;code&gt;displayName&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Redux-Like Components!
&lt;/h2&gt;

&lt;p&gt;While the &lt;code&gt;statelessComponent&lt;/code&gt; acts as a functional component mixin, there's also another special ReasonReact function called &lt;code&gt;reducerComponent&lt;/code&gt;. This function allows to directly include a "state machine"-like architecture into our components.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X5PYxvMb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/redux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X5PYxvMb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/redux.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using this component requires to define an &lt;code&gt;initialState&lt;/code&gt; and a &lt;code&gt;reducer&lt;/code&gt; function, which contain all the state manipulation logic. Those who have already used &lt;a href="https://redux.js.org/"&gt;redux&lt;/a&gt; will certainly recognize this pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* game.re */

/* ... action type, state type and reducer ... */

let component = ReasonReact.reducerComponent("Game");

let make = (~game, _children) =&amp;gt; {
  ...component,
  initialState: () =&amp;gt; { game, message: None },
  reducer,
  render: (self) =&amp;gt; {
    let { game, message } = self.state;

    let messageElement = switch(message) {
        | None =&amp;gt; nullElement
        | Some(message) =&amp;gt; stringToElement(message)
    };

    &amp;lt;div className="game"&amp;gt;
        (messageElement)
        &amp;lt;Board
            board=game.board
            onCellClick={(x, y) =&amp;gt; self.send(Click(x, y))}
        /&amp;gt;
        /* ... */
    &amp;lt;/div&amp;gt;
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In combination with the &lt;code&gt;reducerComponent&lt;/code&gt;, it is usual to define 2 types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One type for the actions (represented as a variant), and&lt;/li&gt;
&lt;li&gt;One type for the state (represented as a record)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, Reason is able to infer by itself the &lt;code&gt;initialState&lt;/code&gt; type. The &lt;code&gt;action&lt;/code&gt; type is used to represent actions which can then be pattern-matched in the reducer function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* game.re */

type action = Click(int, int) | Restart;

type state = { game, message: option(string) };

let reducer = (action, state) =&amp;gt; switch (action) {
    | Restart =&amp;gt; ReasonReact.SideEffects(locationReload)
    | Click(x, y) =&amp;gt; switch(applyCellClick(state.game, x, y)) {
        | game =&amp;gt; ReasonReact.Update({
            game,
            message: None
        })
        | exception Board.InvalidMove =&amp;gt; ReasonReact.Update({
            ...state,
            message: Some("Invalid Move")
        })
        | exception InsolubleGame(game) =&amp;gt; ReasonReact.Update({
            game,
            message: Some("No One Can Play")
        })
        | exception CantSwitchPlayer(game) =&amp;gt; ReasonReact.Update({
            game,
            message: Some("Opponent can't play, play again!")
        })
    }
};

/* ... react component ... */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the Reason philosophy, the reducer must be pure. Also using a pure function makes the code much more testable and easier to read. Only 4 distinct values can be returned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ReasonReact.NoUpdate&lt;/code&gt;: don't update state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ReasonReact.Update&lt;/code&gt;: update state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ReasonReact.SideEffects&lt;/code&gt;: don't update state but trigger a side effect&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ReasonReact.UpdateWithSideEffects&lt;/code&gt;: update state and trigger a side effect&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Rigorous Interoperability
&lt;/h2&gt;

&lt;p&gt;Reason allows to communicate with other languages thanks to &lt;a href="https://reasonml.github.io/docs/en/external.html"&gt;Externals&lt;/a&gt; (also known as FFI or "interop"). Using "Externals" is the way to go to write safe, predictive, and reliable typed code between Reason and any other language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OXERF7rs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/interop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OXERF7rs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://marmelab.com/images/blog/reasonml/interop.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An Externals is a kind of typed contract / interface between the safe Reason world and the unsafe external world. It's this system that allows the &lt;a href="https://github.com/glennsl/bs-jest"&gt;bs-jest&lt;/a&gt; and &lt;a href="https://github.com/rhysforyou/bs-enzyme"&gt;bs-enzyme&lt;/a&gt; libraries that you'll find further to work.&lt;/p&gt;

&lt;p&gt;Here is a simple example from the famous &lt;code&gt;alert()&lt;/code&gt; function of JavaScript, which takes one arg and returns nothing (a.k.a. a "unit").&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[@bs.val] external alert : string =&amp;gt; unit = "alert";
alert("hello");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're an adventurous man, and you are using Reason with JavaScript, you can also use JS code through the &lt;a href="https://bucklescript.github.io/bucklescript/api/Js.html"&gt;JS module&lt;/a&gt;, or inject code directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* Using the JS module */
Js.log("I'm logged via JS Module externals");

/* Direcly inject raw code */
[%bs.raw {| console.log("I'm logged via raw JS code"); |}];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A complete guide for JavaScript interop is available on &lt;a href="https://reasonml.github.io/docs/en/interop.html"&gt;Reason&lt;/a&gt; and &lt;a href="https://bucklescript.github.io/docs/en/intro-to-external.html"&gt;Bucklescript&lt;/a&gt; documentations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit Testing Reason Code
&lt;/h2&gt;

&lt;p&gt;Under the hood, "create-react-app" uses &lt;a href="https://github.com/facebook/jest"&gt;Jest&lt;/a&gt; as test runner thanks to the &lt;a href="https://github.com/glennsl/bs-jest"&gt;bs-jest&lt;/a&gt; binding. Nothing special about it, the test architecture is almost the same as in JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* board_test.re */
open Jest;
open Expect;

describe("Board", () =&amp;gt; {
    /* ... */

    describe("getCountForColor", () =&amp;gt; {
        test("should return the number of cells of corresponding color", () =&amp;gt; Board.({
            expect(getCountForColor(init(4, 4), Some(Cell.Black))) |&amp;gt; toBe(2);
            expect(getCountForColor(init(4, 4), Some(Cell.White))) |&amp;gt; toBe(2);
            expect(getCountForColor(init(4, 4), None)) |&amp;gt; toBe(12);
        }));
    });

    /* ... */
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the way, it's also possible to use &lt;a href="https://github.com/airbnb/enzyme"&gt;enzyme&lt;/a&gt; to test components as in any other ReactJS project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* cell_test.re */
open Jest;
open Enzyme;
open Expect;

configureEnzyme(react_16_adapter());

describe("&amp;lt;Cell /&amp;gt;", () =&amp;gt; {
    test("should render a disk with the right identifier", () =&amp;gt; {
        let test = (color, expectedClass) =&amp;gt; {
            let wrapper = shallow(
                &amp;lt;Cell
                    color
                    onClick=((_) =&amp;gt; ())
                /&amp;gt;
            );

            expect(wrapper |&amp;gt; find(expectedClass) |&amp;gt; length) |&amp;gt; toBe(1);
        };

        test(Some(Cell.Black), ".cell.black");
        test(Some(Cell.White), ".cell.white");
        test(None, ".cell");
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Pragmatic Community
&lt;/h2&gt;

&lt;p&gt;During development, I had plenty of questions about best practices. Faced with the lack of documentation, I went to the language &lt;a href="https://discord.gg/reasonml"&gt;Discord&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Despite a notable lack of online resources, Reason benefits from a large and reactive community (~200 people always connected). My questions didn't go unanswered more than 5 minutes.&lt;/p&gt;

&lt;p&gt;Recently, I also discovered that the community has introduced a &lt;a href="https://reasonml.chat/"&gt;centralized forum&lt;/a&gt; that appears to be very crowded and active. There are also &lt;a href="https://reason.town/"&gt;fabulous podcasts&lt;/a&gt; that I've all listened to! Don't hesitate to listen to them, this initiative is rare enough to be highlighted.&lt;/p&gt;

&lt;p&gt;Some of these quotes from other developers sound very relevant to me. They perfectly reflect the language's philosophy, which seems to be &lt;em&gt;pragmatism&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My philosophy is that &lt;strong&gt;my time is more valuable than the computer’s time&lt;/strong&gt;, so if I write it in a way that I understand it, it’s OK. - jdeisenberg&lt;/p&gt;

&lt;p&gt;If this is a game that is going to be played by a human, then if evaluation of the board takes 2 milliseconds instead of 2 microseconds, will the person notice? Probably not. - jdeisenberg&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A section from the "what and why?" of the language website confirms that this philosophy is not specific to the community, but to the language itself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An eye for simplicity &amp;amp; pragmatism.&lt;/strong&gt; We allow opt-in side-effect, mutation and object for familiarity &amp;amp; interop, while keeping the rest of the language pure, immutable and functional.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Indeed, Reason is really a pragmatic language, and I like it. Moreover, this principle is consistent with &lt;a href="https://marmelab.com/blog/2017/09/29/project-initialization.html"&gt;agility&lt;/a&gt;, which we practice on every project at marmelab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is This Ready To Use ?
&lt;/h2&gt;

&lt;p&gt;Yes, it is ready to use in production! Reason is supported and &lt;a href="https://reasonml.github.io/blog/2017/09/08/messenger-50-reason.html"&gt;used by Facebook&lt;/a&gt; everyday on big projects. This way, I think you can fairly trust it.&lt;/p&gt;

&lt;p&gt;Moreover, Reason is a &lt;strong&gt;very stable programming language&lt;/strong&gt;, it results from &lt;strong&gt;decades of research&lt;/strong&gt; and compiler engineering from the OCaml language. Its interoperability capabilities give to Reason the &lt;strong&gt;ability to be integrated&lt;/strong&gt; into any existing JavaScript project incrementally, so why wait?&lt;/p&gt;

&lt;p&gt;On my side, there's no doubt that I would like to develop with Reason again. During this project, I've never felt stuck, &lt;strong&gt;everything is designed to produce clean code, with pragmatic alternatives&lt;/strong&gt; in case of difficulty! The developer experience is just awesome!&lt;/p&gt;

&lt;p&gt;To finish, its &lt;strong&gt;active community&lt;/strong&gt; and &lt;strong&gt;cross-platform capabilities&lt;/strong&gt; make me believe that Reason still has some beautiful days ahead. So, don't pass by it! And so, using types saves kittens, don't forget that!&lt;/p&gt;

&lt;p&gt;You can test Reason without setting up a complete stack thanks to &lt;a href="https://reasonml.github.io/en/try.html"&gt;the online compiler&lt;/a&gt; which is very complete and impressively fast!&lt;/p&gt;

&lt;p&gt;If you want to read more on the subject by other authors, I recommend the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://2ality.com/2017/11/about-reasonml.html"&gt;What is ReasonML? (2ality.com - JavaScript and more)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://reasonmlhub.com/exploring-reasonml/"&gt;Exploring ReasonML And Functional Programming (reasonmlhub.com)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jaredforsyth.com/tags/reason/"&gt;JS Interop / Cross-platform Reason (jaredforsyth.com - Jared Forsyth Blog)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://khoanguyen.me/reasonml-toolchain/"&gt;ReasonML Toolchain (khoanguyen.me - Khoa Nguyen Blog)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>reason</category>
      <category>docker</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Elixir GenServer Explained to Redux Developers</title>
      <dc:creator>Demangeon Julien</dc:creator>
      <pubDate>Tue, 19 Dec 2017 20:30:31 +0000</pubDate>
      <link>https://forem.com/juliendemangeon/elixir-genserver-explained-to-redux-developers-1foh</link>
      <guid>https://forem.com/juliendemangeon/elixir-genserver-explained-to-redux-developers-1foh</guid>
      <description>&lt;p&gt;Note: This post was originally posted on &lt;a href="https://marmelab.com/blog/2017/10/04/elixir-genserver-explained-to-redux-developers.html"&gt;marmelab.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Although very young, &lt;a href="https://elixir-lang.org/"&gt;the Elixir language&lt;/a&gt; has gained a lot of popularity since its creation. Whereas based upon an ancestral language / platform called &lt;a href="https://en.wikipedia.org/wiki/Erlang_(programming_language)"&gt;Erlang&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/16779162/what-kind-of-virtual-machine-is-beam-the-erlang-vm?answertab=votes#tab-top"&gt;BEAM&lt;/a&gt;, Elixir provides strong functional, concurrent and distributed capabilities. Its feel modern and fun. That's why I just could not resist to play with it.&lt;/p&gt;

&lt;p&gt;In this post, I'll give the keys that helped me understand GenServer, the cornerstone of a lot of Elixir distributed applications / systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GenServer Swiss Knife
&lt;/h2&gt;

&lt;p&gt;Like any other language built on top of the Erlang VM, Elixir relies on lightweight and isolated threads (usually called &lt;a href="https://elixir-lang.org/getting-started/processes.html"&gt;processes&lt;/a&gt;), and messages passed between these threads. The key benefits of this mechanism are primarily fault-tolerance, distributivity and scalability.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://erlang.org/doc/design_principles/gen_server_concepts.html"&gt;gen_server&lt;/a&gt; (for "Generic Server") is a standard module included in the underlying &lt;a href="http://learnyousomeerlang.com/what-is-otp"&gt;Erlang OTP&lt;/a&gt; (Open Telecommunications Platform). It offers abstractions to build a basic client &amp;lt;-&amp;gt; server system with a common shared resource (state). It was used in a lot of Open Source projects in the Elixir community.&lt;/p&gt;

&lt;p&gt;GenServer usually acts as a central registry with its own state, on which we can perform (a)synchronous actions via message passing. In the web dev world, it can be roughly compared to an asynchronous &lt;a href="http://redux.js.org/"&gt;Redux&lt;/a&gt; store.&lt;/p&gt;

&lt;p&gt;So how does it compare with Redux? In the example below, I'll create a simple registry of quotes. I'll use both GenServer and Redux to show what they have in common.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Elixir Version
&lt;/h2&gt;

&lt;p&gt;Here is how to implement a registry of quotes with GenServer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# quotes_list.ex&lt;/span&gt;

&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;QuotesList&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;

    &lt;span class="c1"&gt;# Client API&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:read&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kn"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kn"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;# Server Callbacks&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:read&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_cast&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kn"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:noreply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kn"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, I define an Elixir module called &lt;code&gt;QuotesList&lt;/code&gt;. Since &lt;code&gt;GenServer&lt;/code&gt; comes from an underlying Erlang library, it was provided through an Elixir Bridge with a kind of "mixin" (thanks to the &lt;a href="https://elixir-lang.org/getting-started/alias-require-and-import.html#use"&gt;"use"&lt;/a&gt; macro).&lt;/p&gt;

&lt;p&gt;In the Elixir world, &lt;code&gt;start_link&lt;/code&gt; is the common method name for starting a process which is attached to the current &lt;a href="https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html"&gt;supervision tree&lt;/a&gt;. The third parameter of this method represents the &lt;a href="http://redux.js.org/docs/recipes/reducers/InitializingState.html"&gt;initial state&lt;/a&gt; (an empty array) of our QuotesList module.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Client API&lt;/strong&gt; section can be defined as the public interface of our module. We can call &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;, ... from the outside to manipulate or access our store at our convenience.&lt;/p&gt;

&lt;p&gt;On the other side, the &lt;strong&gt;Server Callbacks&lt;/strong&gt; section is responsible for the inner working state manipulation of the GenServer. It responds respectively to the different calls / casts made in the Client API section, thanks to the strong &lt;a href="https://elixir-lang.org/getting-started/pattern-matching.html"&gt;pattern matching&lt;/a&gt; capabilities of Elixir. In the next chapter, I'll cover this section in a deeper way.&lt;/p&gt;

&lt;p&gt;To conclude this part about the Elixir implementation, here is an example of GenServer usage for our &lt;code&gt;QuotesList&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# another_module.ex&lt;/span&gt;

&lt;span class="c1"&gt;# Start the quote server&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;QuotesList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;

&lt;span class="c1"&gt;# Adding some items&lt;/span&gt;
&lt;span class="no"&gt;QuotesList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"All that glitters is not gold."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;QuotesList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Elementary, my dear Watson."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;QuotesList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Houston, we have a problem."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Read the quotes back&lt;/span&gt;
&lt;span class="no"&gt;QuotesList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Redux Version
&lt;/h2&gt;

&lt;p&gt;On the Redux side, here is the equivalent of the preceding example in &lt;a href="https://en.wikipedia.org/wiki/ECMAScript#6th_Edition_-_ECMAScript_2015"&gt;ES6&lt;/a&gt;.&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="c1"&gt;// quoteListStore.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;quoteListReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&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;return&lt;/span&gt; &lt;span class="nx"&gt;createStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quoteListReducer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contrary to the Elixir implementation, there's no need to create a "read" method in Redux. We can access the state value directly with &lt;a href="http://redux.js.org/docs/api/Store.html#getState"&gt;getState&lt;/a&gt; on the store. &lt;/p&gt;

&lt;p&gt;Furthermore, the initial state is defined directly into the default value of the &lt;a href="http://redux.js.org/docs/basics/Reducers.html"&gt;reducer&lt;/a&gt; and not in the &lt;a href="http://redux.js.org/docs/api/createStore.html"&gt;createStore&lt;/a&gt; initializer.&lt;/p&gt;

&lt;p&gt;Elixir relies on &lt;a href="https://elixir-lang.org/getting-started/basic-types.html#atoms"&gt;atom&lt;/a&gt; tags to bring matching capabilities to our handlers. In EcmasScript, we use a &lt;code&gt;type&lt;/code&gt; attribute to match the right case of the reducer switch.&lt;/p&gt;

&lt;p&gt;In Elixir, it's necessary to access data by message passing from another process. It's not required in the EcmaScript &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop"&gt;EventLoop&lt;/a&gt; which is mono-threaded.&lt;/p&gt;

&lt;p&gt;And here is how to use the Redux registry in ES:&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="c1"&gt;// index.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;quoteListStore&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./quoteListStore.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addQuote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quote&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;quoteListStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addQuote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All that glitters is not gold.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;quoteListStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addQuote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Elementary, my dear Watson.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;quoteListStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addQuote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Houston, we have a problem.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;quoteListStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Call, Cast &amp;amp; Info Callbacks
&lt;/h2&gt;

&lt;p&gt;If you've never encountered GenServer before, you've certainly asked yourself about the meaning of &lt;code&gt;cast&lt;/code&gt; and &lt;code&gt;call&lt;/code&gt;. These "verbs" corresponds to two different types of actions which can be triggered. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;cast&lt;/code&gt; action consists of an asynchronous action on the store, without any expectation on the result. It means that the action is queued and ready to be processed by corresponding GenServer &lt;code&gt;handle_cast&lt;/code&gt; handler ASAP. It's similar to the famous &lt;a href="http://redux.js.org/docs/api/Store.html#dispatch"&gt;dispatch&lt;/a&gt; method in Redux.&lt;/p&gt;

&lt;p&gt;On the other side, the &lt;code&gt;call&lt;/code&gt; action consists of a synchronous action on the store. The calling process is paused until the action is processed by corresponding GenServer &lt;code&gt;handle_call&lt;/code&gt; handler. It's most often used to access the data.&lt;/p&gt;

&lt;p&gt;Another &lt;code&gt;info&lt;/code&gt; action exists, but is not usually used. This action is triggered when an incoming message comes from an unknow source / process (not the Client API section). The corresponding &lt;code&gt;handle_info&lt;/code&gt; can be compared to some kind of "catchAll" handler (&lt;code&gt;default&lt;/code&gt; case in a Redux reducer &lt;code&gt;switch / case&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If I had to compare Redux and Elixir GenServer, I would say that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GenServer != Redux because of the nature of each running platform.Erlang BEAM / Elixir is distributed, EcmaScript is not.&lt;/li&gt;
&lt;li&gt;GenServer offers kind of &lt;a href="https://en.wikipedia.org/wiki/Remote_procedure_call"&gt;RPC&lt;/a&gt; capabilities through calls. Redux doesn't.&lt;/li&gt;
&lt;li&gt;When the only purpose of Redux is to manipulate the "state", it's not the case of GenServer.&lt;/li&gt;
&lt;li&gt;Redux reducer logic is centralized, GenServer logic is split in multiple &lt;code&gt;handle_*&lt;/code&gt; methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may also be interested by the following related links to go further into  Elixir and GenServer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/elixir/GenServer.html"&gt;https://hexdocs.pm/elixir/GenServer.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://culttt.com/2016/08/24/understanding-genserver-elixir/"&gt;http://culttt.com/2016/08/24/understanding-genserver-elixir/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/blackode/when-and-where-to-use-cast-cal-info-messages-in-elixir-erlang-genserver-9baf937b6494"&gt;https://medium.com/blackode/when-and-where-to-use-cast-cal-info-messages-in-elixir-erlang-genserver-9baf937b6494&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elixir</category>
      <category>redux</category>
      <category>javascript</category>
      <category>genserver</category>
    </item>
    <item>
      <title>Let's cook some Crystal!</title>
      <dc:creator>Demangeon Julien</dc:creator>
      <pubDate>Fri, 15 Dec 2017 19:15:58 +0000</pubDate>
      <link>https://forem.com/juliendemangeon/lets-cook-some-crystal-3eh</link>
      <guid>https://forem.com/juliendemangeon/lets-cook-some-crystal-3eh</guid>
      <description>&lt;p&gt;Note: This post was originally posted on &lt;a href="https://marmelab.com/blog/2017/12/14/lets-cook-some-crystal.html" rel="noopener noreferrer"&gt;marmelab.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Crystal? Some of you may have heard about it in the best TV series of all the time, Breaking Bad! Thankfully, we're not gonna talk about drugs in this post, but about a fabulous programming language I've heard of recently.&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%2Fmarmelab.com%2Fimages%2Fblog%2Fcrystal_breakingbad.jpg" 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%2Fmarmelab.com%2Fimages%2Fblog%2Fcrystal_breakingbad.jpg" alt="Breaking Bad Crystal Cooking"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my constant quest to discover new languages and paradigms, I came across &lt;a href="https://crystal-lang.org/" rel="noopener noreferrer"&gt;Crystal&lt;/a&gt;. Crystal is a compiled, &lt;a href="https://en.wikipedia.org/wiki/Type_system#Static_type_checking" rel="noopener noreferrer"&gt;statically typed&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/Object-oriented_programming" rel="noopener noreferrer"&gt;object-oriented&lt;/a&gt; language. Its syntax is strongly inspired by Ruby, and its goals are mostly the same as &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Golang&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As usual when I learn a new language, I started a fresh new project that I could publish on GitHub. My use case: &lt;a href="https://github.com/marmelab/laurel" rel="noopener noreferrer"&gt;a CLI app&lt;/a&gt; intended to facilitate &lt;a href="https://en.wikipedia.org/wiki/Caesar_cipher" rel="noopener noreferrer"&gt;Caesar Cipher&lt;/a&gt; operations.&lt;/p&gt;

&lt;p&gt;During this post, I'll try to give a large overview of the language capabilities, together with code snippets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ruby, Are You There?
&lt;/h2&gt;

&lt;p&gt;As I said in the introduction, a lot of the Crystal syntax concepts were taken from &lt;a href="https://www.ruby-lang.org/fr/" rel="noopener noreferrer"&gt;Ruby&lt;/a&gt;. The main reason of this syntax choice comes from the language creators' background.&lt;/p&gt;

&lt;p&gt;Ruby is an object-oriented, reflective and &lt;a href="https://en.wikipedia.org/wiki/Type_system#Dynamic_type_checking_and_runtime_type_information" rel="noopener noreferrer"&gt;dynamically typed&lt;/a&gt; programming language. It was developed 20 years ago to provide productivity and fun to developers. It was used in many medium and large projects like &lt;em&gt;GitHub&lt;/em&gt;, &lt;em&gt;Diaspora&lt;/em&gt; or &lt;em&gt;Redmine&lt;/em&gt; (my first happy Ruby experience), and made popular by RoR (&lt;em&gt;Ruby on Rails&lt;/em&gt;). &lt;/p&gt;

&lt;p&gt;While Ruby is an interpreted and &lt;a href="https://en.wikipedia.org/wiki/Cross-platform" rel="noopener noreferrer"&gt;multi-platform&lt;/a&gt; language (which runs on &lt;a href="https://en.wikipedia.org/wiki/YARV" rel="noopener noreferrer"&gt;YARV&lt;/a&gt; VM), Crystal is not. That means Crystal needs to be compiled on the platform where it'll be executed.&lt;/p&gt;

&lt;p&gt;As you are going to see later, Crystal is not Ruby, it &lt;em&gt;mimics&lt;/em&gt; Ruby. If you're a Rubyist, you'll be a little disappointed by static typing and inference. Even so, many basic concepts have been taken from Ruby. Among them, we find &lt;em&gt;"Blocks"&lt;/em&gt;, &lt;em&gt;"Symbols"&lt;/em&gt; and &lt;em&gt;"Everything is an object" principle&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Crystal Blocks
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/blocks_and_procs.html" rel="noopener noreferrer"&gt;Blocks&lt;/a&gt; are heavily used in Crystal (as much as in Ruby). They allow to capture a block of code with its own context, and execute it later. It's almost the same thing as &lt;em&gt;closures&lt;/em&gt; or &lt;em&gt;anonymous functions&lt;/em&gt; in other languages.&lt;/p&gt;

&lt;p&gt;Here is a part of code from my toy project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="no"&gt;Encoder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ALPHABET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;key: &lt;/span&gt;&lt;span class="n"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;count: &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&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="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the block which is defined between &lt;code&gt;do |shift|&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; is called for each letter between &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;Encoder::ALPHABET.size&lt;/code&gt; (thanks to &lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/literals/range.html" rel="noopener noreferrer"&gt;Crystal Range&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The last letter (defined by &lt;code&gt;Encoder::ALPHABET.size&lt;/code&gt;) is excluded from the range because of &lt;code&gt;...&lt;/code&gt;. To include the last letter, it would been necessary to use &lt;code&gt;..&lt;/code&gt;, which is inclusive.&lt;/p&gt;

&lt;p&gt;Within the &lt;code&gt;.each&lt;/code&gt; call, the block is &lt;strong&gt;"yielded"&lt;/strong&gt; with the corresponding function from &lt;a href="https://github.com/crystal-lang/crystal/blob/v0.24.1/src/range.cr#L102" rel="noopener noreferrer"&gt;range.cr&lt;/a&gt;. In fact, a block is called with the &lt;code&gt;yield&lt;/code&gt; keyword from Crystal as described in the doc example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;twice&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;twice&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Hello!"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# =&amp;gt; prints "Hello!" twice&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Symbols
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Symbol&lt;/strong&gt; is another interesting concept also found in Ruby. A Crystal &lt;a href="https://crystal-lang.org/api/0.23.1/Symbol.html" rel="noopener noreferrer"&gt;Symbol&lt;/a&gt; is a constant which is identified by its name. Internally, Crystal holds a registry of Symbols, which are represented as an Int32.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;
&lt;span class="ss"&gt;:hello&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="ss"&gt;:hello&lt;/span&gt; &lt;span class="c1"&gt;# true&lt;/span&gt;
&lt;span class="ss"&gt;:hello&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt; &lt;span class="c1"&gt;# false&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Symbols are closely the same as &lt;a href="http://elixir-lang.github.io/getting-started/basic-types.html#atoms" rel="noopener noreferrer"&gt;Elixir atoms&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everything is an Object
&lt;/h3&gt;

&lt;p&gt;In Crystal, as in Ruby, everything is an object. Effectively, since reading post, you've already experienced no less than 3 objects (Blocks, Symbols and Ranges). Just like in Ruby, all objects extend &lt;a href="https://crystal-lang.org/api/0.20.1/Object.html" rel="noopener noreferrer"&gt;Object&lt;/a&gt;. When you write Crystal code, most of the time, you write classes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Curses&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Window&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Curses&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, Crystal can also be used in a functional way. As a module requires a class, the solution is to make the module &lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/modules.html#extend-self" rel="noopener noreferrer"&gt;"self-extended"&lt;/a&gt;. For instance, I can write an &lt;code&gt;Encoder&lt;/code&gt; module that &lt;em&gt;does not&lt;/em&gt; contain a class by using &lt;code&gt;extend self&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Encoder&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;

  &lt;span class="no"&gt;ALPHABET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"abcdefghijklmnopqrstuvwxyz "&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uncoded&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Int32&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="n"&gt;dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_shift_dictionary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;normalized_uncoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uncoded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="n"&gt;normalized_uncoded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I can call the &lt;code&gt;encode()&lt;/code&gt; method directly, without a supporting class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Encoder&lt;/span&gt;
&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'o'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Crystal Functionalities
&lt;/h2&gt;

&lt;p&gt;Whereas Crystal picks some concepts from Ruby, it also comes with a lot of unexpected functionalities such as &lt;em&gt;Type inference&lt;/em&gt;, &lt;em&gt;concurrency&lt;/em&gt; and &lt;em&gt;compile time null reference checks&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type Inference at its Core
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Type inference&lt;/em&gt; is one of the most valuable Crystal functionnalities. It gives you the power to delegate the type attribution process to the compiler. Moreover, in association with &lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/union_types.html" rel="noopener noreferrer"&gt;Union Types&lt;/a&gt;, it allows to give different types to the same variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;# : Int32 | String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, the type of &lt;code&gt;a&lt;/code&gt; is automaticaly infered from the &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree" rel="noopener noreferrer"&gt;AST&lt;/a&gt; (Abstract Syntax Tree) at compile time. It's also possible to assign the type manually, as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Int32&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;String&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type Inference also works with &lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/literals/array.html" rel="noopener noreferrer"&gt;Arrays&lt;/a&gt;, &lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/literals/tuple.html" rel="noopener noreferrer"&gt;Tuples&lt;/a&gt;, &lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/literals/named_tuple.html" rel="noopener noreferrer"&gt;NamedTuples&lt;/a&gt;, &lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/literals/hash.html" rel="noopener noreferrer"&gt;Hashes&lt;/a&gt;...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&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="s2"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Array(Int32 | String | Char)&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="s2"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Tuple(Int32, String, Char)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Crystal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;year: &lt;/span&gt;&lt;span class="mi"&gt;2017&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# NamedTuple(name: String, year: Int32)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'a'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Hash(Int32 | Char, Int32)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Syntaxic sugar and shortcuts exist to declare empty typed structures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt; &lt;span class="c1"&gt;# same as Array(Int32).new&lt;/span&gt;
&lt;span class="no"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Tuple(Int32, String, Char)&lt;/span&gt;
&lt;span class="no"&gt;NamedTuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;x: &lt;/span&gt;&lt;span class="no"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;y: &lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# NamedTuple(x: Int32, y: String)&lt;/span&gt;
&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt; &lt;span class="c1"&gt;# same as Hash(Int32, Int32).new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Concurrency with Channels and Fibers
&lt;/h3&gt;

&lt;p&gt;In addition to its fun syntax and static typing system, Crystal brings some concurrency capabilities (inspired by &lt;a href="https://en.wikipedia.org/wiki/Communicating_sequential_processes" rel="noopener noreferrer"&gt;CSP&lt;/a&gt;) through &lt;a href="https://crystal-lang.org/docs/guides/concurrency.html#fibers" rel="noopener noreferrer"&gt;Fibers&lt;/a&gt;. It's one of the most valuable functionalities of Crystal in comparison to other compiled languages&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Concurrency_(computer_science)" rel="noopener noreferrer"&gt;Concurrency&lt;/a&gt; consists of running several tasks in the same time interval through operation switching. This concept is often mistaken with &lt;a href="https://en.wikipedia.org/wiki/Parallel_computing" rel="noopener noreferrer"&gt;parallelism&lt;/a&gt;, which consists of running multiples operations simultaneously (mathematically, in parallel).&lt;/p&gt;

&lt;p&gt;Crystal Fibers can be compared to Golang's &lt;a href="https://gobyexample.com/goroutines" rel="noopener noreferrer"&gt;Goroutines&lt;/a&gt;. The main difference lays in the way Crystal allocate operations to CPUs. When Golang uses all availables CPUs, Crystal is only capable of using one of them for the moment.&lt;/p&gt;

&lt;p&gt;Fibers use the same &lt;code&gt;message passing&lt;/code&gt; system as Golang to achieve synchronisation and data passing between Fibers. It uses a kind of light-weight pipes called &lt;a href="https://crystal-lang.org/docs/guides/concurrency.html#channels" rel="noopener noreferrer"&gt;Channels&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is a little example of asynchronous operations written with Goroutines and Fibers. It'll give you a more concrete example of Fibers usage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// GOLANG&lt;/span&gt;

&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&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;defer&lt;/span&gt; &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"ping"&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="c"&gt;// Program will wait for 5s&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// =&amp;gt; ping&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="c1"&gt;# CRYSTAL&lt;/span&gt;

&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

&lt;span class="n"&gt;spawn&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;
  &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt; &lt;span class="c1"&gt;# Program will wait for 5s&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; ping&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this example, I used the &lt;code&gt;channel&lt;/code&gt; system to provide an exchange pipe between the main thread and the routine (async thread).&lt;/p&gt;

&lt;p&gt;To declare an async thread, the &lt;code&gt;spawn&lt;/code&gt; keyword with an associated &lt;a href="https://crystal-lang.org/docs/syntax_and_semantics/blocks_and_procs.html" rel="noopener noreferrer"&gt;code block&lt;/a&gt; is used on the Crystal side. With Golang, an anonymous function is started in a goroutine via the &lt;code&gt;go&lt;/code&gt; keyword ahead of it.&lt;/p&gt;

&lt;p&gt;At assignation time (in this example), the main thread is stopped until the corresponding &lt;code&gt;channel&lt;/code&gt; sends data back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Null Reference Checks
&lt;/h3&gt;

&lt;p&gt;In you career, you've certainly heard of "NullPointerException" or the &lt;a href="https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare" rel="noopener noreferrer"&gt;The Billion Dollar Mistake&lt;/a&gt;. This well known concept comes from the fact that it's deadly simple to call on a reference which is &lt;code&gt;Null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In Crystal, this kind of exception can't happen. A checks is issued at compile time to prevent it, thanks to Static Typing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hello world"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous code will fail with a compile time exception.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;crystal&lt;/span&gt; &lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cr&lt;/span&gt;
&lt;span class="no"&gt;Error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;undefined&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="s1"&gt;'e'&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="no"&gt;Nil&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt;
          &lt;span class="o"&gt;^~~~~~&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exception occurs because &lt;code&gt;hello&lt;/code&gt; can be either &lt;code&gt;String&lt;/code&gt; or &lt;code&gt;Nil&lt;/code&gt;, and there's no &lt;code&gt;upcase&lt;/code&gt; method on &lt;code&gt;Nil&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crystal Tooling
&lt;/h2&gt;

&lt;p&gt;Another argument in favour of Crystal is its great standard library, which covers most of the usual needs. &lt;a href="https://crystal-lang.org/api/0.23.1/" rel="noopener noreferrer"&gt;A lot of tools&lt;/a&gt; are bundled with Crystal itself (HTTP, JSON, Markdown Parser and so on), making it ready to use instantly. &lt;/p&gt;

&lt;p&gt;For example, here is a small HTTP server written in Crystal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"http/server"&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;content_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"text/plain"&lt;/span&gt;
  &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"Hello world, got &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Listening on http://127.0.0.1:8080"&lt;/span&gt;
&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Crystal Ecosystem
&lt;/h2&gt;

&lt;p&gt;Despite its youth, Crystal has gained a lot of popularity in no time thanks to its Ruby-like syntax. It actually shares hype in the declining rubyist's world with another language, &lt;a href="https://elixir-lang.org/" rel="noopener noreferrer"&gt;Elixir&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Most Crystal-based projects are very confidential for the moment. Nevertheless, some of them have gained popularity rapidly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kemalcr/kemal" rel="noopener noreferrer"&gt;KEMAL&lt;/a&gt; - Fast, Effective, Simple web framework (including websockets, etc)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Crecto/crecto" rel="noopener noreferrer"&gt;CRECTO&lt;/a&gt; - Database wrapper (inspired by Elixir's Ecto)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mperham/sidekiq.cr" rel="noopener noreferrer"&gt;SIDEKIQ&lt;/a&gt; - Simple, efficient job processing (Including web monitoring UI)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crystal bundles with an easy-to-use dependency management system. It consists of a simple YAML file (named shard.yml) listing dependencies and associated versions. It looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MyAmbitiousProject&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.1.0&lt;/span&gt;

&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;openssl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;github&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;datanoise/openssl.cr&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;development_dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minitest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;git&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/ysbaddaden/minitest.cr.git&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~&amp;gt; 0.3.1&lt;/span&gt;

&lt;span class="na"&gt;license&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MIT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, a simple &lt;code&gt;crystal deps&lt;/code&gt; command is enough to retrieve needed dependencies into the project tree.&lt;/p&gt;

&lt;p&gt;If you're curious to discover other interesting Crystal projects, a &lt;a href="https://crystalshards.xyz/" rel="noopener noreferrer"&gt;dedicated portal&lt;/a&gt; has been created specially for that purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Crystal has been first released in 2014. It's a relatively young language for the moment, but it promises a bright future.&lt;/p&gt;

&lt;p&gt;Its advanced type inference system combined with static typing and union types give Crystal the feeling of a higher-level scripting language, with performances close to the metal. It can be a good alternative to Golang for modest performance needs.&lt;/p&gt;

&lt;p&gt;Moreover, if you're already familiar with Ruby, Crystal is the first choice language. It offers good performances without having to bear Golang's heavy syntax.&lt;/p&gt;

&lt;p&gt;Finally, if you like this language but need &lt;a href="https://en.wikipedia.org/wiki/Distributed_computing" rel="noopener noreferrer"&gt;distributed operations&lt;/a&gt;, you can take a look at &lt;a href="https://elixir-lang.org/getting-started/introduction.html" rel="noopener noreferrer"&gt;the Elixir language&lt;/a&gt;, which is very appreciated by rubyists, too.&lt;/p&gt;

&lt;p&gt;If you're interested in the project associated to this post, you should take a look at &lt;a href="https://github.com/marmelab/laurel" rel="noopener noreferrer"&gt;the repository&lt;/a&gt;. It'll also give you a good start to dockerize Crystal apps in the same time.&lt;/p&gt;

</description>
      <category>perf</category>
      <category>crystal</category>
      <category>ruby</category>
      <category>go</category>
    </item>
  </channel>
</rss>
