<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>dimafeng.com</title>
    <description>This blog is about programming tricks and tips.
</description>
    <link>http://dimafeng.com/</link>
    <atom:link href="http://dimafeng.com/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Sun, 15 Sep 2019 21:42:24 +0000</pubDate>
    <lastBuildDate>Sun, 15 Sep 2019 21:42:24 +0000</lastBuildDate>
    <generator>Jekyll v3.8.5</generator>
    
      <item>
        <title>neotypes: Akka-http + neo4j</title>
        <description>&lt;p&gt;I haven’t been writing posts for a while and this is going to be my first blog post for this year. Today, I’m going to introduce you to my most recent pet project - &lt;a href=&quot;https://neotypes.github.io/neotypes/&quot;&gt;neotypes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We’re going to be talking about graph databases today. If you’re not familiar with graph databases and neo4j particularly, please check &lt;a href=&quot;https://neo4j.com/developer/graph-database/&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve been using neo4j for about a year now and I absolutely love it. Of course, it’s not a silver bullet but it’s something new that helps to model your domain on a completely different level. Since I also love Scala and functional programming, I was missing a “native” Scala driver. So I decided to build it by myself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;neotypes&lt;/strong&gt; is a Scala lightweight, type-safe, asynchronous driver (not opinionated on side-effect implementation) for neo4j. Let’s break this sentence down into distinct properties of this driver.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Scala&lt;/strong&gt; - the driver provides you with support for all standard Scala types without the need to convert Scala &amp;lt;-&amp;gt; Java types back and forth and you can easily add your types.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Lightweight&lt;/strong&gt; - the driver depends on &lt;code class=&quot;highlighter-rouge&quot;&gt;shapeless&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;neo4j Java driver&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Type-safe&lt;/strong&gt; - the driver leverages &lt;a href=&quot;https://blog.scalac.io/2017/04/19/typeclasses-in-scala.html&quot;&gt;typeclasses&lt;/a&gt; to derive all needed conversions at the compile time.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Asynchronous&lt;/strong&gt; - the driver sits on top of &lt;a href=&quot;https://neo4j.com/blog/beta-release-java-driver-async-api-neo4j/&quot;&gt;asynchronous Java driver&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Not opinionated on side-effect implementation&lt;/strong&gt; - you can use it with any implementation of side-effects of your chose (scala.Future, cats-effect
 IO, Monix Task, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, let’s jump to a real example.&lt;/p&gt;

&lt;h2 id=&quot;akka-http--neo4j&quot;&gt;Akka-http + neo4j&lt;/h2&gt;

&lt;p&gt;We will be building a sample application using &lt;strong&gt;Akka-http&lt;/strong&gt; as a web server and &lt;strong&gt;neo4j&lt;/strong&gt; as a database. &lt;strong&gt;Akka-http&lt;/strong&gt; is pretty popular framework in Scala ecosystem for building http applications such as sites, http APIs, microservices, etc. &lt;strong&gt;Akka&lt;/strong&gt; and &lt;strong&gt;Akka-http&lt;/strong&gt; are based on &lt;code class=&quot;highlighter-rouge&quot;&gt;scala.concurrent.Future&lt;/code&gt;, so using a neo4j Java driver would be a challenge. What you would do is you would deal with tons of &lt;code class=&quot;highlighter-rouge&quot;&gt;java.util.concurrent.CompletionStage&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;scala.concurrent.Future&lt;/code&gt; conversion and try to map query outputs to your domain classes manually. &lt;strong&gt;neotypes&lt;/strong&gt; offers a better approach.&lt;/p&gt;

&lt;p&gt;Our application is going to be a movie catalog based on the Movie graph dataset which comes with neo4j. There is an &lt;a href=&quot;https://github.com/neo4j-examples/neo4j-movies-java-bolt&quot;&gt;existing application&lt;/a&gt; built by neo4j team as an example of java driver usage. So we can rewrite it to Scala.&lt;/p&gt;

&lt;h3 id=&quot;environment-configuration&quot;&gt;Environment configuration&lt;/h3&gt;

&lt;p&gt;To start, we need a neo4j instance to run our queries against. I’m a docker fan, so we going to use a docker compose to run my local instance of the database.&lt;/p&gt;

&lt;p&gt;My &lt;code class=&quot;highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt; looks as follows&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;na&quot;&gt;neo4j&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;neo4j:3.5.0&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;7474:7474&quot;&lt;/span&gt;
   &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;7687:7687&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./db/dbms:/data/dbms&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Execute &lt;code class=&quot;highlighter-rouge&quot;&gt;docker-compose up&lt;/code&gt; to start the database. After it’s up and running, go to http://localhost:7474/browser/ and execute &lt;code class=&quot;highlighter-rouge&quot;&gt;:play movie-graph&lt;/code&gt; in the query window. Now we have the sample data.&lt;/p&gt;

&lt;p&gt;If you run a query &lt;code class=&quot;highlighter-rouge&quot;&gt;MATCH p=()--&amp;gt;() RETURN p LIMIT 25&lt;/code&gt;, you will see something similar to:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/neotypes1/movie-graph.png&quot; /&gt;
&lt;/p&gt;

&lt;h3 id=&quot;data-access-layer&quot;&gt;Data access layer&lt;/h3&gt;

&lt;p&gt;One of the queries that we want to run is to find a movie cast by its title. The query that is used in &lt;a href=&quot;https://github.com/neo4j-examples/neo4j-movies-java-bolt&quot;&gt;java application&lt;/a&gt; looks as follows:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MATCH (movie:Movie {title: $title})
       OPTIONAL MATCH (movie)&amp;lt;-[r]-(person:Person)
       RETURN movie.title as title, 
              collect({name:person.name, job:head(split(lower(type(r)),'_')), role:head(r.roles)}) as cast
       LIMIT 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We need to come up with a model that the result of this query will be mapped to. We could use anonymous types such as &lt;code class=&quot;highlighter-rouge&quot;&gt;Tuple&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;HList&lt;/code&gt; but it’s easier to map the result to a case class and then convert it to json object as-is. In our case, we can use these two case classes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MovieCast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Since the query output has aliases for each element, they will be mapped to corresponding fields of a case class.&lt;/p&gt;

&lt;p&gt;Now we can write some queries using &lt;strong&gt;neotypes&lt;/strong&gt;. For simplicity, a service layer is incapsulating both business logic and data access logic (do not do it this way in your production code).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;neotypes.Driver&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;neotypes.exaple.akkahttp.MovieService.MovieToActor&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;neotypes.implicits._&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;scala.concurrent.ExecutionContext.Implicits.global&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;scala.concurrent.Future&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MovieService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Driver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;findMovie&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;MovieCast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readSession&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;MATCH (movie:Movie {title: $title})
       OPTIONAL MATCH (movie)&amp;lt;-[r]-(person:Person)
       RETURN movie.title as title, 
              collect({name:person.name, job:head(split(lower(type(r)),'_')), role:head(r.roles)}) as cast
       LIMIT 1&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;MovieCast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;single&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let’s take a look at this code. In order to access neo4j, we need to obtain an instance of a Driver. For modularity and testing purposes, the driver is injected via the constructor. As you can see, we’re passing an instance of &lt;code class=&quot;highlighter-rouge&quot;&gt;neotypes.Driver&lt;/code&gt; parametrized by &lt;code class=&quot;highlighter-rouge&quot;&gt;[Future]&lt;/code&gt; which means that we’re using &lt;code class=&quot;highlighter-rouge&quot;&gt;neotypes&lt;/code&gt; wrapper for &lt;code class=&quot;highlighter-rouge&quot;&gt;org.neo4j.driver.v1.Driver&lt;/code&gt; and all side effects will be encapsulated in &lt;code class=&quot;highlighter-rouge&quot;&gt;scala.concurrent.Future&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;neotypes.Driver&lt;/code&gt; has a very handy method &lt;code class=&quot;highlighter-rouge&quot;&gt;readSession&lt;/code&gt; (and the same &lt;code class=&quot;highlighter-rouge&quot;&gt;write&lt;/code&gt; alternative) for automatic resource management. Using this method, you don’t need to think about session closing as well as transaction commits/rollbacks - it’s all done by the library.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;c&quot;&quot;&quot;MATCH (movie:Movie {title: $title})...&lt;/code&gt; is &lt;a href=&quot;https://docs.scala-lang.org/overviews/core/string-interpolation.html&quot;&gt;custom string interpolator&lt;/a&gt;. It means that &lt;code class=&quot;highlighter-rouge&quot;&gt;$title&lt;/code&gt; is not regular interpolation. &lt;strong&gt;neotypes&lt;/strong&gt; converts all variables used in a query into &lt;a href=&quot;https://neotypes.github.io/neotypes/docs/types.html&quot;&gt;neo4j supported types&lt;/a&gt; and passes values via statement parameters so that the actual query will look like &lt;code class=&quot;highlighter-rouge&quot;&gt;MATCH (movie:Movie {title: $p1})...&lt;/code&gt; and the actual title value will be passed as &lt;code class=&quot;highlighter-rouge&quot;&gt;p1 -&amp;gt; [value]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we’re coming to the magic part. &lt;code class=&quot;highlighter-rouge&quot;&gt;query[Option[MovieCast]]&lt;/code&gt; defines our mapping. As you can see, we haven’t explicitly specified the mapping rules because &lt;strong&gt;neotypes&lt;/strong&gt; can infer those rules for you. Wrapping of your target type into &lt;code class=&quot;highlighter-rouge&quot;&gt;Option&lt;/code&gt; helps us to deal with no result cases.&lt;/p&gt;

&lt;h3 id=&quot;akka-http&quot;&gt;Akka-http&lt;/h3&gt;

&lt;p&gt;Let’s now define a simple router. Our goal is to handle &lt;code class=&quot;highlighter-rouge&quot;&gt;/movie/[movie name]&lt;/code&gt; urls.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MovieRoute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;movieService&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;MovieService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;implicit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executionContext&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ExecutionContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
 
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;route&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pathPrefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;movie&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pathPrefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Segment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pathEndOrSingleSlash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;movieService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;findMovie&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;movie&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;nc&quot;&gt;OK&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;movie&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asJson&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;nc&quot;&gt;BadRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asJson&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;it’s pretty straightforward. Since we’re dealing with scala &lt;em&gt;Future&lt;/em&gt;s, we don’t need to convert our service layer output, we just map it to a proper http response.&lt;/p&gt;

&lt;h3 id=&quot;wrap-it-up&quot;&gt;Wrap it up&lt;/h3&gt;

&lt;p&gt;Now we just need to glue everything together.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GraphDatabase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AuthTokens&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asScala&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;movieService&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MovieService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpRoute&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MovieRoute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;movieService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;Http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bindAndHandle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;httpRoute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the beginning, we create regular &lt;code class=&quot;highlighter-rouge&quot;&gt;org.neo4j.driver.v1.Driver&lt;/code&gt;, and then wrap it into &lt;strong&gt;neotypes&lt;/strong&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;Driver&lt;/code&gt; by using &lt;code class=&quot;highlighter-rouge&quot;&gt;.asScala[Future]&lt;/code&gt; method. That’s it!&lt;/p&gt;

&lt;p&gt;To demonstrate the application, we can use &lt;code class=&quot;highlighter-rouge&quot;&gt;curl&lt;/code&gt; to call endpoints.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ curl http://localhost:9000/movie/The%20Matrix

{&quot;title&quot;:&quot;The Matrix&quot;,&quot;cast&quot;:[{&quot;name&quot;:&quot;Emil Eifrem&quot;,&quot;job&quot;:&quot;acted&quot;,&quot;role&quot;:&quot;Emil&quot;},{&quot;name&quot;:&quot;Joel Silver&quot;,&quot;job&quot;:&quot;produced&quot;,&quot;role&quot;:&quot;null&quot;},{&quot;name&quot;:&quot;Lana Wachowski&quot;,&quot;job&quot;:&quot;directed&quot;,&quot;role&quot;:&quot;null&quot;},{&quot;name&quot;:&quot;Lilly Wachowski&quot;,&quot;job&quot;:&quot;directed&quot;,&quot;role&quot;:&quot;null&quot;},{&quot;name&quot;:&quot;Hugo Weaving&quot;,&quot;job&quot;:&quot;acted&quot;,&quot;role&quot;:&quot;Agent Smith&quot;},{&quot;name&quot;:&quot;Laurence Fishburne&quot;,&quot;job&quot;:&quot;acted&quot;,&quot;role&quot;:&quot;Morpheus&quot;},{&quot;name&quot;:&quot;Carrie-Anne Moss&quot;,&quot;job&quot;:&quot;acted&quot;,&quot;role&quot;:&quot;Trinity&quot;},{&quot;name&quot;:&quot;Keanu Reeves&quot;,&quot;job&quot;:&quot;acted&quot;,&quot;role&quot;:&quot;Neo&quot;}]}%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I also borrowed a UI part of &lt;a href=&quot;https://github.com/neo4j-examples/neo4j-movies-java-bolt&quot;&gt;the java sample application&lt;/a&gt; so that you can enjoy a nice looking visual representation.&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/neotypes1/ui.png&quot; /&gt;
&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;As you could see, &lt;strong&gt;neotypes&lt;/strong&gt; drastically simplifies interaction with neo4j from Scala. If you want to learn more and help the project, please:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Star the project on GitHub - &lt;a href=&quot;https://github.com/neotypes/neotypes&quot;&gt;https://github.com/neotypes/neotypes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Read the official documentation - &lt;a href=&quot;https://neotypes.github.io/neotypes/docs.html&quot;&gt;https://neotypes.github.io/neotypes/docs.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Check the sources of the application we built today - &lt;a href=&quot;https://github.com/neotypes/examples&quot;&gt;https://github.com/neotypes/examples&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
        <pubDate>Thu, 27 Dec 2018 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2018/12/27/neotypes-1/</link>
        <guid isPermaLink="true">http://dimafeng.com/2018/12/27/neotypes-1/</guid>
        
        
        <category>neo4j,</category>
        
        <category>akka-http</category>
        
      </item>
    
      <item>
        <title>Flexible alerting for ELK</title>
        <description>&lt;p&gt;For the past month, I’ve been working on my pet project - &lt;a href=&quot;https://github.com/l3rt/l3rt&quot;&gt;L3rt&lt;/a&gt;. It’s a very flexible alternative to &lt;a href=&quot;https://github.com/Yelp/elastalert&quot;&gt;Elastalert&lt;/a&gt;. The main idea was to replace &lt;code class=&quot;highlighter-rouge&quot;&gt;yml&lt;/code&gt; configurations with Groovy DSL and create some simple web UI to create and debug rules. In this post, I’m going to show you what I’ve got so far.&lt;/p&gt;

&lt;div class=&quot;disclaimer&quot;&gt;
&lt;h1&gt;Disclaimer&lt;/h1&gt;
This application is under heavy development and can have bugs. Please use it with caution.
&lt;/div&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;h1&gt;Note&lt;/h1&gt;
For all who is interested in participating in development or have brilliant ideas for the project's future, don't hesitate to submit issues and send pull requests. &lt;a href=&quot;https://github.com/l3rt/l3rt&quot;&gt;L3rt&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;In order to show you how it all works, I’ll be using &lt;a href=&quot;https://github.com/l3rt/docker-elk&quot;&gt;this preconfigured docker-compose example of ELK stack&lt;/a&gt;. In this project, we already have all that we need for monitoring demonstration, the only we need to add is an alerting tool.&lt;/p&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt; and add the following service:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;  &lt;span class=&quot;nx&quot;&gt;l3rt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dimafeng&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l3rt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;8080:8080&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elk&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s it! Now we’re ready to check how it works.&lt;/p&gt;

&lt;p&gt;Execute &lt;code class=&quot;highlighter-rouge&quot;&gt;$ docker-compose up -d&lt;/code&gt; to start all docker containers. Great, we just need to load some logs to our monitoring system.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;nc localhost 5000 &amp;lt; /path/to/logfile.log&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you want to make sure all data is there, you can set up Kibana index patterns using &lt;a href=&quot;https://github.com/l3rt/docker-elk#default-kibana-index-pattern-creation&quot;&gt;this instruction&lt;/a&gt;. But I skip this step for now.&lt;/p&gt;

&lt;h2 id=&quot;web-playgroud&quot;&gt;Web playgroud&lt;/h2&gt;

&lt;p&gt;Open &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt; in your browser. You should see something like this:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/l3rt/first-screen.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;Now we can write some rules. The most basic rule is a &lt;a href=&quot;https://github.com/l3rt/l3rt/blob/master/docs/elasticsearchQueryRule.md&quot;&gt;query rule&lt;/a&gt;.
Let’s say, we want to retrieve messages that contain a sentence “Service started”.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ruleName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;myTestRule&quot;&lt;/span&gt;                         &lt;span class=&quot;c1&quot;&gt;// (1)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;index:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;logstash-*&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;// (2)&lt;/span&gt;
            
            &lt;span class=&quot;nl&quot;&gt;query:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;                                &lt;span class=&quot;c1&quot;&gt;// (3)&lt;/span&gt;
                &lt;span class=&quot;nl&quot;&gt;query:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                            &lt;span class=&quot;nl&quot;&gt;bool:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                                &lt;span class=&quot;nl&quot;&gt;must:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                                        &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;match&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Service started&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;
                                    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                        &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;],&lt;/span&gt;
            
            &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;                              &lt;span class=&quot;c1&quot;&gt;// (4)&lt;/span&gt;
                    &lt;span class=&quot;nl&quot;&gt;sources:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                            &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;elasticSearch:http://elasticsearch:9200&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;reaction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;                               &lt;span class=&quot;c1&quot;&gt;// (5)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let’s take a look at what the rule consists of.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You should name your rule. The name will be used for storing of rule execution metadata.&lt;/li&gt;
  &lt;li&gt;This is an index that will be used for querying. By default, Logstash is using indexes &lt;code class=&quot;highlighter-rouge&quot;&gt;logstash-*&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;It is an ElasticSearch query. You can read more about ElasticSearch search API &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Since we haven’t specified config (yet), we need to define an ElasticSearch connection.&lt;/li&gt;
  &lt;li&gt;Let’s just print the result as a log message for now.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In my case, I see the following messages:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/l3rt/script-1.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;It prints all messages matched by the query in a raw format. Now we would want to extract message data and send it to some real target. First, say we have a message that looks like &lt;code class=&quot;highlighter-rouge&quot;&gt;2016-12-10 17:27:01] [info] [ 4844] Service started in 1093 ms.&lt;/code&gt; and we want to retrieve an integer value of milliseconds and depending on that value we’ll be sending or ignoring the message.&lt;/p&gt;

&lt;p&gt;How to extract that value - since the rule is just a groovy based script we can use all the JVM power.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;(?s).*Service started in (\\d*).*&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;replaceAll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;\$1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toInteger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, if the value is greater than 1000 then we send a notification to a DevOps by email. If it’s greater than 2000 we send an email to DevOps and a HipChat message to a public room of our company. Otherwise, we ignore it. It can look as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;    &lt;span class=&quot;n&quot;&gt;reaction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;forEach&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;(?s).*Service started in (\\d*).*&quot;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;replaceAll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;\$1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toInteger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;devops@company.com&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Enormous starting time&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${it.data.get(&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@timestamp&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;)}: Enormous starting time detected - ${startTime}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;hipchat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Notifications&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Enormous starting time detected - ${startTime}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;RED&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;devops@company.com&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Starting time warning&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${it.data.get(&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@timestamp&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;)}: Starting time is out of normal - ${startTime}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After rule launch you’ll see:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-log&quot; data-lang=&quot;log&quot;&gt;2017-10-04T01:05:56.096Z[INFO] Email: recipient=devops@company.com subject=Enormous starting time body=2017-09-25T00:49:22.831Z: Enormous starting time detected - 2093
2017-10-04T01:05:56.096Z[INFO] HipChat: room=Notifications message=Enormous starting time detected - 2093 color=RED notify=true&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;real-configuration&quot;&gt;Real configuration&lt;/h2&gt;

&lt;p&gt;L3rt didn’t send real messages, it printed debug information to the log. In order to send real messages, we have to configure targets.&lt;/p&gt;

&lt;p&gt;Let’s create a config file &lt;code class=&quot;highlighter-rouge&quot;&gt;./l3rt/conf.json&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;elasticSearch:http://elasticsearch:9200&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;targetSettings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mailServer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;host&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;smtp.gmail.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;port&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;465&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;auth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;myemail@test.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hipchat&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;accessToken&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;baseUrl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://api.hipchat.com/v2/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And modify compose file as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;  &lt;span class=&quot;nx&quot;&gt;l3rt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dimafeng&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l3rt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;8080:8080&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;networks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elk&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l3rt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;conf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l3rt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we can restart all services and start from the beginning - load some rules and run the rule. If all have been configured correctly, you’ll get real notifications to your email and hipchat room. You also can remove the &lt;code class=&quot;highlighter-rouge&quot;&gt;config&lt;/code&gt; section from the rule declaration since we have it in the permanent configuration file.&lt;/p&gt;

&lt;h2 id=&quot;rule-execution-metadata&quot;&gt;Rule execution metadata&lt;/h2&gt;

&lt;p&gt;The last thing we haven’t accomplished yet is preventing the rule to retrieve the same data each execution. If you take a look at the &lt;code class=&quot;highlighter-rouge&quot;&gt;query&lt;/code&gt;, you’ll notice that each time this rule is executed, the same query is generated, hence each 5 seconds you’ll be receiving the same messages. To ignore old results, we have to explicitly specify what ElasticSearch records should not be taken into account. This can be achieved by using &lt;code class=&quot;highlighter-rouge&quot;&gt;lastSeenTimestamp&lt;/code&gt;. It’s a variable that is available within the rule which contains the last timestamp seen during the previous rule execution.&lt;/p&gt;

&lt;p&gt;The final rule would look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ruleName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;myTestRule&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;index:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;logstash-*&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            
            &lt;span class=&quot;nl&quot;&gt;query:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;nl&quot;&gt;query:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                            &lt;span class=&quot;nl&quot;&gt;bool:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                                &lt;span class=&quot;nl&quot;&gt;must:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                                        &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;range&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@timestamp&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;gt&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastSeenTimestamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]]],&lt;/span&gt;
                                        &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;match&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Service started&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;
                                    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                        &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;reaction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;forEach&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;(?s).*Service started in (\\d*).*&quot;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;replaceAll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;\$1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toInteger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;devops@company.com&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Enormous starting time&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${it.data.get(&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@timestamp&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;)}: Enormous starting time detected - ${startTime}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;hipchat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Notifications&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Enormous starting time detected - ${startTime}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;RED&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;devops@company.com&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Starting time warning&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${it.data.get(&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@timestamp&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;)}: Starting time is out of normal - ${startTime}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;running-the-rule-in-background&quot;&gt;Running the rule in background&lt;/h2&gt;

&lt;p&gt;Since we have our rule done, we would want to start using it in background. To do so, we just need to save the rule. Click save button and type a name. That’s it! Now the rule will be executed automatically in background by timer (by default, each 5 seconds)&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;If you practice Infrastructure-As-Code approach, you would probably prefer to mount existing folder with rules to your container. It’s easy to do - just mount it to &lt;code class=&quot;highlighter-rouge&quot;&gt;/l3rt/rules/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Take a look at other rules. For now, I have got just one more - &lt;a href=&quot;https://github.com/l3rt/l3rt/blob/master/docs/elasticsearchCountRule.md&quot;&gt;Count Rule&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/l3rt/l3rt&quot;&gt;Contribute your fixes or features&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the configured docker compose file used in the article in &lt;a href=&quot;https://github.com/l3rt/docker-elk&quot;&gt;this github project&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Sun, 24 Sep 2017 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2017/09/24/alerting/</link>
        <guid isPermaLink="true">http://dimafeng.com/2017/09/24/alerting/</guid>
        
        
        <category>docker,</category>
        
        <category>scala,</category>
        
        <category>elk,</category>
        
        <category>elasticsearch,</category>
        
        <category>logstash</category>
        
      </item>
    
      <item>
        <title>Pragmatic view of the modern front-end application development</title>
        <description>&lt;p&gt;I wrote several posts about the way I build back-end applications using Scala and today it’s time to show you
what modern front-end application may look like from a pragmatic point  of view. Why do I call this &lt;em&gt;pragmatic&lt;/em&gt;? Because I consider myself as a full-stack engineer so I prefer more mature approaches rather than &lt;a href=&quot;https://en.wikipedia.org/wiki/Bleeding_edge_technology&quot;&gt;&lt;em&gt;the bleeding edge&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;disclaimer&quot;&gt;
&lt;h1&gt;Disclaimer&lt;/h1&gt;
This article is intended to be read by full-stack engineers or inexperienced front-end developers. Front-end experts may find this article outdated.
&lt;/div&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;h1&gt;Note&lt;/h1&gt;
The project described in this article &lt;strong&gt;&lt;a href=&quot;https://github.com/dimafeng/typescript-react-mobx-template&quot;&gt;is available on my GitHub profile&lt;/a&gt;&lt;/strong&gt;.
&lt;/div&gt;

&lt;p&gt;I had been using multiple approaches since I started writing web applications until I came up with the current one. The evolution of techniques I was following was like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pure JS -&amp;gt; JQuery -&amp;gt; Vaadin -&amp;gt; AngularJS -&amp;gt; (current approach)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All of these approaches were big steps  in relation to previous ones, but they still had a lot of downsides. The main disadvantage of most of them is a high support cost (this doesn’t apply to Vaadin, but it has its own kinds of problems).&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#what-a-modern-web-application-is&quot; id=&quot;markdown-toc-what-a-modern-web-application-is&quot;&gt;What a modern web application is&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#project-structure&quot; id=&quot;markdown-toc-project-structure&quot;&gt;Project structure&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#dependency-management&quot; id=&quot;markdown-toc-dependency-management&quot;&gt;Dependency management&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#typescript&quot; id=&quot;markdown-toc-typescript&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#webpack&quot; id=&quot;markdown-toc-webpack&quot;&gt;Webpack&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#linting&quot; id=&quot;markdown-toc-linting&quot;&gt;Linting&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#build-steps&quot; id=&quot;markdown-toc-build-steps&quot;&gt;Build steps&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#projects-stack&quot; id=&quot;markdown-toc-projects-stack&quot;&gt;Project’s stack&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#reactjs&quot; id=&quot;markdown-toc-reactjs&quot;&gt;React.js&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#communication-with-a-backend-api&quot; id=&quot;markdown-toc-communication-with-a-backend-api&quot;&gt;Communication with a backend API&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#mobx&quot; id=&quot;markdown-toc-mobx&quot;&gt;MobX&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#dependency-injection&quot; id=&quot;markdown-toc-dependency-injection&quot;&gt;Dependency Injection&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#testing&quot; id=&quot;markdown-toc-testing&quot;&gt;Testing&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#dev-tools&quot; id=&quot;markdown-toc-dev-tools&quot;&gt;Dev Tools&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#wrapping-up&quot; id=&quot;markdown-toc-wrapping-up&quot;&gt;Wrapping up&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-a-modern-web-application-is&quot;&gt;What a modern web application is&lt;/h2&gt;

&lt;p&gt;The JavaScript world is the most dynamic and fast growing environment and therefore what I’m saying today will be quite outdated tomorrow and absolutely useless in a week. But there are some stable trends which will be relevant for a longer period of time.&lt;/p&gt;

&lt;p&gt;Per my understanding, a modern web app today should:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Be a Single Page Application.&lt;/li&gt;
  &lt;li&gt;Use dependencies (no manual copying of js files to the &lt;code class=&quot;highlighter-rouge&quot;&gt;/js&lt;/code&gt; folder, the same is applicable to css).&lt;/li&gt;
  &lt;li&gt;Have automatic packaging. A resulted js should only have code that is used (not entire &lt;code class=&quot;highlighter-rouge&quot;&gt;node_module&lt;/code&gt; with all dependencies).&lt;/li&gt;
  &lt;li&gt;Allow you to write in latest JS versions (&amp;gt;=ES6) or TypeScript and produce ES5/ES6 compatible code.&lt;/li&gt;
  &lt;li&gt;Provide you with browser auto-reload in the &lt;em&gt;dev mode&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Conduct type checking.&lt;/li&gt;
  &lt;li&gt;Allow writing unit tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, I’m going to show you how you can achieve all these goals on the example of a real application.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/react/typescript-template.gif&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;project-structure&quot;&gt;Project structure&lt;/h2&gt;

&lt;h3 id=&quot;dependency-management&quot;&gt;Dependency management&lt;/h3&gt;

&lt;p&gt;The time when it’s ok to copy js files into &lt;code class=&quot;highlighter-rouge&quot;&gt;/js&lt;/code&gt; folder has come and gone. Now all libraries you may want to use are stored on &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npmjs.com&lt;/a&gt;. To start working with it, you need to install &lt;a href=&quot;https://nodejs.org/en/download/&quot;&gt;node and npm&lt;/a&gt; or &lt;a href=&quot;https://yarnpkg.com/lang/en/docs/install/&quot;&gt;yarn&lt;/a&gt; (&lt;strong&gt;yarn&lt;/strong&gt; is an &lt;em&gt;npm&lt;/em&gt; alternative that claims that it provides faster and more reliable user experience while preserving npm file/command format).&lt;/p&gt;

&lt;p&gt;It used to be popular to use &lt;strong&gt;Bower&lt;/strong&gt; as a client-side application dependency manager, but it now seems &lt;strong&gt;Bower&lt;/strong&gt; is dying so &lt;strong&gt;npm/yarn&lt;/strong&gt; is more preferable way.&lt;/p&gt;

&lt;p&gt;The entry point to an &lt;strong&gt;npm&lt;/strong&gt; project is &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;typescript-react-template&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;dev&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;lint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;jest&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;jest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;strong&gt;dependencies&lt;/strong&gt; section defines what libraries will be available in the application scope. An actual dependency looks like this &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;react&quot;: &quot;15.4.2&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;h1&gt;Note&lt;/h1&gt;
By default, the '--save' npm flag saves all versions in the &lt;a href=&quot;https://docs.npmjs.com/misc/semver&quot;&gt;caret range&lt;/a&gt; syntax. This is a bad practice in the Java world although this is a common practice in the JS world. This may cause random build failures and that’s why I prefer the fixed version notation.
&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;devDependencies&lt;/strong&gt; section covers all dependencies used during build/test/etc.&lt;/p&gt;

&lt;p&gt;After you have &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; configured, you can execute &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install&lt;/code&gt;. This will download all dependencies from &lt;strong&gt;npmjs.com&lt;/strong&gt; and put into the &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; folder.&lt;/p&gt;

&lt;h3 id=&quot;typescript&quot;&gt;TypeScript&lt;/h3&gt;

&lt;p&gt;Since I wanted to have a more supportable and predictable codebase, I found TypeScript very helpful. TypeScript is a typed superset of JavaScript. It means that you write JavaSript as you did before but you have the ability to optionally specify types in your code, as well as to have all external libraries to be typed. Moreover, since the code is typed, IDEs can do smarter autocompletion and help with refactoring. All type errors will be shown during the transpilation process.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/react/type-error.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;To make it work you need to have the TypeScript compiler in your devDependencies and compiler configuration as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;commonjs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;es5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;jsx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;sourceMap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;emitDecoratorMetadata&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;experimentalDecorators&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;noUnusedLocals&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;noUnusedParameters&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;outDir&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dist&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;typeRoots&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;node_modules/@types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;exclude&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;dist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;node_modules&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;build&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is a typical configuration that transpiles TypeScript to JavaScript (ES5 standard which is supportable by most popular browsers).&lt;/p&gt;

&lt;p&gt;In order to use external dependencies in a typed way, you need to find and put a typing file (&lt;code class=&quot;highlighter-rouge&quot;&gt;*.d.ts&lt;/code&gt;) inside your project for each dependency that is used from your code. Some libraries have built-in typings, but for those that don’t, there is a repository with community driven typings for hundreds of libraries. All these typings are available in the NPM with a prefix &lt;code class=&quot;highlighter-rouge&quot;&gt;@types/&lt;/code&gt; e.g. typings for &lt;code class=&quot;highlighter-rouge&quot;&gt;react&lt;/code&gt; are &lt;code class=&quot;highlighter-rouge&quot;&gt;@types/react&lt;/code&gt; so you can install it as follows: &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install --save react @types/react&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If everything is configured correctly, you can compile your project from the command line by using &lt;code class=&quot;highlighter-rouge&quot;&gt;tsc&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;webpack&quot;&gt;Webpack&lt;/h3&gt;

&lt;p&gt;Now we have all dependencies and our code base and we need to do ‘something’ in order to produce resulting js and css files. There used to be a couple of standard approaches to do that ‘something’ - Grunt and Gulp. Both of them knew where your sources and dependencies are and then were able to concatenate all of it and put to a &lt;code class=&quot;highlighter-rouge&quot;&gt;dist&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Then &lt;a href=&quot;https://webpack.github.io/&quot;&gt;wepback&lt;/a&gt; came to the scene. The main idea of it is to have a declarative configuration that knows only where your sources are and is able to understand what dependencies (not only JavaScript) are used in the code. Knowing all of that, webpack can produce more compact resulting bundles with fewer efforts. As a bonus, it has a built-in auto-reload server.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/react/what-is-webpack.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;When I say declarative, I mean something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;__dirname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/app&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;__dirname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/dist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bundle.js&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And it’s all you need to write to glue all js files starting with &lt;code class=&quot;highlighter-rouge&quot;&gt;./index.js&lt;/code&gt; and going deeper to its dependencies.&lt;/p&gt;

&lt;p&gt;Webpack works with loaders. Since we want to write code in TypeScript we need to setup the following loader &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install --save-dev ts-loader&lt;/code&gt; and add the following object to the webpack config.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nl&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;ts|tsx&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node_modules&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bower_components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;loaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'react-hot-loader/webpack'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ts-loader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This loader will be using the configuration we defined in the &lt;strong&gt;TypeScript&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;Usually, when you write web applications you would want to have two different scenarios - development and production. A development one should support hot code reload, produce unminified js with source maps and have some dev-specific flags, while a production scenario is intended to be used as a final bundle packager. To achieve this goal, you can create multiple configs with a shared common part. Since Webpack is run on &lt;strong&gt;node.js&lt;/strong&gt; you can treat its configs as regular javascript code so that you create a common part as an exported js object and then merge it with production and development ones using the plugin &lt;code class=&quot;highlighter-rouge&quot;&gt;webpack-merge&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;linting&quot;&gt;Linting&lt;/h3&gt;

&lt;p&gt;When you collaborate with other people, you want to keep your code style consistent. Also, it’s good to have some automated tool that can check common anti-patterns and errors. All these checks are provided by &lt;a href=&quot;https://github.com/palantir/tslint&quot;&gt;tslint&lt;/a&gt;. It can be installed from NPM as follows &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install --save-dev tslint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are a bunch of built-in rules that you can work with out of the box. To start using it, you just need a config file that may look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;class-name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;comment-format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;check-space&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;indent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;spaces&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;no-duplicate-variable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;no-eval&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;jsx-self-close&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;rulesDirectory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;node_modules/tslint-react/rules&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now you can run tslint checks within your codebase &lt;code class=&quot;highlighter-rouge&quot;&gt;tslint &quot;src/**/*.ts*&quot;&lt;/code&gt; (to make &lt;code class=&quot;highlighter-rouge&quot;&gt;tslint&lt;/code&gt; executable you need to install it globally). This already is quite good but we’ll configure it to not execute this command manually. This can be done by webpack’s loader. In order to do it, you need to install &lt;code class=&quot;highlighter-rouge&quot;&gt;tslint-loader&lt;/code&gt; as a dev dependency and configure it in the webpack configuration:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;preLoaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;ts&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;tslint&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, each compile process will be prepended by tslint check and you’ll see all errors and warnings as soon as you save the source file.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/react/tslint.png&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;build-steps&quot;&gt;Build steps&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; is quite limited in imperative task declaration - you can’t specify complex logic of your build steps. The only you can do is define commands that should be executed. It’s not powerfull but at least you don’t need to remember all application lifecycle commands.&lt;/p&gt;

&lt;p&gt;Usually, I have these four scripts:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;NODE_ENV=production webpack -p --config webpack.production.config.js --progress --profile --colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;dev&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;webpack-dev-server --progress --profile --colors --hot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;lint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;tslint &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;src/**/*.ts*&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;jest&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;build&lt;/strong&gt; produces production-ready bundles that you can distribute as is.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;dev&lt;/strong&gt; starts dev server.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;lint&lt;/strong&gt; checks the codebase using linters.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;test&lt;/strong&gt; launches unit tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To start any of the scripts, you can run &lt;code class=&quot;highlighter-rouge&quot;&gt;npm&lt;/code&gt; with the following arguments &lt;code class=&quot;highlighter-rouge&quot;&gt;npm run [script name]&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;projects-stack&quot;&gt;Project’s stack&lt;/h2&gt;

&lt;p&gt;One year ago I wrote a &lt;a href=&quot;/2015/11/16/clojurescript-om/&quot;&gt;post&lt;/a&gt; about &lt;strong&gt;om&lt;/strong&gt; (clojurescrit library based on react.js). Now it’s time to bring React.js to a real life project in the enterprise-ish world.&lt;/p&gt;

&lt;h3 id=&quot;reactjs&quot;&gt;React.js&lt;/h3&gt;

&lt;p&gt;I think there’s no need to describe what React.js is. This framework if pretty popular right now and has a lot of hype around it. TypeScript fully supports JSX so you can write React components and benefit from type checking. A typical component may look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Props&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UserView&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now if you try to use it with an incorrect type (e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;UserView userId={1} /&amp;gt;&lt;/code&gt;) you would get a type check error.&lt;/p&gt;

&lt;h3 id=&quot;communication-with-a-backend-api&quot;&gt;Communication with a backend API&lt;/h3&gt;

&lt;p&gt;I liked the idea of using &lt;strong&gt;rx.js&lt;/strong&gt; instead of promises. An HTTP client on top of &lt;strong&gt;rx.js&lt;/strong&gt; was introduced by &lt;strong&gt;angular 2&lt;/strong&gt; and I found it very useful. It looks like you work with promises when you have simple scenarios and brings all the power when you need to deal with dependent requests, delayed execution, execution timeouts, etc.&lt;/p&gt;

&lt;p&gt;I use a library called &lt;a href=&quot;https://github.com/FundCount/ts-rx-rest&quot;&gt;ts-rx-rest&lt;/a&gt; which I contribute to. Basically, it’s a typed HTTP client with an &lt;strong&gt;rx.js&lt;/strong&gt; interface and it does’t make you follow any particular approach – you can use it in any typescript project. Usually I put all HTTP related code to separate stateless *Service classes so it can be mocked in unit tests.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UserService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;getUsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doGet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;API_URL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/users'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now let’s assume you need to load a user profile with permission list for his group. If you’re waiting too long for any of these two requests then we want just to show an error.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userPermissions$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;permissionsService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getPermissions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userPermissions$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userPermissions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// process 'user' and 'userPermissions'&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// process errors&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This looks very clear, doesn’t it?&lt;/p&gt;

&lt;h3 id=&quot;mobx&quot;&gt;MobX&lt;/h3&gt;

&lt;p&gt;When I just started using React.js I was trying to use pure components and manage their state manually via &lt;code class=&quot;highlighter-rouge&quot;&gt;setState&lt;/code&gt; but this approach is not scalable. Then I found &lt;a href=&quot;https://github.com/reactjs/redux&quot;&gt;redux&lt;/a&gt;, redux looks very promising? but there’s one big problem - it’s way too verbose. In the meanwhile, my co-worker had found &lt;a href=&quot;https://github.com/mobxjs/mobx&quot;&gt;MobX&lt;/a&gt; and it had become a relief.&lt;/p&gt;

&lt;p&gt;Now I split all TypeScript code into three types of components:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;React component&lt;/strong&gt; - JSX component with no state management&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Store&lt;/strong&gt; - component’s state&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Service&lt;/strong&gt; - stateless HTTP API layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React components are only responsible for rendering – they know nothing about the state. All state management is located in stores as well as event reactions (e.g. button clicks, input value changes, etc).&lt;/p&gt;

&lt;p&gt;MobX introduces two main roles of components: observer and observable. An observer is an object whose state changes should be tracked by observers. In our case, a react.js component is an observer that is re-rendered once a state of the observables (only those that are used in the &lt;code class=&quot;highlighter-rouge&quot;&gt;render()&lt;/code&gt; method) has been updated. It may look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UserViewStore&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;observable&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;//...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;observer&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UsersView&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Props&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

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

  &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;}&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When you change &lt;code class=&quot;highlighter-rouge&quot;&gt;users&lt;/code&gt; by adding/removing a value to/from the array or assign a new array to the variable, &lt;code class=&quot;highlighter-rouge&quot;&gt;UsersView&lt;/code&gt; will be re-rendered automatically.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;h1&gt;Note&lt;/h1&gt;
If you need to update multiple variables consequently or do multiple changes to an array, you need to think of atomicity of the re-rendering because each update will cause virtual DOM recalculation.
In these cases, you need to use the &lt;a href=&quot;https://mobx.js.org/refguide/action.html&quot;&gt;runInAction&lt;/a&gt; wrapper function.
&lt;/div&gt;

&lt;h3 id=&quot;dependency-injection&quot;&gt;Dependency Injection&lt;/h3&gt;

&lt;p&gt;MobX provides you with build-in Dependency Injection functionality but it only works with react.js components. When you have multiple stores which depend on each other, you would like to have an ability to inject stores to other stores as well as to inject stores to react.js components. I haven’t found any libraries that solve this problem so that I wrote my own solution:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diInject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;propertyKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;propertyKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bean&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;diContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;propertyKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Context has no bean with name &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;propertyKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.
                    Available beans: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getOwnPropertyNames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;diContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;', '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Not allowed'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;enumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;configurable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This injection decorator uses globally defined &lt;code class=&quot;highlighter-rouge&quot;&gt;diContext&lt;/code&gt; and is able to dynamically inject objects from &lt;code class=&quot;highlighter-rouge&quot;&gt;diContext&lt;/code&gt; by name.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;diContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;userService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UserService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UserViewStore&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;diInject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UserService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;

&lt;p&gt;You can’t deliver reliable software without testing nowadays. It used to be extremely difficult to test javascript but now you can run unit tests in node.js or in a browser very easy. I prefer using &lt;a href=&quot;https://facebook.github.io/jest/&quot;&gt;jest&lt;/a&gt;. The main advantage is that &lt;strong&gt;jest&lt;/strong&gt; is a &lt;em&gt;Zero configuration testing platform&lt;/em&gt; – it just works, moreover it works with TypeScript.&lt;/p&gt;

&lt;p&gt;To start, we need to install &lt;strong&gt;jest&lt;/strong&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install --save-dev jest-cli @types/jest&lt;/code&gt;, then add this small config object to &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;jest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;moduleFileExtensions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;tsx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;js&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;testRegex&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/__tests__/.*&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.(ts|tsx|js)$&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now ready to go!&lt;/p&gt;

&lt;p&gt;Beside &lt;strong&gt;jest&lt;/strong&gt;, I am going to use &lt;a href=&quot;https://github.com/florinn/typemoq&quot;&gt;typemoq&lt;/a&gt;, a mocking library for typescript: &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install --save-dev typemoq&lt;/code&gt;. Let’s look at some tests. Per our configuration, tests should reside in &lt;code class=&quot;highlighter-rouge&quot;&gt;./__tests__/&lt;/code&gt;. Here is an example of a test that works with a store.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'UserViewStore should be filled with data'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userServiceMock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TypeMoq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ofType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UserService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;userServiceMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;just&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]));&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;diContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;userService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userServiceMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UserViewStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, we prepared a service layer so that it doesn’t make a request to the real backend. Instead, it works with &lt;code class=&quot;highlighter-rouge&quot;&gt;Observable.just&lt;/code&gt; that just executes its body right away. After that, we validate the state of the store with a built-in chain &lt;code class=&quot;highlighter-rouge&quot;&gt;expect(...).toEqual(...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That looks great, doesn’t it? Want more? Due to a functional nature of react, we can easily test JSX output. Since we don’t use react component’s state, we just need to explicitly define stores’ state. Then we can calculate the virtual DOM and compare it with a snapshot. The snapshot creation and comparison is a built-in feature of &lt;strong&gt;jest&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'UsersView should render proper DOM'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;user1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;user2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;test2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;test2&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userStoreMock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TypeMoq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ofType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UserStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userViewStoreMock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TypeMoq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ofType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UserViewStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;userStoreMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createUserViewStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userViewStoreMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;userViewStoreMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;diContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;userStore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userStoreMock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UsersView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/Router&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;.toJSON&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;.toMatchSnapshot&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The first run of the test (&lt;code class=&quot;highlighter-rouge&quot;&gt;npm run test&lt;/code&gt;) will generate a snapshot, that will be treated as the correct value, further runs will just compare produced DOM with a snapshot.&lt;/p&gt;

&lt;h3 id=&quot;dev-tools&quot;&gt;Dev Tools&lt;/h3&gt;

&lt;p&gt;When you write real applications at work you would like to be productive as more as you can. Fortunately, there are multiple tools can help to achieve it.&lt;/p&gt;

&lt;p&gt;Since we’re using &lt;strong&gt;webpack&lt;/strong&gt;, there is a built-in browser page refresher. All you need to do it to run &lt;code class=&quot;highlighter-rouge&quot;&gt;npm run dev&lt;/code&gt;. After each change, your page will be auto-refreshed.&lt;/p&gt;

&lt;p&gt;The next tool that saves your life is Google Chrome Dev Tools and plugins. First of all, Dev Tools simplifies life by providing DOM navigator, network monitoring tools, debugger, profiler, etc. You can debug your TypeScript code without any additional extensions - it just works. If you need more advanced tools, you can take a look at &lt;a href=&quot;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?utm_source=gmail&quot;&gt;React Developer Tools&lt;/a&gt;. It is a google chrome extension that can show a virtual DOM with all its attributes. Sometimes, it’s very helpful to check what is the current virtual DOM and how it relates to real DOM.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/react/react_dev_tool.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Another helpful extension is &lt;a href=&quot;https://chrome.google.com/webstore/detail/mobx-developer-tools/pfgnfdagidkfgccljigdamigbcnndkod?hl=en&quot;&gt;MobX Developer Tools&lt;/a&gt;. This extension is toolset that exposes &lt;strong&gt;MobX&lt;/strong&gt;’s magic. It can show DOM re-rendering, actions and reactions, observable changes, etc.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;/assets/react/mobx-dev-tools.gif&quot; /&gt;
&lt;/div&gt;

&lt;h1 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h1&gt;

&lt;p&gt;There is no one proper way to create applications in the JS world. The JS environment is extremely dynamic – every day you can find a new library that simplifies or improves some aspects of application development. I described my current approach and I have to doubt that in several months 50% of described techniques will be rethought and it will a new article in my blog.&lt;/p&gt;

</description>
        <pubDate>Sun, 23 Apr 2017 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2017/04/23/modern-frontend/</link>
        <guid isPermaLink="true">http://dimafeng.com/2017/04/23/modern-frontend/</guid>
        
        
        <category>react.js,</category>
        
        <category>typescript,</category>
        
        <category>mobx,</category>
        
        <category>rx,</category>
        
        <category>rx.js</category>
        
      </item>
    
      <item>
        <title>5 drawbacks to liking SBT</title>
        <description>&lt;p&gt;I have an opensource project written in scala called &lt;a href=&quot;https://github.com/dimafeng/testcontainers-scala&quot;&gt;testcontainers-scala&lt;/a&gt; (if your heart beats faster when you hear &lt;em&gt;docker&lt;/em&gt;, be sure to click on the link). Several days ago I received a pull request that adds scala 2.12 support to my project. Sounds great, right? But unfortunately that broke scala 2.11’s compatibility. To solve this issue, there is a quite standard solution in the scala world - &lt;a href=&quot;http://www.scala-sbt.org/0.13/docs/Cross-Build.html&quot;&gt;Cross-building&lt;/a&gt;. I hadn’t had much experience with
&lt;strong&gt;SBT&lt;/strong&gt; by that time and I had decided to give a try. In this post I’m going to show you what came of this.&lt;/p&gt;

&lt;p&gt;In the comments on Reddit for &lt;a href=&quot;/2016/08/01/testcontainers-selenium/&quot;&gt;my article about integration testing&lt;/a&gt; in scala, somebody said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Even though I “use” sbt I wouldn’t exactly say I know to use it. All I do is copy and paste crap for the most part.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I spent two days trying to replicate the functionality of my &lt;a href=&quot;https://github.com/dimafeng/testcontainers-scala/blob/948f3ebcf9043ddf07e823d7fd9a831b1dbd080a/build.gradle&quot;&gt;Gradle script&lt;/a&gt; using this &lt;em&gt;“copy and paste crap”&lt;/em&gt; approach. I briefly read the official documentation, reviewed a lot of stackoverflow threads and after all I lost hope. Here’s why:&lt;/p&gt;

&lt;h2 id=&quot;1-speed&quot;&gt;1. Speed&lt;/h2&gt;

&lt;p&gt;SBT is super slow. Each time I run tests there were several preparation steps that were downloading and checking some random things.
Subjectively, everything took at least 1.5 times more time than it took in the Gradle script (especially using the &lt;a href=&quot;https://docs.gradle.org/current/userguide/gradle_daemon.html&quot;&gt;Gradle daemon&lt;/a&gt;).&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;http://i.giphy.com/3o6MbnqLhX5tJ5wNQQ.gif&quot; /&gt;
&lt;/p&gt;

&lt;h2 id=&quot;2-project-properties&quot;&gt;2. Project properties&lt;/h2&gt;

&lt;p&gt;My gradle script reads properties from file and It’s even a &lt;a href=&quot;https://docs.gradle.org/current/userguide/build_environment.html&quot;&gt;built-in Gradle feature&lt;/a&gt;. I have two properties files: a local one that is stored along with the project and a global one located in &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.gradle&lt;/code&gt;. If I want to override some property for a particular run, I can use &lt;code class=&quot;highlighter-rouge&quot;&gt;-D&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;-P&lt;/code&gt; command line options.&lt;/p&gt;

&lt;p&gt;I needed the same in SBT. I googled it - &lt;a href=&quot;http://stackoverflow.com/questions/25665848/how-to-load-setting-values-from-a-java-properties-file&quot;&gt;this is what I found&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.Properties&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;appProperties&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settingKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Properties&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;The application properties&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;appProperties&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Properties&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;application.properties&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;prop&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;appProperties&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getProperty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Really? What do I do if I want to have both a local file for versions and a global one for my private data? What do I do if I want to override it via a command line option? - Code it!&lt;/p&gt;

&lt;h2 id=&quot;3-test-exclusion&quot;&gt;3. Test exclusion&lt;/h2&gt;

&lt;p&gt;I have two type of tests: unit and integration. &lt;strong&gt;Because the code base of the project is really small, I keep all of them in one sourceset &lt;code class=&quot;highlighter-rouge&quot;&gt;src/test/scala&lt;/code&gt;&lt;/strong&gt; (I know - I know, it’s not a good practice). But I cannot run integration tests every time I start a &lt;code class=&quot;highlighter-rouge&quot;&gt;test&lt;/code&gt; task because &lt;strong&gt;Travis-ci&lt;/strong&gt; doesn’t allow me to run docker in my tests. In my gradle script, I do a simple trick:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;exclude&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'com/dimafeng/testcontainers/integration/**'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;integrationTest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'com/dimafeng/testcontainers/integration/**'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It’s very simple and clear. If I had a bigger codebase I could also do:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Add an extra sourceset&lt;/li&gt;
  &lt;li&gt;Create a sub-module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What do we have in SBT? - Tags. Ok, I found some examples &lt;a href=&quot;http://www.scalatest.org/user_guide/using_scalatest_with_sbt&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://stackoverflow.com/questions/10302458/excluding-a-scalatest-test-when-calling-my-tests-from-within-sbt&quot;&gt;here&lt;/a&gt;. Also, we need to modify a task &lt;code class=&quot;highlighter-rouge&quot;&gt;test&lt;/code&gt; to make it exclude these tests and create a new one which works with only these. Here’s the &lt;a href=&quot;http://www.scala-sbt.org/0.13/docs/Testing.html&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;http://i.giphy.com/3o7TKrau6cMz9BhKRa.gif&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;Wait, I’m lost, how to glue all of the pieces together? Where to find the missing ones?&lt;/p&gt;

&lt;p&gt;Maybe I can configure an additional sourceset or create a sub-module? - Yes, but you’ll have to read the entire &lt;em&gt;“spaceship manual”&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;4-publishing-to-maven-central&quot;&gt;4. Publishing to maven central&lt;/h2&gt;

&lt;p&gt;My library should be published to maven central to be accessible by all build tools. I found a documentation - &lt;a href=&quot;http://www.scala-sbt.org/0.13/docs/Publishing.html&quot;&gt;Publishing&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There are two ways to specify credentials for such a repository. The first is to specify them inline:
…
The second and better way is to load them from a file, for example:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Credentials&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userHome&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.ivy2&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.credentials&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Wait, I thought there are no built-in tools to work with properties files. Oh, that works for credentials only.&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;http://i.giphy.com/l0MYrXilD8grSUNB6.gif&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;I think I can live with that. What next? I need to sign my binaries. So here’s my signing key. Where to put it?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: While it is general practice to drop the higher-order bits of 64-bit integer keys when passing ids around, the PGP plugin requires the full key id currently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not a problem - &lt;code class=&quot;highlighter-rouge&quot;&gt;gpg --keyid-format LONG -k&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;usePgpKeyHex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;7cf8d72be29df322&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But I want to read my key from the properties file like this &lt;code class=&quot;highlighter-rouge&quot;&gt;usePgpKeyHex(appProperties.value.getProperty(&quot;signing.password&quot;))&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;
build.sbt:82: error: `value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.
usePgpKeyHex(appProperties.value.getProperty(&quot;signing.password&quot;))
                           ^
[error] Type error in expression
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?
&lt;/pre&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;http://i.giphy.com/3o85xI1DBa3XAsOUxO.gif&quot; /&gt;
&lt;/p&gt;

&lt;h2 id=&quot;5-releasing&quot;&gt;5. Releasing&lt;/h2&gt;

&lt;p&gt;I don’t like to keep complex manual procedures in mind - I automate everything. In Gradle, I have a &lt;a href=&quot;https://github.com/researchgate/gradle-release&quot;&gt;release plugin&lt;/a&gt;. It’s very simple and flexible. What it does:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Asks what version to release and updates the current version in the project properties&lt;/li&gt;
  &lt;li&gt;Tags the current git commit&lt;/li&gt;
  &lt;li&gt;Pushes the commits to upstream&lt;/li&gt;
  &lt;li&gt;Using gradle task dependencies, builds project, runs tests, uploads archives&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./gradlw release&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s it. It can’t be easier. What we have in SBT? - &lt;a href=&quot;http://blog.byjean.eu/2015/07/10/painless-release-with-sbt.html&quot;&gt;Painless release with SBT&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait, do I need to write more code than I have in my libriry just to release? I’m not even sure that it can be blended with code I wrote on the previous steps - I don’t even want to try otherwise I’ll have to be debugging it for new two days. Let’s leave it in the old-fashioned way - manually.&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;http://i.giphy.com/CmFMWpEa4IFtS.gif&quot; /&gt;
&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;After two days I gave up. I didn’t find any features in SBT which I don’t have in Gradle. Afterwards, I implemented cross-building in my gragle scripts. It’s less elegant but works well and doesn’t break all what I had before.&lt;/p&gt;

&lt;p&gt;As for SBT, &lt;a href=&quot;https://www.reddit.com/r/scala/comments/5a6muj/sbt_makes_me_want_to_give_up_scala/&quot;&gt;It seems&lt;/a&gt; I’m not the only one who struggles with it. I think, a build tool shouldn’t be so complex and counter-intuitive. The lack of good documentation and good examples makes the quick start quite impossible. You can just sit and copy and paste from documentation and have something working in a few hours. All you need to do is dig and pray so that in 10 years you’ll be lucky to get a &lt;em&gt;“Ph.D. in SBT”&lt;/em&gt;. The current state of SBT doesn’t look mature, all standard procedures which are built-in to maven or Gradle should be coded by yourself.&lt;/p&gt;

&lt;p&gt;So, I’ll stick with Gradle.&lt;/p&gt;

</description>
        <pubDate>Wed, 04 Jan 2017 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2017/01/04/sbt/</link>
        <guid isPermaLink="true">http://dimafeng.com/2017/01/04/sbt/</guid>
        
        
        <category>scala,</category>
        
        <category>sbt,</category>
        
        <category>gradle</category>
        
      </item>
    
      <item>
        <title>Distributed systems cheat sheet</title>
        <description>&lt;p&gt;Since last year, I’ve been dealing with multiple distributed systems and suffering from a lack of structured understanding of how it all work under the hood. This post aims to break the subject down into small parts and
aggregate multiple sources and links I found useful. It covers mostly distributed data storage systems but some concepts may be applied to other types of systems.&lt;/p&gt;

&lt;div class=&quot;disclaimer&quot;&gt;
&lt;h1&gt;Disclaimer&lt;/h1&gt;
I'm not an expert in distributed systems. This blog post reflects my current understanding of the subject.
If you find any mistakes, you're welcome to leave comments.
&lt;/div&gt;

&lt;h2&gt;What a distributed system is&lt;/h2&gt;

&lt;p&gt;A distributed system is a software working on multiple computers/VMs/containers (further in this article I’ll call all of this a &lt;strong&gt;node&lt;/strong&gt;) and communicating with each other via network interfaces. It helps solving scalability and reliability problems by using the following techniques:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Data replication&lt;/strong&gt;  is copying of data to multiple nodes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Data partitioning&lt;/strong&gt; is when data is divided into N parts and processed separately on several nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive into this more deeper:&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#physical-factors&quot; id=&quot;markdown-toc-physical-factors&quot;&gt;Physical factors&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#time-and-order&quot; id=&quot;markdown-toc-time-and-order&quot;&gt;Time and Order&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cap&quot; id=&quot;markdown-toc-cap&quot;&gt;CAP&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#consistency&quot; id=&quot;markdown-toc-consistency&quot;&gt;Consistency&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#replication&quot; id=&quot;markdown-toc-replication&quot;&gt;Replication&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#synchronicity&quot; id=&quot;markdown-toc-synchronicity&quot;&gt;Synchronicity&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#synchronous&quot; id=&quot;markdown-toc-synchronous&quot;&gt;Synchronous&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#asynchronous&quot; id=&quot;markdown-toc-asynchronous&quot;&gt;Asynchronous&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#semi-synchronous&quot; id=&quot;markdown-toc-semi-synchronous&quot;&gt;Semi-synchronous&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#node-relationship&quot; id=&quot;markdown-toc-node-relationship&quot;&gt;Node relationship&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#masterslave-single-copy&quot; id=&quot;markdown-toc-masterslave-single-copy&quot;&gt;Master/Slave (single copy)&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#multi-master&quot; id=&quot;markdown-toc-multi-master&quot;&gt;Multi-master&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#consensus&quot; id=&quot;markdown-toc-consensus&quot;&gt;Consensus&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#two-phase-commit&quot; id=&quot;markdown-toc-two-phase-commit&quot;&gt;Two-Phase commit&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#three-phase-commit&quot; id=&quot;markdown-toc-three-phase-commit&quot;&gt;Three-Phase commit&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#paxos&quot; id=&quot;markdown-toc-paxos&quot;&gt;Paxos&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#raft&quot; id=&quot;markdown-toc-raft&quot;&gt;RAFT&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#partitioning&quot; id=&quot;markdown-toc-partitioning&quot;&gt;Partitioning&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#horizontal-partitioning&quot; id=&quot;markdown-toc-horizontal-partitioning&quot;&gt;Horizontal partitioning&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#links&quot; id=&quot;markdown-toc-links&quot;&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;##Problems&lt;/p&gt;

&lt;p&gt;There are two different worlds - theoretical model and practical experience. They both don’t meet each other in most cases because these models describe a perfect environment, but there is an infinite number of problems that can cause a divergence.&lt;/p&gt;

&lt;h3 id=&quot;physical-factors&quot;&gt;Physical factors&lt;/h3&gt;

&lt;p&gt;All nodes are connected to each other via the network and due to the many factors, this doesn’t provide strong guarantees of data transferring and accessibility.
&lt;a href=&quot;https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing&quot;&gt;Fallacies of distributed computing&lt;/a&gt; explains it as follows: Network is not reliable. Packages may be lost, reordered, or received multiple times, with different non-zero delays and limited throughput of the network. Moreover, the topology of the network is not constant - it can be changed at any time intentionally or accidentally due to network failures, also nodes can crash or be rebooted.&lt;/p&gt;

&lt;h3 id=&quot;time-and-order&quot;&gt;Time and Order&lt;/h3&gt;

&lt;p&gt;When we have a sequence of events occurred in a distributed system, it’s important to know in what order they came.
We can’t rely on physical clocks because it’s always not perfectly synchronized. That’s why people came up with logical clocks.&lt;/p&gt;

&lt;p&gt;Logical clocks are not about actual time, it’s about an order of events, it’s also called a partial ordering. In this model, all events are connected by &lt;a href=&quot;https://en.wikipedia.org/wiki/Happened-before&quot;&gt;happens-before relation&lt;/a&gt;. There are two implementations of this model:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Lamport timestamps&lt;/li&gt;
  &lt;li&gt;Vector Clocks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a more &lt;a href=&quot;http://research.microsoft.com/en-us/um/people/lamport/pubs/time-clocks.pdf&quot;&gt;formal description of this concept&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;cap&quot;&gt;CAP&lt;/h3&gt;

&lt;p&gt;All problems described in previous two sections can be combined in one model called &lt;strong&gt;The CAP theorem&lt;/strong&gt;. It defines the relation between three properties:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Consistency&lt;/strong&gt;, guarantees that all nodes will see the same data representation;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Availability&lt;/strong&gt;, guarantees the fastest availability of the data ignoring its accuracy;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Partition tolerance&lt;/strong&gt;, the system survives network failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The theorem states that only two of these three can be chosen in the system. Knowing that the network with no failures and delays doesn’t exist, we have only two types of systems to choose: CP and AP. Although in the real world, popular distributed systems are neither CA nor AP because they &lt;a href=&quot;https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html&quot;&gt;can provide different guarantees on demand or weaker consistency guaranties or even loose availability/consistency under certain conditions&lt;/a&gt;. This brings us to the idea that the CAP theorem in most cases is a high-level abstraction that can’t be applied to the systems you write or use but can be a starting point for understanding more complex cases.&lt;/p&gt;

&lt;h3 id=&quot;consistency&quot;&gt;Consistency&lt;/h3&gt;

&lt;p&gt;It’s important to know that the &lt;strong&gt;Consistency&lt;/strong&gt; in the CAP theorem means strong consistency, specifically linearizability. But there are many different types of consistency.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Strong consistency&lt;/strong&gt; all nodes see the values in the same order
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Strict consistency:&lt;/em&gt; (impossible to implement in a distributed system) It orders all writes and reads relying on absolute global time.&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;Linearizability:&lt;/em&gt; the order of reads on all nodes matches the order of writes. A read can obtain the most recent applied value or a value that goes after it.&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;Sequential consistency:&lt;/em&gt; the order of reads doesn’t match the order of writes but is the same for all read operations.&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;Causal consistency:&lt;/em&gt; the order of reads of causally-related writes matches the writes order.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Weak consistency&lt;/strong&gt; the order of reads can differ
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Client-centric consistency:&lt;/em&gt; the client works with the distributed system through a cache or uses a session. Unless client writes then reads either through the same cache or session bound to the same node, all reads will be consistent, while other nodes can see an inconsistent state.&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;Eventual consistency:&lt;/em&gt; “It defines that if no update takes a very long time, all replicas eventually become consistent”&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are &lt;a href=&quot;http://www.cs.cmu.edu/~srini/15-446/S09/lectures/10-consistency.pdf&quot;&gt;useful slides&lt;/a&gt; about consistency models.&lt;/p&gt;

&lt;h2 id=&quot;replication&quot;&gt;Replication&lt;/h2&gt;

&lt;p&gt;Now we can take a look at more practical aspects of distributed systems. Let’s assume we have data stored in a system working on one node, now we want to have:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;fault-tolerant: if one node is down, another one can replace it&lt;/li&gt;
  &lt;li&gt;higher accessibility: if we have too many reads and clients are experiencing difficulties under high load, then we copy data to another node to spread the load&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both of these goals can be achieved by multiple approaches depending on more detailed requirements.&lt;/p&gt;

&lt;h3 id=&quot;synchronicity&quot;&gt;Synchronicity&lt;/h3&gt;

&lt;p&gt;The actual copying of the data during the replication can be conducted in several manners.&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;https://docs.google.com/drawings/d/1__xrsDKN3ST7gnQ8FWYMg3XTzVyxYch3gE3ooJnKOgY/pub?w=563&amp;amp;h=926&quot; /&gt;
&lt;/p&gt;

&lt;h4 id=&quot;synchronous&quot;&gt;Synchronous&lt;/h4&gt;

&lt;p&gt;When a client writes some data to the master node, the node accepts data and saves it to its own storage plus sends this data to all replicas. Once all replicas responded back with OK, the master node returns a response to the client. If data didn’t do through to any of replicas, the client will receive an error code - this guarantees data consistency.&lt;/p&gt;

&lt;p&gt;Since the master should wait the response from all of the nodes, a single write operation cannot be faster than the time of the slowest combination of &lt;em&gt;data write to a node&lt;/em&gt; + &lt;em&gt;network latency for this node&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When one of the nodes becomes inaccessible, the master stops accepting writes - all nodes are only available for reads.&lt;/p&gt;

&lt;h4 id=&quot;asynchronous&quot;&gt;Asynchronous&lt;/h4&gt;

&lt;p&gt;In this replication approach, a client receives response as soon as master thinks that the data has been handled by the master, the data copying to replicas is starting asynchronously. The client won’t be notified about copying failure. Asynchronous replication offers fewer guarantees but more faster writes from the client point of view.&lt;/p&gt;

&lt;p&gt;If the master goes down and some data hasn’t been properly delivered to the slaves, this data will be lost even though the client is aware of data write.&lt;/p&gt;

&lt;h4 id=&quot;semi-synchronous&quot;&gt;Semi-synchronous&lt;/h4&gt;

&lt;p&gt;There is a way to combine synchronous and asynchronous approaches called semi-synchronous replication. This approach works the same way as synchronous but returns response once at least one replica acknowledged.&lt;/p&gt;

&lt;p&gt;In case of single replica, this approach is equal to synchronous.&lt;/p&gt;

&lt;h3 id=&quot;node-relationship&quot;&gt;Node relationship&lt;/h3&gt;

&lt;h4 id=&quot;masterslave-single-copy&quot;&gt;Master/Slave (single copy)&lt;/h4&gt;

&lt;p&gt;The most standard replication model is master/slave replication. In this technique, there should be one master node and single or multiple slaves. Master accepts writes and reads but slaves accept only reads. When master goes down, replicas stay available for reads.&lt;/p&gt;

&lt;p&gt;Usually master sends operation log (binary log) or a log with global transaction identifiers, this allows all replicas understand where they are at in that log and catch master up after a failure or initially.&lt;/p&gt;

&lt;p&gt;Most real-world systems promote a slave to a master when the master becomes inaccessible.&lt;/p&gt;

&lt;h4 id=&quot;multi-master&quot;&gt;Multi-master&lt;/h4&gt;

&lt;p&gt;Multi-master is where you can write on any node and data gets replicated to all others. This addresses the problem of the many writes in HA systems.&lt;/p&gt;

&lt;p&gt;Usually, this approach causes different issues due to the fact that clients can work with the same data but from different masters. The following techniques can solve this problem:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;https://docs.google.com/drawings/d/1qxFHXW-cgILSfeAD0ZM0iNO4iff6RjOZUbcGa2vafuE/pub?w=690&amp;amp;h=495&quot; /&gt;
&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Pessimistic locking&lt;/strong&gt; - master locks a potentially affected segment of data so others master refuse modification of the segment.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Optimistic locking&lt;/strong&gt; - based on data versioning. If a master A tries to write a value with a version that doesn’t equal to the one that a master B has, this write will be refused.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Conflict resolution&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Priority - from two conflicting writes we apply a one by some rule (e.g. the write with the latest timestamp)&lt;/li&gt;
      &lt;li&gt;Data merging - &lt;a href=&quot;http://hal.upmc.fr/file/index/docid/555588/filename/techreport.pdf&quot;&gt;convergent or commutative replicated data type&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
  &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/8_DfwEpHE88&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Conflict avoidance&lt;/strong&gt; - data is divided into logical parts and assigned to specific master, so clients are aware of what type of data should go to a specific master. &lt;strong&gt;This approach is very similar to partitioning&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;consensus&quot;&gt;Consensus&lt;/h2&gt;

&lt;p&gt;The consensus problem is a problem of having nodes in distributed systems agreed on some value.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Consensus typically arises in the context of replicated state machines, a general approach to building fault-tolerant systems. Each server has a state machine and a log. The state machine is the component that we want to make fault-tolerant, such as a hash table. It will appear to clients that they are interacting with a single, reliable state machine, even if a minority of the servers in the cluster fail. Each state machine takes as input commands from its log. In our hash table example, the log would include commands like set x to 3. A consensus algorithm is used to agree on the commands in the servers’ logs. The consensus algorithm must ensure that if any state machine applies set x to 3 as the n&lt;sup&gt;th&lt;/sup&gt; command, no other state machine will ever apply a different n&lt;sup&gt;th&lt;/sup&gt; command. As a result, each state machine processes the same series of commands and thus produces the same series of results and arrives at the same series of states.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This may be illustrated as follows:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;https://docs.google.com/drawings/d/1QJu2X_749QVli9jufMp_uXEnIVJe_dDkQE6jTRYxjnI/pub?w=829&amp;amp;h=627&quot; /&gt;
&lt;/p&gt;

&lt;h3 id=&quot;two-phase-commit&quot;&gt;Two-Phase commit&lt;/h3&gt;

&lt;p&gt;The Two-Phase commit algorithm introduces two roles:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Leader (coordinator, master) - a node that a client writes to.&lt;/li&gt;
  &lt;li&gt;Acceptor (cohort, replica) - a node that all writes should be replicated to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This algorithm is very simple and relies on the assumption that network is reliable. There are one leader and one or multiple acceptors in the system. When a leader receives the data to write, it proposes the data to all acceptor and waits for a vote from all of them. An acceptor can accept or reject the value base on acceptor’s state, then:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If all acceptors accepted the value, the leader sends a commit request.&lt;/li&gt;
  &lt;li&gt;If one or more of the acceptors failed, the leader sends a rollback request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that, the leader receives acknowledgment for all commit/rollback command and returns to the client.
More detailed description of the steps can be found &lt;a href=&quot;http://the-paper-trail.org/blog/consensus-protocols-two-phase-commit/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This approach has a critical disadvantage&lt;/strong&gt; - it’s not partition tolerant and it’s blocking. If the leader fails in the middle of the agreement, the acceptors will be infinitely blocked on waiting for commit/rollback request. If some of the replicas fail permanently, then master won’t be able to accept any writes.&lt;/p&gt;

&lt;h3 id=&quot;three-phase-commit&quot;&gt;Three-Phase commit&lt;/h3&gt;

&lt;p&gt;The Three-Phase commit algorithm is an improved version of Two-Phase commit, that aims to eliminate its blocking nature. The algorithm introduces additional revertible phase of pre-commit where acceptor can store the data and switch to the state of waiting for a commit request. If an acceptor doesn’t receive a commit request within specified timeout, the data will be discarded. Even though it solves the problem of blocking, the system can get in an inconsistent state.&lt;/p&gt;

&lt;h3 id=&quot;paxos&quot;&gt;Paxos&lt;/h3&gt;

&lt;p&gt;Paxos is the next generation of consensus algorithms. It solves the weaknesses of the Two-Phase commit and Three-Phase commit algorithms. The main differences are that Paxos requires the majority of nodes to acknowledge in order to send a commit request, in addition to that, the leader assigns a unique sequence number to each write so that an acceptor can distinguish which value comes first.&lt;/p&gt;

&lt;p&gt;You may look at a more detailed description &lt;a href=&quot;http://research.microsoft.com/en-us/um/people/lamport/pubs/paxos-simple.pdf&quot;&gt;here&lt;/a&gt; or &lt;a href=&quot;http://the-paper-trail.org/blog/consensus-protocols-paxos/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are also multiple modifications of the original paxos algorithm like Multi-Paxos, Cheap Paxos, or Fast Paxos.&lt;/p&gt;

&lt;h3 id=&quot;raft&quot;&gt;RAFT&lt;/h3&gt;

&lt;p&gt;Nevertheless, Paxos is not the only partition tolerant algorithm. Furthermore, Paxos is blamed for its complexity.
The Raft algorithm is the youngest from all described above. It’s relatively simple and give the same guarantees as Paxos does.&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/YbZ3zDzDnrw&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The best entry point to the details of this algorithms is &lt;a href=&quot;https://raft.github.io/&quot;&gt;this site&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;partitioning&quot;&gt;Partitioning&lt;/h2&gt;

&lt;p&gt;Partitioning is a technique of dividing the monolith data into several parts and storing them on different nodes.
This technique helps to deal with large data that doesn’t fit one node or deal with a big number of writes/reads when one node of the system can’t handle it. Sometimes it can be used for security purposes (if data should be isolated in a certain way) or when geographical location of data parts is important.&lt;/p&gt;

&lt;p&gt;There are three strategies of partitioning:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Horizontal partitioning&lt;/strong&gt; (sharding) - having a set of objects, each object depending on some rule is stored on the specific node.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vertical partitioning&lt;/strong&gt; - having the same set of objects, each node stores only specific attributes of each object (e.g. user name is held by node A while user DOB is held by node B).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Functional partitioning&lt;/strong&gt; - this strategy divides the data by type (e.g. user info and user orders are located on different nodes).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these strategies solve a particular problem but bring other problems. The main problems are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Probable inconsistency. Data on different nodes are not linked so that we can lose some data.&lt;/li&gt;
  &lt;li&gt;More complex and time-consuming data querying. If the data we need is located on different nodes, we need two steps to obtain the result: query all nodes and then merge the results.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;horizontal-partitioning&quot;&gt;Horizontal partitioning&lt;/h3&gt;

&lt;p&gt;Horizontal partitioning is the most popular strategy due to the fact that in most cases  distributed systems deal with a big number of homogenous objects. Also, this approach gives more scaling flexibility.&lt;/p&gt;

&lt;p&gt;The most interesting part of this strategy is the rule that will be used for data division. This rule is called “sharding key”. It should be chosen beforehand (because it’s relatively difficult in most cases to change this key after the system is in use) and should:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Divide data into approximately the same parts so that there won’t be nodes with too much data and with too little data.&lt;/li&gt;
  &lt;li&gt;Divide data into parts with approximately the same load. It means that hot data shouldn’t be concentrated on a certain node while unused data on another node.&lt;/li&gt;
  &lt;li&gt;Divide by geography. Data related to specific location should preferably be located in the corresponding geographic data-center.&lt;/li&gt;
  &lt;li&gt;Data of a node A shouldn’t avoid relations to data of other nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A sharding key can meet one or more of the properties below depending on the problem. There are several common solutions to choose a sharding key:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Range partitioning&lt;/strong&gt;, the key will be the interval of the value of some sequential attribute (e.g. date of the transaction, user DOB, etc).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;List partitioning&lt;/strong&gt;, the attribute value itself (e.g. user country).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Hash partitioning&lt;/strong&gt;, the key is calculated by applying a hash function to any of model’s attributes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dynamic partitioning&lt;/strong&gt;, keys are associated with values be a certain rule and these relations are stored in an external system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/theanalyst/awesome-distributed-systems&quot;&gt;Awesome Distributed Systems&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/aphyr/distsys-class&quot;&gt;Outline for Aphyr’s class “Distributed Systems Fundamentals”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://book.mixu.net/distsys/single-page.html&quot;&gt;Distributed systems for fun and profit&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
        <pubDate>Sun, 04 Dec 2016 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2016/12/04/distributed-systems/</link>
        <guid isPermaLink="true">http://dimafeng.com/2016/12/04/distributed-systems/</guid>
        
        
        <category>cap,</category>
        
        <category>distributed</category>
        
        <category>systems,</category>
        
        <category>replication,</category>
        
        <category>sharding,</category>
        
        <category>paxos,</category>
        
        <category>raft</category>
        
      </item>
    
      <item>
        <title>How to manage your dotfiles</title>
        <description>&lt;p&gt;A few months ago I wrote a &lt;a href=&quot;/2016/03/27/linux-commands/&quot;&gt;post with Linux commands cheat sheet&lt;/a&gt;. But then I started thinking that I don’t need to remember all those commands if I have
a collection of scripts and aliases which I can use and transfer from one machine to another with ease. Moreover, if had such repository I would store scripts which make freshly installed OS X/MacOs a fully configured development environment.
To achieve this goal, people come up with
an idea of storing their dotfiles and other useful scripts in some (semi-)standard way on github.&lt;/p&gt;

&lt;h2 id=&quot;what-are-dotfiles-and-semi-standard-way&quot;&gt;What are dotfiles and (semi-)standard way&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;dotfiles&lt;/strong&gt; are files whose names start with a dot. In this post, we’re talking about dotfiles located in &lt;code class=&quot;highlighter-rouge&quot;&gt;~/&lt;/code&gt;. Most of them are configurations of different parts of your system.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;(semi-)standard&lt;/strong&gt; is the way these files are stored on github and there’s no one standard way to do it. There is a site &lt;a href=&quot;https://dotfiles.github.io/&quot;&gt;dotfiles.github.io&lt;/a&gt; where all good practices are collected on. Basically, you need to structure your git repo in a way that is easy to install and easy to update when some changes pushed to upstream.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In most cases, you need to clone the dotfiles repo to &lt;code class=&quot;highlighter-rouge&quot;&gt;~/dotfiles&lt;/code&gt; and then run an install script. The install script usually backs up old files and creates symbolic links to those from the cloned repo. Besides, a dotfiles repo may contain scripts for installing additional utils and applications and it can make a fresh system a ready-to-go system in minutes.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img style=&quot;width: 400px;&quot; src=&quot;/assets/dotfiles.jpg&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;which-dotfiles-to-work-with&quot;&gt;Which dotfiles to work with&lt;/h2&gt;

&lt;p&gt;Now we can loot at some files which you can modify to configure system for your needs. I have &lt;a href=&quot;https://github.com/dimafeng/dotfiles&quot;&gt;my own dotfiles&lt;/a&gt; (they’re not quite done yet, but I’m working on it) you can use it as an idea. The intention of having your own dotfiles (and not using existing ones) was to understand how it all works and why you need each line in your configs. Basically, my dotfiles is &lt;strong&gt;a compilation of all popular dotfiles repositories of which parts I found useful with several modifications&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;installsh&quot;&gt;install.sh&lt;/h3&gt;

&lt;p&gt;This is an entry point to the dotfiles repo. Currently, my script is split into three parts: config linking, common parts installation and OS specific application installation. The linking step just creates symbolic links to files from the repo. So you can pull new changes and they automatically will be applied. To make work on my dotfiles more smooth, I use names without dots but create symlinks with dots.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;install.sh link&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then you can install common application and scripts. Currently, it contains:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://ohmyz.sh/&quot;&gt;oh-my-zsh&lt;/a&gt; and theme&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Oh-My-Zsh is an open source, community-driven framework for managing your ZSH configuration. It comes bundled with a ton of helpful functions, helpers, plugins, themes, and a few things that make you shout…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;Some python packages&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;install.sh install_commons&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The OS specific application installation, in my case, uses brew to install all essential applications. You can review and modify the list of applications in &lt;code class=&quot;highlighter-rouge&quot;&gt;brew.sh&lt;/code&gt; and then run:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;install.sh install_app_mac&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;bash_profile&quot;&gt;.bash_profile&lt;/h3&gt;

&lt;p&gt;This is the first file to be loaded when a bash shell is starting. Common practice is to have less code here but load all that you need from separate files grouped by purpose. In my case, I load &lt;code class=&quot;highlighter-rouge&quot;&gt;.aliases&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;.functions&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;zshrc&quot;&gt;.zshrc&lt;/h3&gt;

&lt;p&gt;This is an entry point to the zsh configuration that loads all others configurations. Since I’m using &lt;strong&gt;oh-my-zsh&lt;/strong&gt; this configuration is from the standard &lt;strong&gt;oh-my-zsh&lt;/strong&gt; distribution with a few changes. You can easily go through the file and uncomment lines you need.
In my case, I made the following changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Theme &lt;code class=&quot;highlighter-rouge&quot;&gt;ZSH_THEME=&quot;dracula&quot;&lt;/code&gt; - this is nice looking dracula theme (downloaded during &lt;code class=&quot;highlighter-rouge&quot;&gt;install.sh install&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;Plugins &lt;code class=&quot;highlighter-rouge&quot;&gt;plugins=(docker gradle)&lt;/code&gt; - here you can specify which plugins should be run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, this config script loads &lt;code class=&quot;highlighter-rouge&quot;&gt;.bash_profile&lt;/code&gt; mentioned above, so all aliases and functions will be working in both &lt;strong&gt;bash&lt;/strong&gt; and &lt;strong&gt;zsh&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;aliases&quot;&gt;.aliases&lt;/h3&gt;

&lt;p&gt;All aliases are stored here. The quick overview of several popular repositories gave a basic pattern of this file. Usually, people make their own shortcuts to most used paths in the everyday routine:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cd ~/Documents/Dropbox&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cd ~/Downloads&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cd ~/Desktop&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cd ~/Documents/dev&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;git&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;history&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;functions&quot;&gt;.functions&lt;/h3&gt;

&lt;p&gt;This file contains functions that can be used as regular command line applications. For the convenience, I organized them in the way it could be easily transformed into a documentation.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;mkd&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# Create a new directory and enter it&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	mkdir &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then I added an alias &lt;code class=&quot;highlighter-rouge&quot;&gt;alias dhelp=&quot;grep &quot;^function&quot; ~/dotfiles/functions | sed 's/function/+/g' | sed 's/() #/ - /g'&quot;&lt;/code&gt; and now it works as follows:&lt;/p&gt;

&lt;pre&gt;
$ dhelp
+ calc -  Simple calculator
+ mkd -  Create a new directory and enter it
+ cdf -  Change working directory to the top-most Finder window location
+ fs -  Determine size of a file or total size of a directory
+ dataurl -  Create a data URL from a file
+ server -  Start an HTTP server from a directory, optionally specifying the port
+ gz -  Compare original and gzipped file size
+ json -  Usage: `json '{&quot;foo&quot;:42}'` or `echo '{&quot;foo&quot;:42}' | json`
+ digga -  Run `dig` and display the most useful info
+ escape -  UTF-8-encode a string of Unicode symbols
+ unidecode -  Decode \x{ABCD}-style Unicode escape sequences
+ codepoint -  Get a character’s Unicode code point
+ a -  `a` with no arguments opens the current directory in Atom Editor, otherwise opens the given location
+ v -  `v` with no arguments opens the current directory in Vim, otherwise opens the given location
+ o - `o` with no arguments opens the current directory, otherwise opens the given location
+ tre -  `tre` is a shorthand for `tree` with hidden files and color enabled
+ grr -  Git: Revert changes &amp;amp; Remove all untracked
+ gr -  Git: Revert changes in specific file
+ gacp -  Git: add all, commit and push. [-m &quot;comment&quot;]
&lt;/pre&gt;

&lt;h3 id=&quot;gitconfig&quot;&gt;.gitconfig&lt;/h3&gt;

&lt;p&gt;If you work with multiple git accounts (e.g. you have github account and git account at your work) here’s the trick - if you have the following lines in &lt;code class=&quot;highlighter-rouge&quot;&gt;.gitconfig&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;nn&quot;&gt;[user]&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Dmitry Fedosov&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;(none)&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;you’ll be asked to specify local email for each repo.&lt;/p&gt;

&lt;h3 id=&quot;osx&quot;&gt;.osx&lt;/h3&gt;

&lt;p&gt;OS X/MacOs has a built-in command line tool for configuration - defaults. To get an idea which settings to tune, &lt;a href=&quot;https://gist.github.com/brandonb927/3195465/&quot;&gt;here’s
a script&lt;/a&gt; that interactively asks you what to change. You can go through it and copy settings into your config.&lt;/p&gt;

&lt;h3 id=&quot;vimrc&quot;&gt;.vimrc&lt;/h3&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;https://draculatheme.com/assets/img/screenshots/vim.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;I wrote a &lt;a href=&quot;/2015/09/13/vim1/&quot;&gt;post some time ago&lt;/a&gt; about &lt;strong&gt;vim&lt;/strong&gt; configuration. I haven’t changed too much since that time.
I just configured nice looking theme &lt;a href=&quot;https://draculatheme.com/vim/&quot;&gt;Dracula&lt;/a&gt;. It’s installed from Vundle, so you just need to run &lt;code class=&quot;highlighter-rouge&quot;&gt;:PluginInstall&lt;/code&gt; in your vim.&lt;/p&gt;

</description>
        <pubDate>Sun, 09 Oct 2016 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2016/10/09/dotfiles/</link>
        <guid isPermaLink="true">http://dimafeng.com/2016/10/09/dotfiles/</guid>
        
        
        <category>linux,</category>
        
        <category>osx,</category>
        
        <category>dotfiles,</category>
        
        <category>vim</category>
        
      </item>
    
      <item>
        <title>Integration testing using docker and scala</title>
        <description>&lt;p&gt;A few weeks ago I published a post on Reddit where I &lt;a href=&quot;https://www.reddit.com/r/scala/comments/4s695y/use_docker_containers_for_testing_in_scala/&quot;&gt;tried to advertise&lt;/a&gt; my lib - &lt;a href=&quot;https://github.com/dimafeng/testcontainers-scala&quot;&gt;testcontainers-scala&lt;/a&gt;.
This failed, I got no feedback at all. This prompted me to write this post and show how awesome integration testing might be.&lt;/p&gt;

&lt;p&gt;Here I’m going to show a simple example of selenium tests. Let’s get it started.&lt;/p&gt;

&lt;h2 id=&quot;testcontainers&quot;&gt;Testcontainers&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dimafeng/testcontainers-scala&quot;&gt;Testcontainers-scala&lt;/a&gt; is a wrapper for &lt;a href=&quot;https://github.com/testcontainers/testcontainers-java&quot;&gt;testcontainers-java&lt;/a&gt; that allows using docker containers for functional/integration testing.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;TestContainers is a Java 8 library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;assumptions&quot;&gt;Assumptions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;del&gt;You know how to use SBT&lt;/del&gt; You’re able to copy and paste dependencies to your &lt;code class=&quot;highlighter-rouge&quot;&gt;build.sbt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;You use scala 2.11&lt;/li&gt;
  &lt;li&gt;You run all of these on java &amp;gt;8&lt;/li&gt;
  &lt;li&gt;You have docker installed on your machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If all of those points are true then we’re ready to write some code.&lt;/p&gt;

&lt;h2 id=&quot;build-script&quot;&gt;Build script&lt;/h2&gt;

&lt;p&gt;I’m not going to make it complex, so here’s the simplest minimalistic &lt;code class=&quot;highlighter-rouge&quot;&gt;build.sbt&lt;/code&gt; that we need to start. It’s enough for showing the power of &lt;strong&gt;testcontainers&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;testcontainers-example&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.0&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;scalaVersion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;2.11.8&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;libraryDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;com.dimafeng&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;testcontainers-scala&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0.2.0&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//testcontainers itself
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;libraryDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;org.scalatest&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;scalatest_2.11&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;2.2.6&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;libraryDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;org.testcontainers&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;selenium&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.1.0&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// testcontainer-java module for selenium
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;libraryDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;org.seleniumhq.selenium&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;selenium-java&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;2.53.0&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;libraryDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;org.slf4j&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;slf4j-simple&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.7.21&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implementation&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is pretty standard build script, so there’s no problem just to copy and paste this into &lt;code class=&quot;highlighter-rouge&quot;&gt;build.sbt&lt;/code&gt; of your existing project.&lt;/p&gt;

&lt;div class=&quot;disclaimer&quot;&gt;
&lt;h1&gt;Important note&lt;/h1&gt;
The version of &lt;strong&gt;selenium-java&lt;/strong&gt; links to a version of &lt;strong&gt;selenium/standalone-chrome-debug&lt;/strong&gt; container. If you are using a version different from 2.53.0 please check a version of the container manually. See &lt;a href=&quot;https://hub.docker.com/r/selenium/standalone-chrome-debug/tags/&quot;&gt;the official docker hub page&lt;/a&gt;
&lt;/div&gt;

&lt;h2 id=&quot;specs&quot;&gt;Specs&lt;/h2&gt;

&lt;p&gt;Now we can write some specs. Since I have no prepared backend, I’m going to write specs in terms of &lt;a href=&quot;http://www.scalatest.org/&quot;&gt;scalatest&lt;/a&gt; which test reddit.com.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.dimafeng.scala.example.testcontainers&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.io.File&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.dimafeng.testcontainers.SeleniumTestContainerSuite&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.openqa.selenium.remote.DesiredCapabilities&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.scalatest.FlatSpec&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.scalatest.selenium.WebBrowser&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RedditSpec&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FlatSpec&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SeleniumTestContainerSuite&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebBrowser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;desiredCapabilities&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DesiredCapabilities&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (1)
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recordingMode&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;VncRecordingMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RECORD_FAILING&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;./&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (2)
&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// (3)
&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&quot;Reddit&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;show non-zero number of links on the main page&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://www.reddit.com/&quot;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cssSelector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#siteTable .thing&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;findAllElements&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nonEmpty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// (4)
&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&quot;Reddit&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;redirect to https&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;http://www.reddit.com/&quot;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startsWith&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://www.reddit.com&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// (5)
&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&quot;Reddit&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;stay reddit after click on a random link&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://www.reddit.com/&quot;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;click&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cssSelector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.entry a.title&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;findAllElements&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isDisplayed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentUrl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startsWith&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://www.reddit.com&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is all you need to test your GUI inside the docker. Now let’s break it down. We have &lt;code class=&quot;highlighter-rouge&quot;&gt;SeleniumTestContainerSuite&lt;/code&gt; trait that does all the magic under the hood. It starts a clean new container on each test case, so you don’t need to worry about the state - no data shared between test cases. To make it work in a basic scenario you just need to configure &lt;code class=&quot;highlighter-rouge&quot;&gt;DesiredCapabilities&lt;/code&gt; (1) - here it’s chrome, but you can use firefox as well.&lt;/p&gt;

&lt;p&gt;There are three test cases (3-5). The first two (3-4) are regular selenium tests wrapped with nice &lt;strong&gt;scalatest&lt;/strong&gt; DSL.
And the last one is a test that sometimes fails. But you can say that there is no way to figure out what is going on inside the container and this may be true, but not in our case. As you see in (3) we ask &lt;strong&gt;testcontainers&lt;/strong&gt; to record all failed tests and produce &lt;code class=&quot;highlighter-rouge&quot;&gt;.flv&lt;/code&gt; file. This is how it looks like:&lt;/p&gt;

&lt;p&gt;
&lt;img src=&quot;/assets/testcontainers-selenium/testcontainers-selenium.gif&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;The tests case checks that after clicking on a first link in the list a user won’t be redirected to a foreign domain, in fact, he will.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I had a lot of problems with old fashioned approaches like Chrome/Firefox/Remote/etc. drivers running them locally and on CI servers, and I had a tough time with modern approaches like &lt;strong&gt;phantom.js&lt;/strong&gt;. This seems much more reliable and convenient because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Tests are reproducible:&lt;/strong&gt; if it fails on CI server it fails on your dev environment and visa verse.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Each test case is stateless:&lt;/strong&gt; you don’t need to worry about cleaning cookies, local storage, etc. Each test works with its own clean browser.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Easy to start in parallel:&lt;/strong&gt; since there’s no state, you can run it in parallel.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Simple troubleshooting:&lt;/strong&gt; if a test fails you can watch recorded video or fallback to local Chrome/Firefox drivers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;img style=&quot;width: 300px;&quot; src=&quot;/assets/testcontainers-selenium/Shut-up-and-take-my-money.jpg&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;It’s free and open-sourced - &lt;a href=&quot;https://github.com/dimafeng/testcontainers-scala&quot;&gt;github project with all instructions&lt;/a&gt;. Your contributions are very welcome.&lt;/p&gt;

</description>
        <pubDate>Mon, 01 Aug 2016 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2016/08/01/testcontainers-selenium/</link>
        <guid isPermaLink="true">http://dimafeng.com/2016/08/01/testcontainers-selenium/</guid>
        
        
        <category>docker,</category>
        
        <category>selenium,</category>
        
        <category>scala</category>
        
      </item>
    
      <item>
        <title>Publishing of your artifact to maven central</title>
        <description>&lt;p&gt;Recently, I finished my pet-project and wanted to publish it to maven central. As I found out later,
publishing is not a trivial thing. In this post, I’m going to show you all steps which you need to
go through to publish your artifact.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dimafeng/testcontainers-scala&quot;&gt;My project is a scala wrapper&lt;/a&gt; for a very useful library &lt;a href=&quot;https://github.com/testcontainers/testcontainers-java&quot;&gt;testcontainers-java&lt;/a&gt;. As you may assume, it’s written in scala, but all the following is applicable for java/groovy/whatever language project if it’s built by gradle.&lt;/p&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;p&gt;First of all, you need to request a group id reservation. To do so, you need to sign up in &lt;a href=&quot;https://issues.sonatype.org/projects/OSSRH&quot;&gt;Sonatype’s JIRA&lt;/a&gt; and create an issue where you’ll have to ask to approve your group id. &lt;a href=&quot;https://issues.sonatype.org/browse/OSSRH-23192&quot;&gt;This&lt;/a&gt; is how I did that.&lt;/p&gt;

&lt;h2 id=&quot;gpg-keys&quot;&gt;GPG Keys&lt;/h2&gt;

&lt;p&gt;The next step is a creation of a gpg key. You need to install some additional utilities, on macos it looks like that
&lt;code class=&quot;highlighter-rouge&quot;&gt;brew install gpg gpg2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, tet’s create a key.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;gpg &lt;span class=&quot;nt&quot;&gt;--gen-key&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Pick default answers to the first two questions. Then enter two years as an expiration period. And fill out personal information.&lt;/p&gt;

&lt;p&gt;Now you can list all your keys:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;gpg2 &lt;span class=&quot;nt&quot;&gt;--list-secret-keys&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Copy a keyid of your key and distribute it as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;gpg2 &lt;span class=&quot;nt&quot;&gt;--keyserver&lt;/span&gt; hkp://pool.sks-keyservers.net &lt;span class=&quot;nt&quot;&gt;--send-keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;keyid]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A bit more details on this step are &lt;a href=&quot;http://central.sonatype.org/pages/working-with-pgp-signatures.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;gradle-script&quot;&gt;Gradle script&lt;/h2&gt;

&lt;p&gt;Now we can touch the project. Here are changes which should be made to your &lt;code class=&quot;highlighter-rouge&quot;&gt;build.gradle&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;...
apply plugin: &lt;span class=&quot;s1&quot;&gt;'maven'&lt;/span&gt;
apply plugin: &lt;span class=&quot;s1&quot;&gt;'signing'&lt;/span&gt;

task sourcesJar&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;: Jar&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    classifier &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'sources'&lt;/span&gt;
    from sourceSets.main.allSource
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

task javadocJar&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;: Jar&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    classifier &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'javadoc'&lt;/span&gt;
    from scaladoc
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

artifacts &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    archives javadocJar, sourcesJar
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

signing &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    sign configurations.archives
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

uploadArchives &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    repositories &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        mavenDeployer &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            beforeDeployment &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; MavenDeployment deployment -&amp;gt; signing.signPom&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;deployment&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

            repository&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;url: &lt;span class=&quot;s2&quot;&gt;&quot;https://oss.sonatype.org/service/local/staging/deploy/maven2/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                authentication&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;userName: ossrhUsername, password: ossrhPassword&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

            snapshotRepository&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;url: &lt;span class=&quot;s2&quot;&gt;&quot;https://oss.sonatype.org/content/repositories/snapshots/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                authentication&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;userName: ossrhUsername, password: ossrhPassword&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

            pom.project &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                name &lt;span class=&quot;s1&quot;&gt;'testcontainers-scala'&lt;/span&gt;
                packaging &lt;span class=&quot;s1&quot;&gt;'jar'&lt;/span&gt;
                description &lt;span class=&quot;s1&quot;&gt;'Scala wrapper for testcontainers-java'&lt;/span&gt;
                url &lt;span class=&quot;s1&quot;&gt;'https://github.com/dimafeng/testcontainers-scala'&lt;/span&gt;

                scm &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    connection &lt;span class=&quot;s1&quot;&gt;'scm:git:git@github.com:dimafeng/testcontainers-scala.git'&lt;/span&gt;
                    developerConnection &lt;span class=&quot;s1&quot;&gt;'scm:git:git@github.com:dimafeng/testcontainers-scala.git'&lt;/span&gt;
                    url &lt;span class=&quot;s1&quot;&gt;'git@github.com:dimafeng/testcontainers-scala.git'&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

                licenses &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    license &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        name &lt;span class=&quot;s1&quot;&gt;'The MIT License (MIT)'&lt;/span&gt;
                        url &lt;span class=&quot;s1&quot;&gt;'https://opensource.org/licenses/MIT'&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

                developers &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    developer &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        name &lt;span class=&quot;s1&quot;&gt;'Your name'&lt;/span&gt;
                        email &lt;span class=&quot;s1&quot;&gt;'your email'&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This code allows publishing of releases and snapshots to &lt;em&gt;oss.sonatype.org&lt;/em&gt;. You just need to adjust &lt;code class=&quot;highlighter-rouge&quot;&gt;pom.project&lt;/code&gt; section to match your project information.&lt;/p&gt;

&lt;p&gt;And to make it all work, we need to modify &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.gradle/gradle.properties&lt;/code&gt; by adding a several properties:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-properties&quot; data-lang=&quot;properties&quot;&gt;&lt;span class=&quot;py&quot;&gt;signing.keyId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#keyId
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;signing.password=#yourPassword&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;signing.secretKeyRingFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/Users/user/.gnupg/secring.gpg&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ossrhUsername&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#Sonatype's JIRA username
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ossrhPassword=# password&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;More information on it is &lt;a href=&quot;http://central.sonatype.org/pages/gradle.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;publishing&quot;&gt;Publishing&lt;/h2&gt;

&lt;p&gt;It seems it’s time to deploy your artifact. Make sure your work with non-snapshot version and then execute:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;./gradlew uploadArchives&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once it’s done, you need to promote your release. To do so, you have to go to &lt;a href=&quot;https://oss.sonatype.org/#stagingRepositories&quot;&gt;this page&lt;/a&gt;. In the table with repositories, you’ll see one that looks like your group id but without dots. Go in there and then click ‘Close’ in the top menu. Refresh the view in a few seconds and go to the ‘Activity’ tab - if you did everything correctly on the previous steps, you’ll see no errors and a button ‘Release’ will be enabled (it’s located to the right of ‘Close’ button), click on it and that’s pretty much it.&lt;/p&gt;

&lt;p&gt;Enjoy having your own artifact in maven cental!&lt;/p&gt;

</description>
        <pubDate>Sun, 26 Jun 2016 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2016/06/26/maven-central/</link>
        <guid isPermaLink="true">http://dimafeng.com/2016/06/26/maven-central/</guid>
        
        
        <category>maven</category>
        
        <category>central,</category>
        
        <category>gradle</category>
        
      </item>
    
      <item>
        <title>Not obvious scala features for java developers</title>
        <description>&lt;p&gt;A week ago I finished reading of &lt;a href=&quot;http://www.amazon.com/Scala-Impatient-Cay-S-Horstmann/dp/0321774094&quot;&gt;Scala for the Impatient&lt;/a&gt; by Cay Horstmann. Here are some lessons which I learned from this book.&lt;/p&gt;

&lt;h2 id=&quot;1-method-parentheses&quot;&gt;1. Method parentheses&lt;/h2&gt;

&lt;p&gt;For warming up, here’s the first tip - it’s well known that you can omit using of parentheses for methods without parameters. But there is a rule in scala world: you can omit parentheses on methods which don’t mutate a state.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nextInt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// With parentheses
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Without&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parentheses&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;2-traits-vs-abstract-classes&quot;&gt;2. Traits vs abstract classes&lt;/h2&gt;

&lt;p&gt;Java 8 brings a new experience to interface usage - interface methods can have a default implementation.
But scala eliminates the distinction even more (moreover, it works on JVM &amp;lt; 8): scala traits can have a default method implementation, abstract and defined values and variables. That’s why, in scala world, there is a rule: if you don’t know that to use traits or abstract classes - use traits, you’ll always be able to change them to abstract classes.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Car is ${color}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;red&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;why-is-it-good&quot;&gt;Why is it good&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;You can use traits as &lt;a href=&quot;https://en.wikipedia.org/wiki/Mixin&quot;&gt;mixins&lt;/a&gt;. You even can use it during object creation:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Car with ${wheels} wheels&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wheels&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FourWheel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wheels&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FourWheel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;specs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Car&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;wheels&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;why-is-it-bad&quot;&gt;Why is it bad&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;You can’t define constructor&lt;/li&gt;
  &lt;li&gt;Most features aren’t supported in java. So, you loose java interoperability&lt;/li&gt;
  &lt;li&gt;This approach has lesser performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-processbuilder-dsl&quot;&gt;3. ProcessBuilder DSL&lt;/h2&gt;

&lt;p&gt;There is a nice feature ti execute external one or more external processes from scala code using very convinient DSL:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CMDExample&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ls&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//(1)
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ls&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!!)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//(2)
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ls&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;grep gradle &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!!)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//(3)
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol&gt;
  &lt;li&gt;Executes &lt;code class=&quot;highlighter-rouge&quot;&gt;ls&lt;/code&gt; within working directory and prints to stdout, then returns exit code.&lt;/li&gt;
  &lt;li&gt;The save as 1. but returns command output as a string&lt;/li&gt;
  &lt;li&gt;Equivalent of &lt;code class=&quot;highlighter-rouge&quot;&gt;ls | grep gradle&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;4-regex&quot;&gt;4. Regex&lt;/h2&gt;

&lt;p&gt;Scala provides an easy way to work with java RegEx api. There’s a class and companion object which hold all this convenience - &lt;code class=&quot;highlighter-rouge&quot;&gt;scala.util.matching.Regex&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To create an instance of &lt;code class=&quot;highlighter-rouge&quot;&gt;Regex&lt;/code&gt;, you can use method &lt;code class=&quot;highlighter-rouge&quot;&gt;r&lt;/code&gt; mixed to a string. It may looks like this: &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;\\d+&quot;.r&lt;/code&gt;. Then, you can work with it as follows:&lt;/p&gt;

&lt;h3 id=&quot;find-matches&quot;&gt;Find matches&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;&amp;lt;a\\s+href=\&quot;([^\&quot;]*?)\&quot;\\s*&amp;gt;([^&amp;lt;]*?)&amp;lt;/a&amp;gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;a href=\&quot;test.html\&quot;&amp;gt;test&amp;lt;/a&amp;gt;&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;test.html:test&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For multiple matchings:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
       |&amp;lt;a href=&quot;index.html&quot;&amp;gt;index&amp;lt;/a&amp;gt;
       |&amp;lt;a href=&quot;secondary.html&quot;&amp;gt;secondary&amp;lt;/a&amp;gt;
   &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stripMargin&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;findAllIn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;replace&quot;&gt;Replace&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replaceAllIn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The output of this line will be a string where all &lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt; tags replaced with a content of those tags.&lt;/p&gt;

&lt;h2 id=&quot;5-structural-type&quot;&gt;5. Structural type&lt;/h2&gt;

&lt;p&gt;Structural type is very interesting feature. It allows to define method argument of any type but with requirement of presence of specific methods. This is how it looks like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;printInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;info:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;A&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;B&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;printInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;printInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Mon, 30 May 2016 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2016/05/30/scala-for-java-developer/</link>
        <guid isPermaLink="true">http://dimafeng.com/2016/05/30/scala-for-java-developer/</guid>
        
        
        <category>scala</category>
        
      </item>
    
      <item>
        <title>Netty Hello World</title>
        <description>&lt;p&gt;When you read an article about async programming in java you will definitely find at least mentions of Netty. I’ve heard about this library, I know that many high-performance frameworks based on Netty (Akka, Vert.x, &lt;a href=&quot;http://netty.io/wiki/related-projects.html&quot;&gt;the full list is here&lt;/a&gt;), but I’ve never tried it. So it’s time to write a hello world application using Netty and scala.&lt;/p&gt;

&lt;h2 id=&quot;what-is-netty&quot;&gt;What is Netty&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers &amp;amp; clients.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simply put, Netty is going to be useful if you want to write a server that handles all requests in one thread (technically not one) instead of using a separate thread for each client request. What’s wrong with a thread per request approach? - when we get a high load, we need to have a lot of threads to serve all clients, but having many threads causes high memory consumption and many thread context switches (the second reason is more important due to the fact that it is an expensive operation). This approach is very popular, for example, in javascript world. Node.js http server works exactly in this way.&lt;/p&gt;

&lt;p&gt;Netty operates with &lt;a href=&quot;http://netty.io/4.0/api/io/netty/channel/Channel.html&quot;&gt;Channels&lt;/a&gt; which are abstractions over a socket. As you may see, data can be read from or written to them  - all these operations will be non-blocking. In addition, you can combine channels in groups and execute the same operations as for individual channels. If you’re creating server application you need some of the implementations of &lt;code class=&quot;highlighter-rouge&quot;&gt;ServerSocketChannel&lt;/code&gt;. To start working with a server channel, we have to introduce another important thing - thread pools which all the magic will be run on. There are two thread pools which should be passed to the server channel: boss and workers.
The boss one is going to accept incoming connections while the workers process these accepted connections.&lt;/p&gt;

&lt;h2 id=&quot;what-are-we-going-to-create&quot;&gt;What are we going to create&lt;/h2&gt;

&lt;p&gt;As a demo application, I’m going to code simple app that will be capturing image from webcam and transfer it over websocket to the client side, then javascript will draw it on the canvas - it’s cross-browser and cross-platform solution, you can watch a video even on a mobile device (without audio though).&lt;/p&gt;

&lt;p&gt;To capture images from the camera, we’ll use &lt;a href=&quot;https://github.com/sarxos/webcam-capture&quot;&gt;webcam-capture&lt;/a&gt;. It’s written in pure java and has very simple api.&lt;/p&gt;

&lt;h2 id=&quot;server-side&quot;&gt;Server Side&lt;/h2&gt;

&lt;p&gt;All the code split into two parts: server side and client side. Due to the fact that I’m learning scala, the server side will be written in scala in java-style (I’m trying to adopt canonical, functional style, but this is tough to do very fast)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-scala&quot; data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.awt.Dimension&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.io.ByteArrayOutputStream&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;java.util.concurrent.Executors&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;javax.imageio.ImageIO&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.github.sarxos.webcam.Webcam&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.bootstrap.ServerBootstrap&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.buffer.Unpooled&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.channel.group.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ChannelGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DefaultChannelGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.channel.nio.NioEventLoopGroup&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.channel.socket.SocketChannel&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.channel.socket.nio.NioServerSocketChannel&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.channel.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ChannelHandlerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ChannelInitializer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleChannelInboundHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.handler.codec.http.websocketx.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BinaryWebSocketFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebSocketFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebSocketServerProtocolHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.handler.codec.http.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpObjectAggregator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpServerCodec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.handler.logging.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LoggingHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io.netty.util.concurrent.GlobalEventExecutor&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;scala.concurrent.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ExecutionContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Application&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;implicit&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ec&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ExecutionContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Executors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newSingleThreadExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WEBSOCKET_PATH&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/websocket&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FPS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allChannels&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DefaultChannelGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;all&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GlobalEventExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;INSTANCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;startCapture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;allChannels&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;startServer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;allChannels&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startServer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ChannelGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bossGroup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NioEventLoopGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;workerGroup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NioEventLoopGroup&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServerBootstrap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bossGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;workerGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;NioServerSocketChannel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LoggingHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;childHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ChannelInitializer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;SocketChannel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initChannel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;SocketChannel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;
              &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addLast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpServerCodec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addLast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpObjectAggregator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;65536&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
              &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addLast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebSocketServerProtocolHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;WEBSOCKET_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
              &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addLast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebSocketFrameHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;closeFuture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;bossGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shutdownGracefully&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;workerGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shutdownGracefully&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startCapture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ChannelGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webcam&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Webcam&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Webcam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getDefault&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;webcam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setViewSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Dimension&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;640&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;480&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;webcam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;

    &lt;span class=&quot;nc&quot;&gt;Future&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outputStream&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ByteArrayOutputStream&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ImageIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;webcam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;jpg&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outputStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writeAndFlush&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BinaryWebSocketFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Unpooled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copiedBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;toByteArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)))&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FPS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebSocketFrameHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ChannelGroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleChannelInboundHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;WebSocketFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userEventTriggered&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ChannelHandlerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;scala.Any&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Unit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;evt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebSocketServerProtocolHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ServerHandshakeStateEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HANDSHAKE_COMPLETE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userEventTriggered&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;channelRead0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ChannelHandlerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;WebSocketFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// do nothing
&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you see, we don’t have many lines of code (thanks, scala!). Let’s go through the all key parts of this code.
There are two methods: the first one connects to default camera and starts capturing images (the details of this process won’t be covered in this article), the second one starts a web server.
To define a server, there is a special class &lt;code class=&quot;highlighter-rouge&quot;&gt;ServerBootstrap&lt;/code&gt; which is a &lt;code class=&quot;highlighter-rouge&quot;&gt;ServerChannel&lt;/code&gt; but with a simplified interface for server creation. It provides builder-style approach for its configuration. Here are main configuration steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;group&lt;/code&gt; - takes two event loops, the firs one is for accepting incoming connections, the second one is for data processing&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;channel&lt;/code&gt; - takes a type of the channel that will be created&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;childHandler&lt;/code&gt; - takes a &lt;code class=&quot;highlighter-rouge&quot;&gt;ChannelHandler&lt;/code&gt; that will initialize a channel. In our case, it is a &lt;code class=&quot;highlighter-rouge&quot;&gt;ChannelInitializer&lt;/code&gt;. Its implementation is described below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last step is &lt;code class=&quot;highlighter-rouge&quot;&gt;bind&lt;/code&gt;, that binds our channel to given port and returns a &lt;code class=&quot;highlighter-rouge&quot;&gt;ChannelFuture&lt;/code&gt;. That &lt;code class=&quot;highlighter-rouge&quot;&gt;ChannelFuture&lt;/code&gt; is used for correct closing of the server channel.&lt;/p&gt;

&lt;p&gt;Now let’s go back to &lt;code class=&quot;highlighter-rouge&quot;&gt;ChannelInitializer&lt;/code&gt;. The most interesting part of it is pipeline. Pipeline passes all the date through a chain of &lt;code class=&quot;highlighter-rouge&quot;&gt;ChannelHandler&lt;/code&gt;s. In our case, we have &lt;code class=&quot;highlighter-rouge&quot;&gt;HttpServerCodec&lt;/code&gt; which is a http protocol implementation, &lt;code class=&quot;highlighter-rouge&quot;&gt;WebSocketServerProtocolHandler&lt;/code&gt; easily implements WebSockets (it requires &lt;code class=&quot;highlighter-rouge&quot;&gt;HttpObjectAggregator&lt;/code&gt;) and the last one &lt;code class=&quot;highlighter-rouge&quot;&gt;WebSocketFrameHandler&lt;/code&gt; which is our handler that does simple thing - it add newly connected client to the group of channels. This group is used in parallel thread that captures image and puts the binary into the group. Very simple!&lt;/p&gt;

&lt;h2 id=&quot;client-side&quot;&gt;Client side&lt;/h2&gt;

&lt;p&gt;As per our requirements, the client application should connect to a websocket and render an image once it comes to the client side. Here is all that we need:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewport&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'viewport'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'2d'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;WebSocket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;WebSocket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ws://localhost:8080/websocket&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binaryType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;arraybuffer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onmessage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Your browser does not support Web Socket.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;imgData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b64imgData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrayBufferToBase64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;imgData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;data:image/jpeg;base64,&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b64imgData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;640&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;480&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrayBufferToBase64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;byteLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fromCharCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;btoa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is pure javascipt. We even don’t need jQuery. The first part is standard WebSocket initialization - nothing to comment on it. There are two functions which should be described. &lt;code class=&quot;highlighter-rouge&quot;&gt;arrayBufferToBase64&lt;/code&gt; takes &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer&quot;&gt;ArrayBuffer&lt;/a&gt; (WebSocket in &lt;code class=&quot;highlighter-rouge&quot;&gt;socket.binaryType = &quot;arraybuffer&quot;&lt;/code&gt; mode uses this type of object to pass binaries) and converts to Base64 string. I haven’t written this function, I’ve stolen it from &lt;a href=&quot;http://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string&quot;&gt;here&lt;/a&gt;. And the last key function here is &lt;code class=&quot;highlighter-rouge&quot;&gt;draw&lt;/code&gt; - when we have Base64 binaries of an image we can draw it on a canvas and this is a typical code to do so.&lt;/p&gt;

&lt;h2 id=&quot;demo&quot;&gt;Demo&lt;/h2&gt;

&lt;p&gt;
&lt;img src=&quot;/assets/netty/suZVdHpAUD.gif&quot; /&gt;
&lt;/p&gt;

</description>
        <pubDate>Sun, 08 May 2016 00:00:00 +0000</pubDate>
        <link>http://dimafeng.com/2016/05/08/netty-hello-world/</link>
        <guid isPermaLink="true">http://dimafeng.com/2016/05/08/netty-hello-world/</guid>
        
        
        <category>netty,</category>
        
        <category>scala</category>
        
      </item>
    
  </channel>
</rss>
