<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: diogoaurelio</title>
    <description>The latest articles on DEV Community by diogoaurelio (@diogoaurelio).</description>
    <link>https://dev.to/diogoaurelio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F97389%2F5841b868-3a02-4ab3-8f2d-3ae9d641c98b.png</url>
      <title>DEV Community: diogoaurelio</title>
      <link>https://dev.to/diogoaurelio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/diogoaurelio"/>
    <language>en</language>
    <item>
      <title>Dependency Injection in Scala - cake pattern</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Sat, 18 Feb 2023 13:55:15 +0000</pubDate>
      <link>https://dev.to/diogoaurelio/dependency-injection-in-scala-cake-pattern-4cao</link>
      <guid>https://dev.to/diogoaurelio/dependency-injection-in-scala-cake-pattern-4cao</guid>
      <description>&lt;p&gt;In this post we'll cover Dependency Injection (DI) basics in scala, and focus on how to perform it manually with using the &lt;code&gt;cake pattern&lt;/code&gt;.&lt;br&gt;
All code examples are &lt;a href="https://github.com/mklabs-io/scala-dependency-injection"&gt;available on github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction to DI
&lt;/h2&gt;

&lt;p&gt;Dependency injection encourages loose coupling. It tells you that this is wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;and rather encourages you to instead do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this change we're defining explicitly which dependencies the &lt;code&gt;MyService&lt;/code&gt; constructor needs, and that those should be injected from outside. The rule of thumb: if you see the &lt;code&gt;new&lt;/code&gt; keyword inside a service, that should immediately yield a red flag in your head.&lt;/p&gt;

&lt;p&gt;Might not seem much, but this is already a big improvement, as it greatly simplifies the way we can build tests for the &lt;code&gt;MyService&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;Let's do that. So let's start by defining our dependencies (no pun intended) in &lt;code&gt;build.sbt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="n"&gt;libraryDependencies&lt;/span&gt; &lt;span class="o"&gt;++=&lt;/span&gt; &lt;span class="nc"&gt;Seq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"org.scalamock"&lt;/span&gt; &lt;span class="o"&gt;%%&lt;/span&gt; &lt;span class="s"&gt;"scalamock"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="s"&gt;"5.2.0"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"org.scalatest"&lt;/span&gt; &lt;span class="o"&gt;%%&lt;/span&gt; &lt;span class="s"&gt;"scalatest"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="s"&gt;"3.2.14"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nc"&gt;Test&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And here a sample layout for our mocking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;eu.m6r.scalalightningtalks.di.Background.DI2.&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.scalamock.scalatest.MockFactory&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.scalatest.flatspec.AnyFlatSpec&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.scalatest.matchers.must.Matchers&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BackgroundTest&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AnyFlatSpec&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;Matchers&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;MockFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="s"&gt;"test something BlueService when repository behaves a certain way"&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;mockRepository&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;// service under test&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And this way we can easily manipulate the response from MyRepository. If our original implementation was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;.. then we could mock the response, for example, as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="s"&gt;"test something BlueService when repository behaves a certain way"&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;mockRepository&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;// service under test&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;sut&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// mock&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;mockRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;findOne&lt;/span&gt; &lt;span class="k"&gt;_&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;expects&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;returning&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"two"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;once&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="nv"&gt;sut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="s"&gt;"two"&lt;/span&gt;

  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;However, we're not done yet; consider the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;By defining a general contract for the &lt;code&gt;Repository&lt;/code&gt; (via our trait), we are nicely adding a &lt;strong&gt;separation of concerns&lt;/strong&gt; - in the future we can easily swap to a different concrete &lt;code&gt;Repository&lt;/code&gt; implementation (for example, instead using a given DB, using another), without having to change anything in &lt;code&gt;BlueService&lt;/code&gt; implementation.&lt;/p&gt;

&lt;p&gt;If this is your first time hearing about it, you may be asking yourself:  But where then do I instantiate and pass the concrete Repository instance?
In other words: Where do I instantiate and inject &lt;code&gt;BlueService&lt;/code&gt; dependency?&lt;/p&gt;

&lt;p&gt;DI relies on Inversion of Control (IoC) principle, which encourages one to create the concrete service implementations outside of the actual services that use them. This is usually done in a central container, or spread out across multiple centralization containers which determine which dependency is instantiated and gets injected to which class. &lt;/p&gt;
&lt;h2&gt;
  
  
  Options for DI in Scala
&lt;/h2&gt;

&lt;p&gt;We have several options for DI in Scala:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using libraries from java world, such as &lt;a href="https://github.com/google/guice"&gt;Guice&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;using pure scala: manually injecting via a central container, with the &lt;code&gt;cake pattern&lt;/code&gt;, or with the &lt;code&gt;reader monad&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;using scala libraries: &lt;a href=""&gt;MacWire&lt;/a&gt;, &lt;a href="https://github.com/dickwall/subcut"&gt;SubCut&lt;/a&gt;, &lt;a href="https://github.com/scaldi/scaldi"&gt;Scaldi&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post we'll just show case the most basic form of manual DI, and then exemplify the second alternative with the &lt;code&gt;cake pattern&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Manual DI - central container
&lt;/h2&gt;

&lt;p&gt;Let's start with the simplest, and arguably the most frowned upon. If we're being honest here, quite a reasonable one if you're working on a small project.&lt;/p&gt;

&lt;p&gt;Just create a main container where your configuration(s) is/are loaded, and passed to create dependencies, and inject them in several services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreenService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;myRepo&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;blueService&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myRepo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;greenService&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GreenService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myRepo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The beauty about this solution is two-folded: one it is very simple - it is straight forward, anyone can understand it, there is no magic happening underneath the hood. The second is that we have compile type safety giving us compile time seat-belt for any mistakes.&lt;/p&gt;

&lt;p&gt;This has one core drawback, which is that it is not very scalable. It requires tediously declaring all new dependencies, increasing linearly as the project grows, while making sure that the exact instantiation and injection are guaranteed at the right time and place. Eventually we might bump into one of these mistakes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;blueService&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myRepo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;myRepo&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;.. and be sure that this will compile, but &lt;code&gt;myRepo&lt;/code&gt; will be &lt;code&gt;null&lt;/code&gt; when referenced, since it hasn't been initialized (a case of forward reference). &lt;/p&gt;

&lt;p&gt;Arguably not the worst thing in the world, and easily solvable by letting the compiler solve it for us with the keyword &lt;code&gt;lazy&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;lazy&lt;/span&gt; &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;blueService&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BlueService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myRepo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;lazy&lt;/span&gt; &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;myRepo&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However not all is bad; in fact, manual DI does not get nearly as much love as it should. In comparison with most DI frameworks, which use reflection at run-time to dynamically infer the dependency graph, it gives us type-safety at compile time, a slight startup time improvement, and, most of all, removes the magic done behind the scenes. I can't state this enough: no framework magic to fight against (looking at you spring).&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual DI - Cake pattern
&lt;/h2&gt;

&lt;p&gt;The key building block to implement the cake pattern is to relie on trait &lt;code&gt;mix-in&lt;/code&gt; instead of inheritance. &lt;br&gt;
The name &lt;code&gt;cake&lt;/code&gt; comes from the idea of multiple layers - as we mix-in multiple traits with each other. &lt;br&gt;
We will dive right next in how the mix-in mumbo jumbo is executed - but just keep in mind that this is how one hooks dependencies, which forces the implementer of the traits to then inject concrete definitions of them. &lt;/p&gt;

&lt;p&gt;Let's review some fundamentals about scala traits to make the previous paragraph make any sense.&lt;/p&gt;
&lt;h3&gt;
  
  
  cake pattern background: traits &amp;amp; diamond problem
&lt;/h3&gt;

&lt;p&gt;The closest thing to a trait in the java world would be an interfaces - more concretely a java 8+ interface. Since java 8, interfaces can even have concrete method implementation using the &lt;code&gt;default&lt;/code&gt; keyword, and so can traits. One interface can also, like scala traits, extend more than one interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Demo1&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Demo2&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// this is fine&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Demo3&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Demo1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Demo2&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This might ring some alarm bells and cold sweats in you, namely regarding the &lt;a href="https://www.tutorialspoint.com/what-is-diamond-problem-in-case-of-multiple-inheritance-in-java"&gt;diamond problem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem comes when the original interfaces being extended share one or more methods with the same signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Demo1&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Demo2&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"hallo"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// interface can extend multiple interfaces, &lt;/span&gt;
    &lt;span class="c1"&gt;// however on conflict, one will need to override&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Demo3&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Demo1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Demo2&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Demo1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The way java handles this situation is by forcing the developer to explicitly implement the concrete method in conflict - the &lt;code&gt;greet&lt;/code&gt; method in our silly example.&lt;/p&gt;

&lt;p&gt;Like java interfaces, one can extend a trait with another trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt;
&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;OsFileLocker&lt;/span&gt;
&lt;span class="c1"&gt;// this is also valid syntax:&lt;/span&gt;
&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;FileWriter&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;OsFileLocker&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in presence of conflicting method signatures, scala will behave differently. Here are more complete illustration of the diamond problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
    &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;FileOps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FileOps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"loaded"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;OsFileLocker&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FileOps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"lock created &amp;amp; file loaded"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileSystemConsumer&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;OsFileLocker&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;Note: extending in Scala 3 is, in my opinion, clearer: &lt;code&gt;class FileSystemOperator extends FileWriter, OsFileLocker&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The scala compiler will allow such wiring and apply a simple disambiguation rule: on conflicting method signature, use the implementation of the last trait being extended, e.g. the one one furthest to the right (&lt;code&gt;OsFileLocker&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileSystemConsumer&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="py"&gt;readFile&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// will print: lock created &amp;amp; file loaded&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make it perfectly clear, if one swapped the order, the print message would simply be "loaded":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileSystemConsumer&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;OsFileLocker&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileSystemConsumer&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="py"&gt;readFile&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// will print: loaded&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  cake pattern background: self type annotation
&lt;/h3&gt;

&lt;p&gt;The second essential trick we'll be using is scala's &lt;a href="https://docs.scala-lang.org/tour/self-types.html"&gt;&lt;code&gt;self&lt;/code&gt; type&lt;/a&gt; - which provides a way to mix-in another trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;intro&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;


  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this:&lt;/span&gt; &lt;span class="kt"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"$intro, I am Foo"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;By specifying &lt;code&gt;this: Greeting =&amp;gt;&lt;/code&gt; we are defining that whoever extends &lt;code&gt;Greeter&lt;/code&gt; will need to also extend the &lt;code&gt;Greeter&lt;/code&gt; trait, or anything that extends it.  The anything that extends it is the relevant part, and the main reason why we don't simply declare &lt;code&gt;trait Greeter extends Greeting&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If one tried to instantiate a Greeter trait, the compiler would immediately complain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// this won't compile&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;greeter&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if one would define a concrete implementation, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;PortugueseGreeting&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;intro&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Olá"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the following would compile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;greeter&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;PortugueseGreeting&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;greeter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// will print: Olá, I am Foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key part here to understand is the &lt;code&gt;with PortugueseGreeting&lt;/code&gt; - the concrete part where we're injecting the intended concrete implementation of the &lt;code&gt;Greeting&lt;/code&gt; contract. One would not be able to force the developer to inject a concrete implementation if one would have used inheritance to define the &lt;code&gt;Greeter&lt;/code&gt; trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// bad: using inheritance&lt;/span&gt;
    &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"$intro, I am Foo"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that anything available in the &lt;code&gt;Greeting&lt;/code&gt; trait will also be available for the &lt;code&gt;Greeter&lt;/code&gt; trait - in our silly example the &lt;code&gt;intro&lt;/code&gt; method - when using the preferred mix-in implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  the cake pattern example (finally)
&lt;/h3&gt;

&lt;p&gt;We are going to use an example often seen in API's code, namely where we want to specify that a service (where business logic resides) needs to be injected with a generic implementation of a repository (where we define CRUD operations with a given data store).&lt;/p&gt;

&lt;p&gt;Let's keep this simple; our model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our generic UserRepository contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;    &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second step is where specific cake pattern design would kick in. One would define a component, say &lt;code&gt;UserRepositoryComponent&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;UserRepositoryComponent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// expose the generic contract&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;userRepo&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UserRepository&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Components&lt;/code&gt; have a single purpose: to expose a given contract. Given the property that we talked earlier that the exposed value - &lt;code&gt;userRepo&lt;/code&gt; in our example - will be available for use in the trait where any other trait where it is mixed-in.&lt;br&gt;
So if we had a generic service contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;    &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;findUser&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We could wire all of these together in a &lt;code&gt;UserServiceComponent&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;UserServiceComponent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this:&lt;/span&gt; &lt;span class="kt"&gt;UserRepositoryComponent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;

    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;userService&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyUserService&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyUserService&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;findUser&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;userRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;I hope by now the reason for the name &lt;code&gt;cake&lt;/code&gt; starts becoming clearer. Like a cake with several layers, our component declares a class inside of it, which, in turn, makes use of the &lt;code&gt;userRepo&lt;/code&gt; value thanks to the &lt;code&gt;this: UserRepositoryComponent =&amp;gt;&lt;/code&gt; mix-in.&lt;/p&gt;

&lt;p&gt;At this point we're exactly in the same situation as we were when we couldn't instantiate a new &lt;code&gt;Greeter&lt;/code&gt; instance, since we still can't instantiate a &lt;code&gt;UserServiceComponent&lt;/code&gt;. No worries, let's implement a concrete mock Repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;CassandraUserRepositoryComponent&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;UserRepositoryComponent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;userRepo&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CassandraUserRepository&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CassandraUserRepository&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now we can glue it all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;userServiceComponent&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserServiceComponent&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;CassandraUserRepositoryComponent&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;userServiceComponent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;findUser&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// will print: User(1,john)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Just like before, we're leveraging scala self-type to inject the concrete implementation of our repository only on instantiation.&lt;/p&gt;

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

&lt;p&gt;In this post we went through the basics of dependency injection with examples in scala, and dived into a concrete way to wire your code to perform DI manually, with the cake pattern. As mentioned in the beginning, feel free to grab the code snippets available &lt;a href="https://github.com/mklabs-io/scala-dependency-injection"&gt;on github&lt;/a&gt; to play with them.&lt;/p&gt;

&lt;p&gt;We sincerely hope that we were able to distill all building blocks of the cake pattern in simple terms that didn't require you to take a PhD in category theory.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.scala-lang.org/tour/self-types.html"&gt;Scala &lt;code&gt;self&lt;/code&gt; types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jonasboner.com/real-world-scala-dependency-injection-di/"&gt;Really old, but great post about the Cake Pattern by industry heavy weight Jonas Bonér, CTO at Lightbend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/rahasak/scala-cake-pattern-e0cd894dae4e"&gt;Blog post distilling all required building blocks in Scala for using the Cake pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://di-in-scala.github.io/"&gt;A fabulous deep dive to DI in scala from the creator himself of the &lt;code&gt;MacWire&lt;/code&gt; library, Adam Warski&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://scalamock.org/quick-start/"&gt;Scala Mock quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.scalatest.org/user_guide/testing_with_mock_objects"&gt;Scala test with Mock documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>scala</category>
      <category>di</category>
      <category>functional</category>
      <category>programming</category>
    </item>
    <item>
      <title>yet another post about type classes in Scala</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Mon, 02 Jan 2023 16:15:43 +0000</pubDate>
      <link>https://dev.to/mklabs/yet-another-post-about-type-classes-in-scala-3d5n</link>
      <guid>https://dev.to/mklabs/yet-another-post-about-type-classes-in-scala-3d5n</guid>
      <description>&lt;p&gt;While recently having a chat with a colleague about type classes in scala, I realized I failed at properly explaining the concept. So here I am, giving it (yet) another stab.&lt;/p&gt;

&lt;p&gt;In this post we will: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;understand the intuition behind type classes (TCs), to better reason when to use them;&lt;/li&gt;
&lt;li&gt;provide two concrete examples with code in scala;&lt;/li&gt;
&lt;li&gt;conclude with a very brief look into &lt;code&gt;cats&lt;/code&gt;, a widely used scala library that heavily relies on TCs;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The examples provided in this post were written in Scala 2, and &lt;a href="https://github.com/mklabs-io/scala-type-classes-intro"&gt;are available in this github repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intuition
&lt;/h2&gt;

&lt;p&gt;Type classes provide a way to model for different behaviors according to the type of the object being handled. So, at it's core, a type class is (unlike the name might at first sight suggest) actually just an interface - a &lt;code&gt;trait&lt;/code&gt; in scala - that defines the behavior with a given method signature that accepts or returns generic type. &lt;br&gt;
We then define concrete implementations for that interface for a given specific type. These we call the type class instances.&lt;br&gt;
Usually, as a last step, one exposes this functionality with a given api, say, for example a static method. &lt;/p&gt;
&lt;h2&gt;
  
  
  Example 1
&lt;/h2&gt;

&lt;p&gt;Let's say we work in a company that does ratings, and, to simplify matters, issues 5 star ratings. Currently the company started with doing evaluations of restaurants. However, we want to be able to extend those in the future to other aspects in life, such as hotels, cities, concerts, cars, gadgets, etc, you name it. &lt;br&gt;
Modelling our business domain, we'd quickly understand that a car is a completely distinct model than a hotel, so using classic OOP polymorphism by finding a common denominator interface that all of the other classes extend/inherit is a weak solution.&lt;br&gt;
Instead, what we really want is just to define a general interface for rating any of these types - think generics. In more rigorous terms this is called parametric polymorphism, which refers to the ability to define a single code template that can work with any type &lt;code&gt;T&lt;/code&gt; parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// this is our Type Class&lt;/span&gt;
  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Our TC has a single method that accepts a generic type, and returns 1-5 star rating which we oversimplified with an Integer (&lt;code&gt;Int&lt;/code&gt;) return type. &lt;/p&gt;

&lt;p&gt;Let's add two (rather silly but hopefully illustrative) models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foodQuality&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sweetness&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saltiness&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bitterness&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sourness&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;umami&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now comes the second part, where we deviate from parametric polymorphism - where the concrete implementation is completely agnostic to the Type &lt;code&gt;T&lt;/code&gt; being handled - and add specific TC instances that define different behaviors/strategies depending on the object being handled. For rating a restaurant one could implement a simple algorithm as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;RestaurantReviewer&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nv"&gt;scala&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;math&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;round&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.6F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;foodQuality&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.3F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;location&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;and, on the other hand, for reviewing a dish the following strategy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
    &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;DishReviewer&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;scala&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;round&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sweetness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;saltiness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;bitterness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sourness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;umami&lt;/span&gt;
      &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;TC are also sometimes referred to as ad hoc polymorphism, which opposes parametric polymorphism because one purposely defines a concrete distinct implementation for every given type. I found Jason McClellan does a great job explaining the &lt;a href="https://dev.to/jmcclell/inheritance-vs-generics-vs-typeclasses-in-scala-20op"&gt;different types of polymorphism and in concrete for type classes, so a highly recommend you to have a look at it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The usual third and last step is to expose the overall rating functionality, for example, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Evaluator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Alright, this is already enough for us to dry-run in a demo app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;DemoTC&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foodQuality&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sweetness&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saltiness&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bitterness&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sourness&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;umami&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;ReviewStrategies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;RestaurantReviewer&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nv"&gt;scala&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;math&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;round&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.6F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;foodQuality&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.3F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;location&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;DishReviewer&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;scala&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;round&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sweetness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;saltiness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;bitterness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sourness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;umami&lt;/span&gt;
      &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Evaluator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;restaurant1&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Cheesegaddon"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foodQuality&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// rate using `RestaurantReviewer` strategy:  &lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;restaurant1Rating&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;restaurant1&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="nv"&gt;ReviewStrategies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;RestaurantReviewer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// will print: Restaurant Cheesegaddon final rate is: 4 stars&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Restaurant ${restaurant1.name} final rate is: ${restaurant1Rating} stars"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;


&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Note that so far we're not leveraging any of scala's powerful features. As a matter a fact, we can implement the exact same demo code in java (yes java nerds, bear with me, as mentioned in the inline code comments, the above code is not the finest, but it illustrates my point):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoTCJava&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// this is our Type Class&lt;/span&gt;
    &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Note 1: Avoiding using newer Java Records to make this code easily runable on any jdk version &lt;/span&gt;
    &lt;span class="c1"&gt;// Note 2: made usually private internal vars public as to avoid extra verbosity of implementing getters;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Restaurant&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;foodQuality&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;foodQuality&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;foodQuality&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foodQuality&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dish&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sweetness&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;saltiness&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;bitterness&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sourness&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;umami&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sweetness&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;saltiness&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;bitterness&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sourness&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;umami&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sweetness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sweetness&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saltiness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saltiness&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bitterness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bitterness&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sourness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sourness&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;umami&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;umami&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RestaurantReviewer&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Restaurant&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;round&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;foodQuality&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DishReviewer&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dish&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;round&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sweetness&lt;/span&gt;
                            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saltiness&lt;/span&gt;
                            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bitterness&lt;/span&gt;
                            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sourness&lt;/span&gt;
                            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="no"&gt;F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;umami&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Restaurant&lt;/span&gt; &lt;span class="n"&gt;restaurant1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cheesegaddon"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;RestaurantReviewer&lt;/span&gt; &lt;span class="n"&gt;reviewer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RestaurantReviewer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;evaluator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;restaurant1Rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;restaurant1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reviewer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Restaurant %s final rate is: %d stars"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;restaurant1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;restaurant1Rating&lt;/span&gt;
                &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This is an example where scala's implicits really shine. If we made our API - the Evaluator static class - accept the evaluator as an implicit argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Evaluator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;implicit&lt;/span&gt; &lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;.. and changed our &lt;code&gt;ReviewStrategies&lt;/code&gt; to implicitly define TC instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;ReviewStrategies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;implicit&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;RestaurantReviewer&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nv"&gt;scala&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;math&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;round&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.6F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;foodQuality&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.3F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;location&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;implicit&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;DishReviewer&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Reviewer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Dish&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;scala&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;round&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sweetness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;saltiness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;bitterness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sourness&lt;/span&gt;
          &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5F&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;umami&lt;/span&gt;
      &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;.. we could then simply import the intended review strategies based on scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ReviewStrategies._&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;restaurant1Rating&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;restaurant1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And this is one of my favorite things about TCs, namely the flexibility for future extension that they provide. If perhaps tomorrow a new food critic would join the team, one that uses a completely different algorithm for computing the rate, absolutely no change would be required&lt;br&gt;
in our API - we would simply need to define and import the new different set of strategies.&lt;/p&gt;
&lt;h2&gt;
  
  
  Example 2
&lt;/h2&gt;

&lt;p&gt;Our second example is meant to illustrate an additional nice thing about TCs: the compile time safety.&lt;/p&gt;

&lt;p&gt;Let's say we want to prevent the following to happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;aComparison&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"a String"&lt;/span&gt;
  &lt;span class="c1"&gt;// will print: Comparison is false&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Comparison is $aComparison"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Your IDE will hopefully highlight the fact that we are comparing an int with a string, but compilation will succeed nonetheless, and the expression will evaluate to false.&lt;/p&gt;

&lt;p&gt;To solve this, we can use the same strategy as before. Let's define an &lt;code&gt;Eq&lt;/code&gt; TC with two concrete implementations, respectively for &lt;code&gt;Int&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Eq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val2&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;implicit&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;IntEq&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Eq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val2&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;val2&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;implicit&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;StringEq&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Eq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val2&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;val1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Comparison&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val2&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;implicit&lt;/span&gt; &lt;span class="n"&gt;comparator&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;comparator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;aNumber&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;anotherNumber&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;result1&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Comparison&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aNumber&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;anotherNumber&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// will print: 4 == 5 is false&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"$aNumber == $anotherNumber is $result1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With this approach we are certain that if we try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;Comparison&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... compilation will fail, as intended.&lt;/p&gt;

&lt;p&gt;We could improve our &lt;code&gt;Comparison&lt;/code&gt; implementation just a little further leveraging scala extension methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;MyComparisons&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;implicit&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyIntComparison&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;implicit&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Eq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;`===`&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val2&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If we import &lt;code&gt;MyComparisons&lt;/code&gt; object, we will immediately start having access to our custom &lt;code&gt;===&lt;/code&gt; method for all &lt;code&gt;Int&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; type objects, allowing the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;MyComparisons._&lt;/span&gt;
  &lt;span class="c1"&gt;// will print: 4 === 5 is false&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"$aNumber === $anotherNumber is ${aNumber === anotherNumber}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In case you're wondering how extension methods work, essentially the compiler is smart enough to underneath the hood to rap our &lt;code&gt;Int&lt;/code&gt; instance stored in variable &lt;code&gt;aNumber&lt;/code&gt; into a new instance of: &lt;br&gt;
&lt;code&gt;new MyIntComparison(aNumber)&lt;/code&gt; &lt;br&gt;
.. and call the method &lt;code&gt;===&lt;/code&gt; towards the other &lt;code&gt;Int&lt;/code&gt; instance stored in variable &lt;code&gt;anotherNumber&lt;/code&gt;: &lt;br&gt;
&lt;code&gt;new MyIntComparison(aNumber).=== (anotherNumber)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Pretty cool, right? &lt;/p&gt;

&lt;p&gt;If you're thinking to implement this by yourself, think again. Scala's Swiss-army-knife library &lt;code&gt;cats&lt;/code&gt; provides exactly this same functionality.&lt;/p&gt;

&lt;p&gt;Start by importing it in sbt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val catsVersion = "2.1.1"

libraryDependencies ++= Seq(
  "org.typelevel" %% "cats-core" % catsVersion
)

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

&lt;/div&gt;



&lt;p&gt;And use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cats.instances.int._&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt;  &lt;span class="nn"&gt;cats.syntax.eq._&lt;/span&gt;

  &lt;span class="c1"&gt;// will print: 2 === 3 is false&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"2 === 3 is ${2 === 3}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



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

&lt;p&gt;I'd like to wish that, if anything, this post manages to convey the intuition behind type classes. &lt;/p&gt;

&lt;p&gt;Type classes are useful when we want to model different behaviors according to the specific type of an object. With our previous example, we tried to provide a case where it makes little sense to use polymorphism to model distinct concepts, namely restaurants, hotels, cars, cities, etc. In other words, instead of having a common interface that all of the previous classes inherit, we prefer to rather use generics.&lt;br&gt;
Our type class is nothing but an interface that defines the signature for a given behavior/method leveraging generics.&lt;br&gt;
This leaves the concrete implementation open for accommodate different strategies according to the concrete types, or even different strategies for the same time. This idea is probably what makes type classes so powerful: the flexibility to extend them.&lt;/p&gt;

&lt;p&gt;Our second type class example attempted to illustrate one last perk: type safety at compile time. It did so with a simplified example of the &lt;code&gt;cats&lt;/code&gt; core library for type safety equality comparison between objects. If you're not familiar with cats, &lt;a href="https://typelevel.org/cats/"&gt;go ahead and give it go&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Parametric_polymorphism"&gt;parametric polymorphism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Parametric_polymorphism"&gt;ad hoc polymorphism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Jason McClellan on the &lt;a href="https://dev.to/jmcclell/inheritance-vs-generics-vs-typeclasses-in-scala-20op"&gt;different types of polymorphism and where type classes fit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://typelevel.org/cats/"&gt;cats core library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mklabs-io/scala-type-classes-intro"&gt;repo code for this blog post&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>scala</category>
      <category>functional</category>
      <category>programming</category>
    </item>
    <item>
      <title>Terraforming in 2021 – new features, testing and compliance</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Sun, 02 May 2021 17:07:29 +0000</pubDate>
      <link>https://dev.to/mklabs/terraforming-in-2021-new-features-testing-and-compliance-17ho</link>
      <guid>https://dev.to/mklabs/terraforming-in-2021-new-features-testing-and-compliance-17ho</guid>
      <description>&lt;p&gt; Both &lt;a href="https://www.linkedin.com/in/jrcferrao/" rel="noopener noreferrer"&gt;João&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/diogoaurelio/" rel="noopener noreferrer"&gt;I&lt;/a&gt; have been using regularly terraform for some time now, and are big fans of it. Big enough to even have worked for quite a while on a &lt;a href="https://www.mkops.io/" rel="noopener noreferrer"&gt; side project of our own to simplify managing terraform environments&lt;/a&gt; (which unfortunately did not succeed), at least. And yes, now that we are preparing the next one with &lt;a href="https://www.mkops.io/" rel="noopener noreferrer"&gt;mklabs&lt;/a&gt;, which naturally also heavily relies on terraform scripts, it made only sense to start by sharing some of our favorite tools that gravitate in the terraform ecosystem. 
&lt;/p&gt;
&lt;p&gt;We kick off with the latest updates in terraform itself, from 0.12 until the latest 0.15, and then go straight to surrounding tooling, where we mainly focus on testing and compliance checking for infrastructure. &lt;/p&gt;

&lt;p&gt;You can find all the code supporting this this post &lt;a href="https://github.com/mklabs-io/tf-ecosystem-blog-post" rel="noreferrer noopener"&gt;here&lt;/a&gt;.&lt;/p&gt;



&lt;h3&gt;Overview of latest Terraform versions&lt;/h3&gt;

&lt;p&gt;Version 0.15 &lt;a href="https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-15-general-availability" rel="noopener noreferrer"&gt;has just recently been released&lt;/a&gt;. Yet, a lot of companies out there are still running environments up to 0.11.X, and for a good reason. Though version 0.12 was launched already a while ago (2019), it brought great disruption. If this is your case, chances are that you gave up on keep up to date with its progress. Thus, we thought it would make sense to first review some of terraform features you might be missing out, before we try to convince you also considering further improvements.&lt;/p&gt;

&lt;h4&gt;0.12&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First-class expression syntax&lt;/strong&gt;: probably the most noticeable change, no more string interpolation sintax (&lt;em&gt;confettis&lt;/em&gt; blowing in the background)!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generalized type system&lt;/strong&gt;: (yay!) able to specify types of variables;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration constructs&lt;/strong&gt;: introduction a the &lt;code&gt;for&lt;/code&gt; operator allowing closer proximity to programming languages and thus more expressiveness to the DSL;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More details, see the &lt;a href="https://www.hashicorp.com/blog/announcing-terraform-0-12" rel="noopener noreferrer"&gt;general availability announcement page&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;0.13&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Module improvements&lt;/strong&gt; - brings ability to use several meta tags that until so far were only available for &lt;code&gt;resources&lt;/code&gt; &lt;a href="https://www.hashicorp.com/blog/terraform-0-13-brings-powerful-meta-arguments-to-modular-workflows" rel="noopener noreferrer"&gt;in modules&lt;/a&gt;. In this case, we can now use &lt;code&gt;depends_on&lt;/code&gt; for coupling dependencies with modules (finally!), along with ability instantiate multiple module instances with &lt;code&gt;count&lt;/code&gt; or &lt;code&gt;for_each&lt;/code&gt;; &lt;a href="https://www.hashicorp.com/blog/terraform-0-13-brings-powerful-meta-arguments-to-modular-workflows" rel="noopener noreferrer"&gt;more details here&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://datacenternotes.files.wordpress.com/2021/03/terraform_module_dependency.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2021%2F03%2Fterraform_module_dependency.jpg" alt=""&gt;&lt;/a&gt;Example specifying a module dependency (a personal favorite), &lt;a href="https://www.hashicorp.com/blog/terraform-0-13-brings-powerful-meta-arguments-to-modular-workflows" rel="noopener noreferrer"&gt;source hashicorp blog&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom variable validation&lt;/strong&gt; - when specifying variables one can from this version on wards specify custom rules for the input that is accepted and respective error message to allow fast failure; more details here;  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://datacenternotes.files.wordpress.com/2021/03/terraform_variable_validation.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2021%2F03%2Fterraform_variable_validation.jpg" alt=""&gt;&lt;/a&gt;Example variable validation, &lt;a href="https://www.hashicorp.com/blog/custom-variable-validation-in-terraform-0-13" rel="noopener noreferrer"&gt;source hashicorp blog&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Support 3rd party providers&lt;/strong&gt; - terraform now allows one to reference your own &lt;a href="https://registry.terraform.io/browse/providers" rel="noopener noreferrer"&gt;provider&lt;/a&gt; in the terraform block &lt;code&gt;required_providers&lt;/code&gt;. The &lt;code&gt;required_providers&lt;/code&gt; keyword in the terraform block already existed in terraform 12, though with was restricted to hashicorp's own providers; now you can reference your own DNS source to host your own registry, and upon &lt;code&gt;terraform init&lt;/code&gt; it will be installed same as it used to all other providers; &lt;a href="https://www.hashicorp.com/blog/automatic-installation-of-third-party-providers-with-terraform-0-13" rel="noopener noreferrer"&gt;more details here&lt;/a&gt;; note that if you are already using the &lt;code&gt;required_providers&lt;/code&gt; keyword in terraform block, to migrate from version 12 to 13 you should adapt it, as shown in the following example:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://datacenternotes.files.wordpress.com/2021/03/terraform13_providers.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2021%2F03%2Fterraform13_providers.jpg" alt=""&gt;&lt;/a&gt;Example required_providers, source &lt;a href="https://www.terraform.io/upgrade-guides/0-13.html" rel="noopener noreferrer"&gt;terraform upgrade guides&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More details, see the &lt;a href="https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-13" rel="noopener noreferrer"&gt;general availability announcement page&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;0.14&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sensitive variables &amp;amp; outputs&lt;/strong&gt; - allowing one to flag a variable as "sensitive" will redact its output on the CLI;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved diff&lt;/strong&gt; - this is probably one of the most common complaints I hear, namely the difficulty in reading a terraform &lt;code&gt;plan&lt;/code&gt; (and along with it the same for &lt;code&gt;apply&lt;/code&gt; and &lt;code&gt;show&lt;/code&gt;) output; with this new change, it hides unchanged fields (irrelevant for the diff) while displaying a count of the hidden elements for better clarity; &lt;a href="https://www.hashicorp.com/blog/terraform-0-14-adds-a-new-concise-diff-format-to-terraform-plans" rel="noopener noreferrer"&gt;more details here&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://datacenternotes.files.wordpress.com/2021/03/terraform14_improved_diff.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2021%2F03%2Fterraform14_improved_diff.jpg" alt=""&gt;&lt;/a&gt;Example excerpt diff, &lt;a href="https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-14-general-availability" rel="noopener noreferrer"&gt;source hashicorp blog&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;dependency lockfile&lt;/strong&gt; - as soon as you run &lt;code&gt;terraform init&lt;/code&gt; with version 14 you will notice that a &lt;code&gt;.terraform.lock.hcl&lt;/code&gt; file will be created in that directory and outside the &lt;code&gt;.terraform&lt;/code&gt; directory. This file is intended to be added to version control (git committed), to guarantee that the exact same provider versions are run everywhere;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More details, see the &lt;a href="https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-14-general-availability" rel="noopener noreferrer"&gt;general availability announcement page&lt;/a&gt;.&lt;/p&gt;



&lt;h4&gt;0.15&lt;/h4&gt;

&lt;p&gt;Finally, here are some of the main highlights the latest version just very recently announced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Remote state data source compatibility&lt;/strong&gt;: in order to make it easier to upgrade to newer versions, you can use reference remote state data objects that are using older versions; note that this feature has been back ported into previous releases as well, namely 0.14.0, 0.13.6, and 0.12.30;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improvements to conceal sensitive values (passwords, for example)&lt;/strong&gt;: following version 0.14 work now provider developers can specify the properties that are by default sensitive and should be anyway hidden in outputs; moreover, terraform also added a function (sensitive) for users to be able to explicitly hide values;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improvements in logging behavior&lt;/strong&gt;: ability to control provider and terraform log level separately &lt;code&gt;TF_LOG_CORE=level&lt;/code&gt; and &lt;code&gt;TF_LOG_PROVIDER=level&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More details, see the &lt;a href="https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-15-general-availability" rel="noopener noreferrer"&gt;general availability announcement page&lt;/a&gt;.&lt;/p&gt;



&lt;h3&gt;Handling multiple versions&lt;/h3&gt;

&lt;p&gt;Assuming that these new features convinced you to upgrade your existing terraform environments, being realistic here, this will not happen from one day to another. You will have a transition period (if not permanently) where you have environments with different terraform versions. That is OK, you can still keep your sanity while hopping between all of them thanks to tools like the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/tfutils/tfenv" rel="noopener noreferrer"&gt;TFEnv&lt;/a&gt; - terraform environment switcher inspired (from the ruby world) by &lt;code&gt;rbenv&lt;/code&gt; written with shell scripts;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/warrensbox/terraform-switcher/" rel="noopener noreferrer"&gt;Terraform Switcher &lt;/a&gt;- yet another project essentially doing the same written in go;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of these projects overlap almost entirely, so we will simply exemplify with one of them, namely tfenv:&lt;/p&gt;



&lt;a href="https://datacenternotes.files.wordpress.com/2021/03/tfenv_demo.gif" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2021%2F03%2Ftfenv_demo.gif%3Fw%3D1024" alt=""&gt;&lt;/a&gt;











&lt;p&gt;Here we are showing how you can switch between installed versions &lt;code&gt;tfenv use &amp;lt;local-version&amp;gt;&lt;/code&gt;, how you can check which versions are already locally installed with &lt;code&gt;tfenv list&lt;/code&gt;, all versions currently available &lt;code&gt;tfenv list-remote&lt;/code&gt; (minor detail: the current version of the library I'm using to record my terminal, &lt;a href="https://terminalizer.com/docs" rel="noopener noreferrer"&gt;terminalizer&lt;/a&gt;, does not capture me scrolling up and selecting version terraform &lt;code&gt;0.14.5&lt;/code&gt;)&lt;br&gt;Last but not least, we also show a cool feature from tfenv, namely the ability to automatically recognize the minimum required version in a given environment. Same goes for the latest version, in case you are wondering. And yes, this is also available in terraform switcher project.&lt;/p&gt;





&lt;h3&gt;Testing&lt;/h3&gt;





&lt;p&gt;Testing is probably the most confusing topic in the Infrastructure-as-Code (IaC) land, and terraform not being an exception, as a lot of different tools and procedures get thrown in this same bag, when, well, they probably should not. Usually when talking about testing, people usually mean three different things:&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;static checks&lt;/strong&gt; - validation of mainly the structure code without actually running the code; a fast away for performing sanity checks, either local and/or in your CI/CD pipelines; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;integration tests&lt;/strong&gt; - provided you are properly using inversion of control with variables, they give you the power to test your modules or environments for different generic cases;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;compliance checks&lt;/strong&gt; - tests done in the aftermath, after all resources have already been deployed; these can serve distinct purposes that we will explore better later, but essentially the goal is to confirm that what is deployed is what was initially intended and expressed in terraform;&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;Yes, you got that right: if you were looking forward to some classic unit testing, you can forget that for now. Let us dive straight into more details.&lt;/p&gt;





&lt;h4&gt;Static checks&lt;/h4&gt;





&lt;p&gt;Again, these are not tests strictly speaking, but rather just simple validation checks one can run to catch common errors without actually deploying anything. There is an array of tools out there, but let us start with the one provided out of the box in terraform binary.&lt;/p&gt;





&lt;p&gt;It is not uncommon for the tool creators to provide their own validators. Kubernetes provides validate &lt;code&gt;kubectl apply -f &amp;lt;file&amp;gt; --dry-run --validate=true&lt;/code&gt;, helm provides lint &lt;code&gt;helm lint &amp;lt;path&amp;gt;&lt;/code&gt;; terraform provides &lt;code&gt;validate&lt;/code&gt;. &lt;/p&gt;





&lt;p&gt;In the following example running &lt;code&gt;terraform validate&lt;/code&gt; would catch two of the three issues:&lt;/p&gt;




&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Validate will require to have previously run &lt;code&gt;terraform init&lt;/code&gt;, so that it can leverage providers. In our example it will detect the typo in the aws bucket resource reference, along with the invalid CIDR provided to create the VPC. What it will not detect, however, is the non existent EC2 instance type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://datacenternotes.files.wordpress.com/2021/03/terraform_validate_demo.gif" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2021%2F03%2Fterraform_validate_demo.gif%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/terraform-linters/tflint"&gt;TFLint&lt;/a&gt; comes to the rescue. Being yet another open source tool written in go, it comes as a binary much like terraform and does not even require terraform to be installed. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://datacenternotes.files.wordpress.com/2021/03/tflint.gif" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2021%2F03%2Ftflint.gif%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running with the &lt;code&gt;deep&lt;/code&gt; option requires one to provide credentials, providing a more thorough inspection. In our case, it detected the incorrect instance type, as well as the wrong AMI.&lt;/p&gt;

&lt;p&gt;You can also &lt;a rel="noreferrer noopener" href="https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/config.md"&gt;customize tflint&lt;/a&gt; to inject variables, define modules to ignore, etc. You can check the &lt;a href="https://github.com/terraform-linters/tflint/tree/master/docs/user-guide" rel="noreferrer noopener"&gt;user guide&lt;/a&gt; for more details.  &lt;/p&gt;

&lt;p&gt;Now besides linting for configuration issues in your code, another recommendation is to &lt;em&gt;check for security issues&lt;/em&gt;, such as too permissive security group rules, unencrypted resources, etc. &lt;/p&gt;

&lt;p&gt;Here again more than one tool exists to assist. We will highlight two of the most popular ones here: &lt;a rel="noreferrer noopener" href="https://github.com/tfsec/tfsec"&gt;tfsec&lt;/a&gt; and &lt;a rel="noreferrer noopener" href="https://github.com/bridgecrewio/checkov"&gt;checkov&lt;/a&gt;. Both provide a predefined set of checks that they use to inspect your code, allowing to explicitly open exceptions (if you really want to) by annotating your code with comments, and adjust the configuration to ignore some modules, for example. &lt;/p&gt;

&lt;p&gt;TFSec is written in Go, and is probably the fastest to get started, and currently &lt;a rel="noreferrer noopener" href="https://tfsec.dev/docs/aws/home/"&gt;provides up to 10 checks&lt;/a&gt; for the current main cloud providers (AWS, GCP, and Azure). The potential downside is that works exclusively for Terraform, so you will need to use additional tools to inspect kubernetes/helm/cloudformation etc. &lt;/p&gt;

&lt;p&gt;Checkov, on the other hand, despite being a more recent tool, has seen stellar development speed (being developed by a &lt;a rel="noreferrer noopener" href="https://bridgecrew.io/round-a-announcement/"&gt;startup with good founding rounds&lt;/a&gt;, and &lt;a rel="noreferrer noopener" href="https://www.paloaltonetworks.com/company/press/2021/palo-alto-networks-announces-intent-to-acquire-bridgecrew"&gt;PaloAlto Networks acquisition&lt;/a&gt; can't hurt). Not only do they have a &lt;a href="https://docs.bridgecrew.io/docs/aws-policy-index" rel="noopener noreferrer"&gt;really comprehensive number of checks&lt;/a&gt; across all the main cloud providers, but they also span across multiple technologies, such as Kubernetes, Cloudformation, serverless and ARM templates. And the list keeps growing. Checkov provides you the option to run either a pure static check by just pointing to the terraform directory or terraform file, or by actually running it against a terraform plan file. The nice thing about running it directly is naturally the simplicity of not requiring to have the target environment accessible to test the code.&lt;/p&gt;



&lt;p&gt;These tools are grabbing a lot of attention lately, as the double checking for security issues was usually locked in the hands of devops/devsecops teams, which in practice constituted a development bottleneck. By injecting these checks early in CI/CD pipelines, a great deal of development speed is freed without compromising security.   &lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Integration tests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/gruntwork-io/terratest"&gt;Terratest&lt;/a&gt; is probably the closest one can get now a days to testing the specific peace of terraform code. It is a Go library, and requires one to write tests in Go. This is obviously a potential limitation as not all teams have knowledge in Go. On the upside, I would argue that the learning curve of learning Go to get the basics - read enough for writing terraform tests - is not steep if you know already at least one programming language. &lt;/p&gt;

&lt;p&gt;Having worked already in several Go projects in the context of mklabs, we're naturally favorably biased towards Terratest. So, even if you have never tried Go, we would still recommend having a look on our sample repository, where we provide go mod setup to make it easy getting started. And if this did not convince you yet, here's what might: you can also use Terratest to test Dockerfiles, Kubernetes and Packer setups. &lt;/p&gt;

&lt;p&gt;This might seem intimidating, but we would argue that the benefits are worth it. Let us look at an example skeleton of a test setup for AWS:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Essentially the skeleton is always the same: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;start by defining the variables you want to inject as input for your terratest run; you might want to rather inject random variables even, to test in greater depth;&lt;/li&gt;
&lt;li&gt;make sure you tell the setup to destroy all created resources after the terraform apply has been completed using the &lt;code&gt;defer&lt;/code&gt; statement; this is equivalent to the &lt;code&gt;trap&lt;/code&gt; keywork in shell, and it will execute even if something fails in the meanwhile; the only prerequisite is that you declare it before you call &lt;code&gt;terraform.InitAndApply()&lt;/code&gt; method;&lt;/li&gt;
&lt;li&gt;Let the test be deployed by passing the terraform config setup you have previously declared in &lt;code&gt;terraformOptions&lt;/code&gt; to &lt;code&gt;terraform.InitAndApply&lt;/code&gt; method;&lt;/li&gt;
&lt;li&gt;Finally, declare the things you want to assert; that is, declare what you expect should have been deployed - the &lt;code&gt;expected&lt;/code&gt; - and see if they match what was actually deployed - the &lt;code&gt;result&lt;/code&gt;. The simplest way is to check in terraform apply output, which is accessible via `terraform.Output()` method. Alternatively, terragrunt also provides you some methods out of the box for frequently checked things on a per provide basis.  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sounds like fun, right? Here is an example of some of the tests we could write to our basic terraform example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here is the output of running these tests for our demo setup:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://datacenternotes.files.wordpress.com/2021/03/terratest_demo-1.gif" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2021%2F03%2Fterratest_demo-1.gif%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final thoughts regarding terratest&lt;/strong&gt;: we find terratest a great tool to implement changes in your infrastructure with confidence, no matter if they are just simple day to day changes, or bigger and complexer upgrades or migrations. &lt;/p&gt;

&lt;p&gt;We just scratched the surface here on the tests one can develop with terratest - for example combining SSH access into instances and confirming access to resources, etc. However, there are no free lunches, and this can come at a price: tests can take a long time (depending obviously on what you are testing), and require a non trivial time investment - learning how to use, writing them, and setting up the environment, as you probably will want to run them in an isolated environment. For example, in AWS case, this would ideally be a dedicated account. We recommend reading &lt;a href="https://terratest.gruntwork.io/docs/#testing-best-practices" rel="noopener noreferrer"&gt;best practices on how to perform testing&lt;/a&gt; from terragrunt, the company behind terratest.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Compliance checks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The last mile is asserting that what you wanted to be deployed, was indeed deployed exactly &lt;em&gt;as you wanted&lt;/em&gt;. Abusing terraform &lt;code&gt;null_resource&lt;/code&gt; is a classic one leading to unintended surprises. One way of achieving this would be to run these tests right after the &lt;code&gt;terraform apply&lt;/code&gt; stage of your CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;But the next question you might have is how do I know that these configurations stay that way, that &lt;em&gt;no one changed things inadvertently&lt;/em&gt; ? We've seen this situation arise in different forms: changes done by users manually via GUI or CLI; via different terraform environments mutating overlapping resources properties; or as a by-product of using different IaC tools, for example configuring some bits with Cloudformation, some K8s or Helm, etc. &lt;/p&gt;

&lt;p&gt;Arguably more interesting would be scheduling to run these checks continuously and repeatedly, to make sure things stay as you expected. Let's see some options out there to achieve this.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;The rogue approach&lt;/strong&gt;: in practice you can do this type of compliance checks with any programming language you favor.  As we shown before, one can export terraform' state into &lt;code&gt;json&lt;/code&gt; format, and then use, for example, python with &lt;code&gt;pytest&lt;/code&gt; and &lt;code&gt;boto3&lt;/code&gt; libraries to compare what is deployed with the desired output. You could even go further, and use &lt;code&gt;boto3&lt;/code&gt; to scan your accounts for different aspects that you considered go against best practices, such as lack of encryption (in-flight and at rest).&lt;/p&gt;

&lt;p&gt;While this might be tempting at first sight, you might end up writing way more testing code, than the actual terraform code. Not only it seems kind of silly, but it can get hairy.    &lt;/p&gt;

&lt;p&gt;The second reason not to follow this approach, is that there are already several solutions out there fairly tested and intuitive to use that can help you with this task, which we will cover now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Driftctl - open source go library from cloudskiff for terraform;&lt;/li&gt;
&lt;li&gt;Sentinel - Hashicorp's own solution;&lt;/li&gt;
&lt;li&gt;terraform-compliance - open source BDD based solution dedicated for terraform;&lt;/li&gt;
&lt;li&gt;Conftest - test suite for multiple frameworks besides terraform, such as kubernetes and dockerfiles; &lt;/li&gt;
&lt;li&gt;Inspec - Chef compliance testing tool, written in ruby;&lt;/li&gt;
&lt;li&gt;Built-in cloud provider - each cloud provider has it's own inspections mechanisms in place;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may be wondering why the first place in our list is a library still in beta. That is a good point, and we would argue that its progress seems to be promising, and that we like to support startups. Moreover we think its &lt;a rel="noreferrer noopener" href="https://docs.driftctl.com/0.7.1/usage"&gt;simplicity of usage&lt;/a&gt; deserves a highlight as it delivers one thing and one thing only: check if what is in your terraform state file is what is actually deployed. Simply point to your terraform statefile when you run &lt;code&gt;driftctl scan&lt;/code&gt; command and you will get a detailed report if you have &lt;em&gt;drifted&lt;/em&gt;. Due to the low effort required to implement this library and value provided, we think it deserves taking it for a spin.&lt;/p&gt;

&lt;p&gt;Next on our list is Hashicorp's (the company behind terraform) own enterprise solution for this, &lt;a rel="noreferrer noopener" href="https://www.hashicorp.com/sentinel"&gt;Sentinel&lt;/a&gt;. This is could make sense if you are already using other Hashicorp's enterprise functionality, benefiting from Terraform Enterprise.&lt;/p&gt;

&lt;p&gt;A direct open source comparable alternative would be using &lt;a rel="noreferrer noopener" href="https://github.com/terraform-compliance/cli"&gt;terraform-compliance&lt;/a&gt;. It follows &lt;a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Behavior-driven_development"&gt;BDD&lt;/a&gt; directives so that you can specify in an easy human readable way your expectations, using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;given&lt;/em&gt;: a given resource type;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;when&lt;/em&gt;: an optional condition you might want to add;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;then&lt;/em&gt;: what you expectation is;   &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of a test file for AWS S3 buckets:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Although we do get the appeal of easily understandable tests that do not require knowing how code, we find terraform-compliance lacks flexibility to test various aspects, mainly due to the BDD nature. Moreover, there are &lt;a rel="noreferrer noopener" href="https://adinermie.com/the-good-the-bad-and-the-ugly-of-using-terraform-compliance/"&gt;more people disenchanted by it with some valid points&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you like terraform-compliance, &lt;a rel="noreferrer noopener" href="https://github.com/open-policy-agent/conftest"&gt;Conftest&lt;/a&gt; might also be worth having a look. It has its own DSL to write policies, and allows you to test multiple frameworks. We found &lt;a rel="noreferrer noopener" href="https://www.blokje5.dev/posts/validating-terraform-plans/"&gt;this blog post&lt;/a&gt; from Lennard Eijsackers very informative, and would thus rather recommend you to check it out. &lt;/p&gt;



&lt;p&gt;Before we dive into own cloud provider compliance checking services, we want to highlight yet another open source tool, namely &lt;a rel="noreferrer noopener" href="https://github.com/inspec/inspec"&gt;InSpec&lt;/a&gt;. It allows you to write tests in ruby, and was &lt;a rel="noreferrer noopener" href="https://docs.chef.io/inspec/inspec_and_friends/#rspec"&gt;built on top of RSpec&lt;/a&gt;. If you know already &lt;a rel="noreferrer noopener" href="https://github.com/k1LoW/awspec"&gt;awsspec&lt;/a&gt;, then this should feel very similar, with the advantage that InSpec also supports GCP and Azure. &lt;/p&gt;

&lt;p&gt;Even though none of us is actively a ruby developer, we find InSpec very easy to get started with and, most importantly, very powerful. It allows you to combine IaC checks to target resources deployed and mapped in terraform state files, with other general policies for cloud account configuration. Moreover, it also allows you to combine additional security checks, such as on OS level configurations and services running. Let us illustrate how you could write these checks. The following check illustrates how to define global policies that an account should obey:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The next one illustrates for generic networking:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The previous examples only illustrate generic control checks that validate overall best practices in your acocunt. However, you might want to also perform assertions regarding what is in your terraform state versus what is deployed - what the &lt;a rel="noreferrer noopener" href="https://cloudskiff.com/"&gt;cloudskiff&lt;/a&gt; engineers rightly name &lt;em&gt;drift&lt;/em&gt;. Christoph Hartmann - one of InSpecs creators -  has a nice &lt;a rel="noreferrer noopener" href="https://lollyrock.com/posts/inspec-terraform/"&gt;blog post&lt;/a&gt; explaining how to use InSpec and integrate with terraform. The approach is essentially as described previously in the rogue approach - import terraform state json file and use it as the expected assertion. &lt;/p&gt;

&lt;h3&gt;Built-in cloud provider policy tools&lt;/h3&gt;

&lt;p&gt;Each cloud provider has a native tool to address company-wide governance policies. Some examples of services are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS: &lt;strong&gt;&lt;a href="https://aws.amazon.com/config/" rel="noopener noreferrer"&gt;AWS Config&lt;/a&gt;&lt;/strong&gt; and to manage cloud configuration deviations within one account, &lt;a rel="noreferrer noopener" href="https://aws.amazon.com/systems-manager/"&gt;Systems Manager&lt;/a&gt; to enforce instance OS security, and more recently &lt;a rel="noreferrer noopener" href="https://aws.amazon.com/controltower/"&gt;Control Tower&lt;/a&gt; for enforcing rules across multiple accounts;&lt;/li&gt;
&lt;li&gt;Azure: &lt;strong&gt;&lt;a href="https://azure.microsoft.com/en-us/services/azure-policy/" rel="noopener noreferrer"&gt;Azure Policy&lt;/a&gt;&lt;/strong&gt; for checking cloud configuration deviations and &lt;strong&gt;&lt;a href="https://azure.microsoft.com/en-us/services/security-center/" rel="noopener noreferrer"&gt;Azure Security Center&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;GCP:&lt;strong&gt; &lt;a href="https://cloud.google.com/blog/products/identity-security/protecting-your-gcp-infrastructure-at-scale-with-forseti-config-validator" rel="noopener noreferrer"&gt;Forseti Config Validator&lt;/a&gt;&lt;/strong&gt; for GCP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just some of the services that we know that can be used for such enforcement. Most of these services go beyond just checking cloud config, and also provide security inspections at instance level, for example. The important point to keep in mind is that these security checks are post deployment compliance assertion, not for preventing configuration issues.&lt;/p&gt;

&lt;h2&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;We find that there is not a single silver bullet that solves all problems, and the best strategy is actually a combination of multiple tactics employed at different stages. The two main phases that require different approaches are &lt;em&gt;pre&lt;/em&gt; and &lt;em&gt;post&lt;/em&gt; deployment. &lt;/p&gt;

&lt;p&gt;For pre-deployment, a combination of static checks and actual tests can be used. Static checks are a great starter, as they are easy to setup, and allow you to enforce generally good practices across the whole organization. In other words, static checks provide you an powerful easy win. With terratest, on the other hand, you mainly gain on confidence that the IaC code will actually work, and that you will catch &lt;em&gt;faux pas&lt;/em&gt;. However, terratest does not come for free, and does require a learning curve with go, along with time investment to develop the actual tests.&lt;/p&gt;

&lt;p&gt;After your code gets deployed comes the next challenge: making sure things stay well architected. Regular scheduled checks that assess if your infrastructure is running as intended should also be part of your devOps strategy, and for this two main routes exist: open source or using dedicated cloud services.   &lt;/p&gt;

&lt;p&gt;And that is it. Thank you for reading, we hope this has been useful. Feel free to reach out to us if you have questions or suggestions.&lt;/p&gt;

&lt;p&gt;Once again, you can find all the code supporting this this post &lt;a rel="noreferrer noopener" href="https://github.com/mklabs-io/tf-ecosystem-blog-post"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;Sources&lt;/h3&gt;

&lt;p&gt;As usual, here is the summary of sources used for this post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a rel="noopener noreferrer" href="https://www.hashicorp.com/blog/announcing-terraform-0-12"&gt;Terraform version 12 general availability notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noopener noreferrer" href="https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-13"&gt;Terraform version 13 general availability notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noopener noreferrer" href="https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-14-general-availability"&gt;Terraform version 14 general availability notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/warrensbox/terraform-switcher/" rel="noopener noreferrer"&gt;Terraform Switcher project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://terratest.gruntwork.io/docs/#testing-best-practices" rel="noopener noreferrer"&gt;Best practices testing with terratest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noreferrer noopener" href="https://github.com/tfsec/tfsec"&gt;TFSec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noreferrer noopener" href="https://github.com/bridgecrewio/checkov"&gt;Bridgecrew checkov&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noreferrer noopener" href="https://github.com/terraform-compliance/cli"&gt;Terraform compliance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noreferrer noopener" href="https://github.com/cloudskiff/driftctl"&gt;Driftctl tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noreferrer noopener" href="https://docs.chef.io/inspec/"&gt;Chef InSpec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lollyrock.com/posts/inspec-terraform/" rel="noreferrer noopener"&gt;Christoph Hartmann blog post how to use Inspec with terraform&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/k1LoW/awspec" rel="noopener noreferrer"&gt;AWS Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noreferrer noopener" href="https://github.com/open-policy-agent/conftest"&gt;Conftest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel="noreferrer noopener" href="https://www.blokje5.dev/posts/validating-terraform-plans/"&gt;Blog post from Lennard Eijsackers on Conftest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The recordings of my terminal were done using &lt;a href="https://terminalizer.com/" rel="noopener noreferrer"&gt;terminalizer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;



</description>
      <category>terraform</category>
      <category>devops</category>
      <category>terratest</category>
      <category>inspec</category>
    </item>
    <item>
      <title>Container orchestration in AWS: comparing ECS, Fargate and EKS</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Sun, 21 Oct 2018 15:31:12 +0000</pubDate>
      <link>https://dev.to/diogoaurelio/container-orchestration-in-aws-comparing-ecs-fargate-and-eks-56d1</link>
      <guid>https://dev.to/diogoaurelio/container-orchestration-in-aws-comparing-ecs-fargate-and-eks-56d1</guid>
      <description>&lt;p&gt;Before rushing into the new cool kid, namely AWS EKS, AWS hosted offering of Kubernetes, you might want to understand how it works underneath and compares to the already existing offerings. In this post we focus on distinguishing between the different AWS container orchestration solutions out there, namely AWS ECS, Fargate, and EKS, as well as comparing their pros and cons.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Before we dive into comparisons, let us summarize what each product is about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ECS&lt;/strong&gt; was the first container orchestration tool offering by AWS. It essentially consists of EC2 instances which have docker already installed, and run a Docker container which talks with AWS backend. Via ECS service you can either launch tasks - unmonitored containers suited usually for short lived operations - and services, containers which AWS monitors and guarantees to restart if they go down by any reason. Compared to Kubernetes, it is quite simpler, which has advantageous and disadvantages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fargate&lt;/strong&gt; was the second service offering to come, and is intended to abstract all everything bellow the container (EC2 instances where they run) from you. In other words, a pure Container-as-a-Service, where you do not care where that container runs. Fargate followed two core technical advancements made in ECS: possibility to assign ENI directly and dedicated to a Container and integration of IAM on a container level. We will get into more detail on this later.&lt;/p&gt;

&lt;p&gt;The following image sourced from &lt;a href="https://aws.amazon.com/blogs/compute/aws-fargate-a-product-overview/" rel="noopener noreferrer"&gt;AWS blog here&lt;/a&gt; illustrates the difference between ECS and Fargate services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2018%2F10%2Ffargate-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdatacenternotes.files.wordpress.com%2F2018%2F10%2Ffargate-1.png" alt="fargate-1" width="800" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EKS&lt;/strong&gt; is the latest offering, and still only available on some Regions. With EKS you can abstract some of the complexities of launching a Kubernetes Cluster, since AWS will now manage the Master Nodes - the control plane. Kubernetes is a much richer container orchestrator, providing features such as network overlay, allowing you to isolate container communication, and storage provisioning. Needless to say, it is also much more more complex to manage, with a bigger investment in terms of DevOps effort.&lt;/p&gt;

&lt;p&gt;Like Kubernetes, you can also use kubectl to communicate with EKS cluster. You will need to configure the &lt;a href="https://github.com/kubernetes-sigs/aws-iam-authenticator" rel="noopener noreferrer"&gt;AWS IAM authenticator locally to communicate with your EKS cluster&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Let us start with costs, the number one usual favorite suspect that Software Developers like to neglect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ECS&lt;/strong&gt;, is a simple service, where the control plane is abstracted away by AWS. You simply launch Worker nodes, which consist of EC2 instance with Docker installed, and a Container daemon running which contains the minimum metadata to know to which cluster it belongs to, and to receive instructions from AWS ECS control plane. Thus, with ECS you only pay per Worker node, read EC2 instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fargate&lt;/strong&gt; abstracts from you the hosting platform of containers - the EC2 instances. This obviously means that you pay a premium per container, compared to ECS. So yes, the cost per Container in Fargate will naturally be higher. On the other hand, and to perform a fair comparison with pure ECS, you should also take into consideration maintenance costs associated with ECS. The hours invested troubleshooting, upgrading ECS instance agents, updating EC2 instance packages, etc., is translated in the form of salaries. Thus, should not be forgotten.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EKS&lt;/strong&gt;, being Kubernetes under the hood,  requires Master nodes always running to monitor the cluster, the EKS control plane. This does not come for free, and will cost you minimum pro cluster 0.20 US Dollars/ hour, which amounts to 144$ pro month. This just to start playing around, without any Worker node. From here on, you only pay the normal price for EC2 instances you launch for Worker nodes, just like the ECS offering.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Auto-scaling&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ECS&lt;/strong&gt; allows you to scale at the task level. Remember: a task maybe one or more containers. Much like EC2, you can configure rules to scale the number of tasks running. However, these are containers running on EC2 instances, which may not have available CPU or RAM resources. So in practice, the trick here is to define another Auto-scaling rule at the ECS cluster level, where you define scale up or down based on the CPU or RAM reservation on the cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fargate&lt;/strong&gt;, as expected, makes the auto-scaling much easier. Here you simply need to define it at the task level, and you are good to go.&lt;/p&gt;

&lt;p&gt;More on &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-auto-scaling.html" rel="noopener noreferrer"&gt;ECS/Fargate auto-scaling can be found here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just recently &lt;a href="https://aws.amazon.com/blogs/opensource/horizontal-pod-autoscaling-eks/" rel="noopener noreferrer"&gt;AWS introduced integration with Kubernetes Horizontal Pod Autoscaler (HPA) for EKS&lt;/a&gt;. Much like ECS, this will  allow you to scale on the pod level, which means again that you will also need to scale on the EC2 level to support pod growth. More on getting started with &lt;a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/" rel="noopener noreferrer"&gt;HPA here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, if you already have an EKS cluster running, make sure your &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/platform-versions.html" rel="noopener noreferrer"&gt;EKS version supports HPA&lt;/a&gt;. All new EKS clusters will be launched with platform version eks.2+, which means they already support HPA at the time of writing this blog post.&lt;/p&gt;

&lt;p&gt;Let us now dive deeper technically in the three main Networking aspects that distinguish the three services.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Networking: Traffic Load Balancing&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Until AWS integrates EKS with their more sophisticated load balancers, namely Application LB and Network LB, traffic flow from a networking perspective will remain very inefficient. Since EKS only supports classic AWS ELB, traffic is randomly and blindly distributed among EC2 instances, and be prone to multi-hop traveling.&lt;/p&gt;

&lt;p&gt;Both ECS and Fargate cleanly integrate with AWS ALB and Network LB, allowing you directly point at the intended containers. Cloudnout provide very good illustrations on &lt;a href="https://cloudonaut.io/eks-vs-ecs-orchestrating-containers-on-aws/" rel="noopener noreferrer"&gt;their blog post&lt;/a&gt; on this topic.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Networking: ENI&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Being able to assign a network card directly to a container might not seem like that big of a deal at first sight. However, effectively this means a higher level of security. This way you are able to assign a Security Group dedicated for that individual container, rather that simply opening all ports for the whole cluster.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;ECS&lt;/strong&gt;, you have the option to associate an ENI directly with a container, by choosing to launch a task in "awsvpc" mode. However - there is always a but, isn't there ? - the maximum number of ENIs (read Virtual NICs) that can be assigned to each EC2 instance varies according to EC2 type; and one could argue that it is rather limited from 2 to 15 at the current time being. So if you are running a lot of small containers, this scenario effectively would mean creating a very big EC2 cluster of small EC2 instances. &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#AvailableIpPerENI" rel="noopener noreferrer"&gt;The following list exemplifies this statement&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With EKS, on the other hand, you have the option to assign a dedicated network interface a a container group, what Kubernetes calls a pod. So that means all containers inside that pod will share the same internal network. However, here come the good news, you can place up to 750 pods per instance. This is a much bigger advantage for EKS.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Networking: Service Discovery&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;AWS has &lt;a href="https://aws.amazon.com/about-aws/whats-new/2018/03/introducing-service-discovery-for-amazon-ecs/" rel="noopener noreferrer"&gt;recently&lt;/a&gt; launched service discovery for ECS/Fargate. This was a key differentiator that the ECS was lagging behind compared to Kubernetes, which uses network overlay to allow essentially container level DNS.&lt;/p&gt;

&lt;p&gt;However it needs to be noted that only Containers launched in "awsvpc" network mode support this feature.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Security Policy Control (AWS IAM integration)&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Returning to the security topic, another pro in favor of ECS/Fargate is the possibility to assign IAM instance profiles dedicated to the Container. What do these policies specify? Well basically access to all other AWS resources, such as S3 buckets, databases/datawarehouses such as DynamoDB, Aurora, Redshift, queing systems such as SQS and Kinesis, etc. You get the picture.&lt;/p&gt;

&lt;p&gt;Again, the argument here is similar to the ENI: assigning dedicated IAM roles on a container level is order of magnitudes safer than on the EC2 instance level.&lt;/p&gt;

&lt;p&gt;ECS and Fargate allow you to specify permissions at the container level. Currently, EKS does not allow you to so. This means you are limited to constrain permissions at the Workers/EC2 level.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Container Registry - AWS ECR&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Nothing special here: as expected, all services integrate with AWS container registry, allowing you to pull from your internal AWS registry.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;To conclusion, ECS and Fargate have a much tighter integration with AWS ecosystem. Kubernetes, on the other hand, has a much tighter integration with generic open source ecosystem, allowing you also to be more Cloud vendor agnostic.&lt;/p&gt;

&lt;p&gt;As usual, here is a compilation of some of the useful sources used to write this post which might serve you as well:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://medium.com/containers-on-aws/choosing-your-container-environment-on-aws-with-ecs-eks-and-fargate-cfbe416ab1a" rel="noopener noreferrer"&gt;Introduction comparison of AWS docker orchestration tools from Nathan Peck &lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://cloudonaut.io/eks-vs-ecs-orchestrating-containers-on-aws/" rel="noopener noreferrer"&gt;Great technical summary from Cloudnaut&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://medium.com/@remy.dewolf/aws-fargate-first-hands-on-experience-and-review-1b52fca2148e" rel="noopener noreferrer"&gt;Fargate introduction with detailed GUI walkthrough&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-auto-scaling.html" rel="noopener noreferrer"&gt;AWS ECS/Fargate auto-scaling configuration documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/compute/introducing-cloud-native-networking-for-ecs-containers/" rel="noopener noreferrer"&gt;AWS new networking mode "awsvpc" for container level direct ENI mapping&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/compute/aws-fargate-a-product-overview/" rel="noopener noreferrer"&gt;AWS blog post about Fargate&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html" rel="noopener noreferrer"&gt;AWS documentation for ECS task roles (container level)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://hackernoon.com/quickly-spin-up-an-aws-eks-kubernetes-cluster-using-cloudformation-3d59c56b292e" rel="noopener noreferrer"&gt;Tutorial walk-through with AWS EKS and ClodFormation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/aws/amazon-ecs-service-discovery/" rel="noopener noreferrer"&gt;ECS supports service discovery&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/opensource/horizontal-pod-autoscaling-eks/" rel="noopener noreferrer"&gt;EKS Horizontal auto-scaling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>fargate</category>
      <category>ecs</category>
      <category>eks</category>
    </item>
    <item>
      <title>Decrypting correctly parameters from AWS SSM</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Sun, 21 Oct 2018 15:29:54 +0000</pubDate>
      <link>https://dev.to/diogoaurelio/decrypting-correctly-parameters-from-aws-ssm-3lhf</link>
      <guid>https://dev.to/diogoaurelio/decrypting-correctly-parameters-from-aws-ssm-3lhf</guid>
      <description>&lt;p&gt;Today is yet short one, but ideally will already save a whole lot of headaches for some people.&lt;/p&gt;

&lt;p&gt;Scenario: You have stored the contents of a string using AWS SSM parameter store (side note: if you are not using it yet, you should definitely have a look), but when retrieving it  decrypted via CLI, you notice that the string has new lines ('\n') substituted by spaces (' ').&lt;/p&gt;

&lt;p&gt;In my case, I was storing a private SSH key encrypted to integrate with some Ansible scripts triggered via AWS CodePipeline + CodeBuild. CodeBuild makes it realy easy to access secrets stored in SSM store, however it was retrieving my key incorrectly, which in term domino-crashed my ansible scripts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aws/aws-cli/issues/2596" rel="noopener"&gt;Here you can also confirm more people are facing this issue&lt;/a&gt;. After following the suggestion of using AWS SDK - in my case with python boto3 - it &lt;em&gt;finally&lt;/em&gt; worked. So here is a gist to overwrite an AWS SSM parameter, and then retrieving it back:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ssm</category>
      <category>python</category>
    </item>
    <item>
      <title>Getting Started with Spark (part 4) -  Unit Testing</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Sun, 21 Oct 2018 15:27:52 +0000</pubDate>
      <link>https://dev.to/diogoaurelio/getting-started-with-spark-part-4----unit-testing-26a5</link>
      <guid>https://dev.to/diogoaurelio/getting-started-with-spark-part-4----unit-testing-26a5</guid>
      <description>

&lt;p&gt;Alright quite a while ago (already counting years), I published a tutorial series focused on helping people getting started with Spark. Here is an outline of the previous posts:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://datacenternotes.com/2015/11/01/getting-started-with-spark-in-pythonscala-part-1/" rel="noopener"&gt;Part 1 Getting Started - covers basics on distributed Spark architecture, along with Data structures (including the old good RDD collections (!), whose use has been kind of deprecated by Dataframes)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://datacenternotes.com/2015/11/01/getting-started-with-the-spark-part-2-sparksql/" rel="noopener"&gt;Part 2 intro to Dataframes&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://datacenternotes.com/2016/10/03/getting-started-with-spark-part-3-udfs-window-functions/" rel="noopener"&gt;Part 3 intro to UDFs and Window Functions &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the meanwhile Spark has not decreased popularity, so I thought I continued updating the same series. In this post we cover an essential part of any ETL project, namely Unit testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/diogoaurelio/pyspark-bootstrap-repo" rel="noopener"&gt;For that I created a sample repository&lt;/a&gt;, which is meant to serve as boiler plate code for any new Python Spark project.&lt;/p&gt;

&lt;p&gt;Let us browse through the main job script. Please note that the repository might contain updated version, which might defer in details with the next gist.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;  &lt;/div&gt;

&lt;p&gt;The previous gist recovers the same example used in the previous post on UDFs and Window Functions.&lt;/p&gt;

&lt;p&gt;Here is an example how we could test our "amount_spent_udf" function:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;  &lt;/div&gt;

&lt;p&gt;Now note the first line on the unit tests script, which is the secret sauce to load a spark context for your unit tests. Bellow is the code that creates the "spark_session" object passed as an argument to the "test_amount_spent_udf" function.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;  &lt;/div&gt;

&lt;p&gt;And that is it. We strongly encourage you to have a look on the &lt;a href="https://github.com/diogoaurelio/pyspark-bootstrap-repo" rel="noopener"&gt;correspondent git repository, where we specify detailed instructions how to run it locally&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And that is it for today, hope it helped!&lt;/p&gt;


</description>
      <category>apachespark</category>
      <category>python</category>
    </item>
    <item>
      <title>Versioning in data projects</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Tue, 25 Sep 2018 05:35:11 +0000</pubDate>
      <link>https://dev.to/diogoaurelio/versioning-in-data-projects-5e4o</link>
      <guid>https://dev.to/diogoaurelio/versioning-in-data-projects-5e4o</guid>
      <description>

&lt;p&gt;Reproducibility is a pillar in science, and version control via git has been a blessing to it. For pure Software Engineering it works perfectly. However, machine learning projects are not just only about code, but rather also about the data. The same model trained with two distinct data sets can produce completely different results.&lt;/p&gt;

&lt;p&gt;So it comes with no surprise when I stumble with csv files on git repos of data teams, as they struggle to keep track of code and metadata. However this cannot be done for today's enormous datasets. I have seen several hacks to solve this problem, none of them bullet proof. This post is not about those hacks, rather about an open source solution for it: &lt;a href="https://dvc.org/" rel="noopener"&gt;DVC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SibN27D1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datacenternotes.files.wordpress.com/2018/09/dvc_flow_large.png" class="article-body-image-wrapper"&gt;&lt;img class="  wp-image-4157 aligncenter" src="https://res.cloudinary.com/practicaldev/image/fetch/s--SibN27D1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://datacenternotes.files.wordpress.com/2018/09/dvc_flow_large.png" alt="dvc_flow_large" width="538" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us exemplify by using a kaggle challenge: &lt;a href="https://www.kaggle.com/c/house-prices-advanced-regression-techniques" rel="noopener"&gt;predicting house prices with Advanced Regression Techniques&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now clone the repo:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:diogoaurelio/kaggle-house-prices.git
&lt;span class="nb"&gt;cd &lt;/span&gt;kaggle-house-prices
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this post we be needing several python packages - such as dvc, boto3, and machine learning related packages - so we are going to exemplify how to configure a local anaconda and install all dependencies required for this tutorial:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;conda &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; kaggle &lt;span class="nv"&gt;python&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.6 &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;source &lt;/span&gt;activate kaggle
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; pip_requirements.txt
conda &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; conda-forge &lt;span class="nt"&gt;--file&lt;/span&gt; conda_requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Alternatively, if you just want to install &lt;a href="https://dvc.org/doc/get-started/install" rel="noopener"&gt;DVC, you can do, for example, also via pip:&lt;/a&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;dvc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Coming back to the git repository, you will notice that there is a directory named ".dvc".&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;.dvc/
├── cache
└── config

1 directory, 1 file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This was created when I locally ran the command "dvc init", which is meant to be abstracted away from the user (as the dot in the directory name would suggest).&lt;/p&gt;

&lt;p&gt;Now comes the interesting part. DVC has the concept of a remote data store, which is used to &lt;a href="https://dvc.org/doc/use-cases/data-and-model-files-versioning" rel="noopener"&gt;share and version data&lt;/a&gt;. Currently in practice can be of &lt;a href="https://dvc.org/doc/get-started/configure" rel="noopener"&gt;six types: local directory, AWS S3, Google Cloud Storage, Azure Blob Storage, SSH, or HDFS&lt;/a&gt;.  To configure a remote data store simply map a local directory to the remote data store. In this case I mapped the "data" directory - which is git ignored - to the remote store as follows:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;dvc remote add &lt;span class="nt"&gt;-d&lt;/span&gt; data s3://kaggle-datasets-store/house-prices
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next let us download data from &lt;a href="https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data" rel="noopener"&gt;kaggle house prices competition&lt;/a&gt; into the "data" directory, such as the "train.csv". You can also download from the terminal using the following command:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;kaggle competitions download &lt;span class="nt"&gt;-c&lt;/span&gt; house-prices-advanced-regression-techniques
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Now let us add it to our data versioned store:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;dvc add data/train.csv 

&lt;span class="c"&gt;# you should see an output similar to the following:&lt;/span&gt;
Adding &lt;span class="s1"&gt;'data/train.csv'&lt;/span&gt; to &lt;span class="s1"&gt;'data/.gitignore'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Saving &lt;span class="s1"&gt;'data/train.csv'&lt;/span&gt; to cache &lt;span class="s1"&gt;'.dvc/cache'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Created &lt;span class="s1"&gt;'hardlink'&lt;/span&gt;: .dvc/cache/80/ccab65fb115cbad143dbbd2bcd5577 -&amp;amp;gt&lt;span class="p"&gt;;&lt;/span&gt; data/train.csv
Saving information to &lt;span class="s1"&gt;'data/train.csv.dvc'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see in the standard output, this command will generate a "train.csv.dvc" file, which contains a metadata about our "train.csv" file. Essentially a md5 hash of a pointer to the file.&lt;/p&gt;

&lt;p&gt;To push this data into S3 is simple:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;dvc push &lt;span class="nt"&gt;-r&lt;/span&gt; data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that I am specifying the "data" repository. If you want to check out dvc configuration, just have a look at .dvc/config file. You will notice that I have a AWS profile configured, which matches my local aws CLI credentials file. Here is how you can configure your local aws credentials to access S3 bucket:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will prompt you for the credentials plus default region and output format, and store them in "~/.aws/config" and "~/.aws/credentials". If you would like to have credentials for multiple AWS accounts, then aws cli allows you to configure "profiles" to store these. Simply do as follows:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure &lt;span class="nt"&gt;--profile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you look at my ".dvc/config" you will notice that I have configured my AWS profile with alias "diogo" for my own AWS account.&lt;/p&gt;

&lt;p&gt;I did not find documentation how to explicitly do this configuration, so in case you are wondering which other configurations you can change, you can do as I did and just have a look at the &lt;a href="https://github.com/iterative/dvc/blob/master/dvc/config.py" rel="noopener"&gt;DVC source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After pushing the data to S3 you will be able to share it with other colleagues. They simply need to run:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;dvc pull
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that in our case you will not be able to download from my S3 bucket, as it is not configured for public access, which will also be the same case for your company data.&lt;/p&gt;

&lt;p&gt;Let us now tie everything together, namely our models with the data. For this I used the &lt;a href="https://www.kaggle.com/dansbecker/xgboost" rel="noopener"&gt;code from a python notebook using XGBoost&lt;/a&gt; from &lt;a href="https://www.kaggle.com/dansbecker" rel="noopener"&gt;DanB&lt;/a&gt;.   DVC has the run command, in which you are able to specify which dependencies as well as required outputs. In our case:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;dvc run &lt;span class="nt"&gt;-d&lt;/span&gt; data/train.csv &lt;span class="nt"&gt;--file&lt;/span&gt; xgboost_base_model.dvc &lt;span class="nt"&gt;-O&lt;/span&gt; data/xgboost_base.pkl python src/xgboost_base.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will create a file named "xgboost_base_model.dvc" containing something similar to:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;cmd: python src/xgboost_base.py
deps:
- md5: 80ccab65fb115cbad143dbbd2bcd5577
path: data/train.csv
md5: e10b323ae9bb3887626a7dc97d6a64d6
outs:
- cache: &lt;span class="nb"&gt;false
&lt;/span&gt;md5: d53d8021c4c362b88da61c347af52196
path: data/xgboost_base.pkl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that this dvc file contains a hash of both our "xgboost_base.py" script, along with a hash of the data. Now the beauty of this is that we can now simply "dvc repro xgboost_base_model.dvc" and it will detect if either the data or the script have changed. If no change has occured, then it will simply output: "Pipeline is up to date. Nothing to reproduce."&lt;/p&gt;

&lt;p&gt;After having completed this, we would now be ready to add all our code to .git, including "dvc repro xgboost_base_model.dvc". This allows other people to also be able to reproduce the same results.&lt;/p&gt;

&lt;p&gt;This example was fairly simple. However more interesting is chaining dvc run command with several steps in order to build pipelines - a multi-stage operations that define your full Machine Learning process. We strongly encourage you to have a look at &lt;a href="https://dvc.org/doc/tutorial/define-ml-pipeline" rel="noopener"&gt;DVC's own tutorial about pipelines&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;


</description>
      <category>dataversioncontrol</category>
      <category>kaggle</category>
    </item>
    <item>
      <title>AWS Server-less data pipelines with Terraform - Part 2</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Tue, 25 Sep 2018 05:31:23 +0000</pubDate>
      <link>https://dev.to/diogoaurelio/aws-server-less-data-pipelines-with-terraform---part-2-3fhg</link>
      <guid>https://dev.to/diogoaurelio/aws-server-less-data-pipelines-with-terraform---part-2-3fhg</guid>
      <description>&lt;p&gt;Alright, it's time for the second post of our sequence focusing on AWS options to setup pipelines in a server-less fashion. The topics that we are covering throughout this series are:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://dev.to/diogoaurelio/aws-server-less-data-pipelines-with-terraform---part-1-9jd" rel="noopener"&gt;Part 1: Python Lambda to load data into AWS Redshift datawarehouse&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://dev.to/diogoaurelio/aws-server-less-data-pipelines-with-terraform---part-2-3fhg"&gt;Part 2: Terraform setup of Lambda function for automatic trigger&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;Part 3: Example AWS Step function to schedule a cron pipeline with AWS Lambda&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post we complement the previous one, by providing infrastructure-as-code with &lt;a href="https://www.terraform.io/" rel="noopener"&gt;Terraform&lt;/a&gt; for deployment purposes. We are strong believers of a DevOps approach also to Data Engineering, also known as "DataOps". Thus we thought it would make perfect sense to share a sample Terraform module along with Python code.&lt;/p&gt;

&lt;p&gt;To recap, so far we have Python code that, if triggered by a AWS event on a new S3 object, will connect to Redshift, and issue SQL Copy command statement to load that data into a given table. Next we are going to show how to configure this with Terraform code.&lt;/p&gt;

&lt;p&gt;As usual, all the code for this post is &lt;a href="https://github.com/diogoaurelio/serverless-pipelines-blog-series" rel="noopener"&gt;available publicly in this github repository&lt;/a&gt;. In case you haven't yet, you will need to install terraform in order follow along this post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First lets start with our proposed structure. We have found it useful to distinguish and isolate dedicated Terraform code according to the environment it needs to be deployed in. An environment can mean different things to different companies. The most common environments are  dev/staging/production, which allow one to safely test code in a controlled setup. However other use cases exist, such as different VPCs or AWS accounts across different tech teams.&lt;/p&gt;

&lt;p&gt;For this reason, we actually require one to export ENVIRONMENT variable in the beginning, which is used as a key for the Makefile to find the correct directory to deploy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;span class="c"&gt;# create a file for terraform secret variables hosting: "$(ENVIRONMENT).tfvars", which our Makefile expects&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;terraform/environments/dev/dev.tfvars
&lt;span class="c"&gt;# Verify what the terraform code plans to deploy&lt;/span&gt;
make plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The make plan command will allow you to get started. Note that Terraform will use your default credentials that you have configured in "~/.aws/credentials". If you want to use different, one simple way (among several) is to export aws access key and secret values before running the command.&lt;/p&gt;

&lt;p&gt;Whenever one runs "make plan", this will run three terraform commands: "terraform init", "terraform update" and "terraform plan". The terraform "init" and "update" are specially useful for the first time you initialize terraform, downloading all specific provider packages you require, and updating whenever you add new requirements.&lt;/p&gt;

&lt;p&gt;At the time of writing this blog post, here is what I have got printed out when running make plan for the first time:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Initializing modules...
- module.redshift_loader_lambda
  Getting &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"github.com/diogoaurelio/terraform-aws-lambda-module"&lt;/span&gt;

Initializing provider plugins...
- Checking &lt;span class="k"&gt;for &lt;/span&gt;available provider plugins on https://releases.hashicorp.com...
- Downloading plugin &lt;span class="k"&gt;for &lt;/span&gt;provider &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1.36.0&lt;span class="o"&gt;)&lt;/span&gt;...
- Downloading plugin &lt;span class="k"&gt;for &lt;/span&gt;provider &lt;span class="s2"&gt;"archive"&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1.1.0&lt;span class="o"&gt;)&lt;/span&gt;...

The following providers &lt;span class="k"&gt;do &lt;/span&gt;not have any version constraints &lt;span class="k"&gt;in &lt;/span&gt;configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"..."&lt;/span&gt; constraints to the
corresponding provider blocks &lt;span class="k"&gt;in &lt;/span&gt;configuration, with the constraint strings
suggested below.

&lt;span class="k"&gt;*&lt;/span&gt; provider.archive: version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.1"&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt; provider.aws: version &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.36"&lt;/span&gt;

Terraform has been successfully initialized!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Now, since we have not yet filled our "dev.tfvars", you will notice short after the following errors:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;##### 1) VPC details: VPC ID and private subnets to use (where the lambda will run)&lt;/span&gt;
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: private_subnet_ids
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: vpc_id

&lt;span class="c"&gt;##### 2) Redshift DB details&lt;/span&gt;
&lt;span class="c"&gt;# The IAM Redshift Role used to issue COPY commands and load data into Redshift&lt;/span&gt;
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: redshift_data_loader_lambda_iam_role
&lt;span class="c"&gt;# The intended Redshift dabase name&lt;/span&gt;
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: redshift_data_loader_lambda_db_name
&lt;span class="c"&gt;# Redshift endpoint or Route53 record to use&lt;/span&gt;
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: redshift_data_loader_lambda_db_host
&lt;span class="c"&gt;# Redshift DB user to use&lt;/span&gt;
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: redshift_data_loader_lambda_db_user
&lt;span class="c"&gt;# Redshift User password to use&lt;/span&gt;
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: redshift_data_loader_lambda_db_password

&lt;span class="c"&gt;# The ARN and name of the bucket where data is being stored (which should be loaded into Redshift)&lt;/span&gt;
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: s3_bucket_arn
Error: Required variable not &lt;span class="nb"&gt;set&lt;/span&gt;: s3_bucket_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt; &lt;/p&gt;

&lt;p&gt;The "*.tfvars" are gitignored. You should now add the details of your own setup into your "dev.tfvars", in case you want to test drive this code. After you do this, run again "make plan" to see what terraform plans to deploy.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core AWS Lambda function module &lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OK, before we deploy, let us have a look on the terraform code,  starting with the Lambda function. Here we are using a specific version of a generic module that we had previously created for Lambda functions. The beauty of this module is its flexibility. For example, you can launch the Lambda inside or outside a VPC, you can attach how many additional IAM policies you desire, and specify a SNS or SQS ARN for Dead Letter Queue (DLQ) for failure handling.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The first thing you can notice is the usage of a different &lt;a href="https://github.com/diogoaurelio/terraform-aws-lambda-module" rel="noopener"&gt;dedicated git repository via the "source" keyword&lt;/a&gt; for the Lambda module. Go ahead and have a look, this is also &lt;a href="https://github.com/diogoaurelio/terraform-aws-lambda-module" rel="noopener"&gt;public, and we have been using it successfully in several projects&lt;/a&gt;. Also note that one can pin point different versions of a given repository, which maps to repository tags. This reassures retro-compatibility and non breaking  progress on each module.&lt;/p&gt;

&lt;p&gt;The second thing you might notice is that we are passing paths of the Lambda function. The reason behind it is that our terraform lambda module will proactively zip our lambda's "src" module; &lt;a href="https://github.com/diogoaurelio/serverless-pipelines-blog-series" rel="noopener"&gt;in our repository located in&lt;/a&gt;: "etl/lambda/redshift/src".&lt;/p&gt;

&lt;p&gt;The second is that we are instantiating the lambda inside a VPC. As mentioned before,  this is optional - the module is flexible enough for you to chose if you want to have the lambda being executed inside a specific VPC or not. In our case, we are assuming that your &lt;em&gt;&lt;span&gt;Redshift cluster is indeed inside a private subnet&lt;/span&gt;&lt;/em&gt; (as advisable), and thus we need to execute the Lambda function inside that VPC to be able to connect to Redshift.&lt;/p&gt;

&lt;p&gt;Please remember to either open Redshift's Security Group either to the specified subnet CIDR, or to our Lambda's security group id.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lambda environment variables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next point up the list are environmental variables. The module accepts those via the variable "&lt;em&gt;lambda_env_vars&lt;/em&gt;". We have defined those via terraform "&lt;a href="https://www.terraform.io/docs/configuration/locals.html" rel="noopener"&gt;locals&lt;/a&gt;", with &lt;span&gt;"&lt;/span&gt;&lt;span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;local.redshift_loader_lambda_env_vars&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;". Let us have a look at those briefly:&lt;/span&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We are passing mainly all parameters which the lambda function uses to connect to Redshift DB. Note also that we are not passing the explicit Redshift DB password, but rather the name of the parameter stored in &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html" rel="noopener"&gt;SSM store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You may ask yourself why we are doing this, considering that this lambda module is already encrypting environmental variables by default. Yes, the lambda module creates automatically a KMS key for this purpose. We are doing it in the end more for illustration purposes, although one could argue that concealing these variables in the AWS GUI is also relevant so that not all users that have access to it can discover the password.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lambda permissions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will verify that we simplified this code in several aspects. A good example are the broad permissions passed to the lambda function for all buckets, among others. A (much) better approach would be to clearly restrict to a small white list of resources. But, for the sake of the tutorial, we will relax on some of these aspects that you should consider when bringing this inside your company.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Note that we are passing permissions to use KMS keys, which is specially relevant if your buckets are encrypted.&lt;/p&gt;

&lt;p&gt;Moreover, we are also passing permission to access the SSM parameter store specific DB password.&lt;/p&gt;

&lt;p&gt;The final statement provides the Lambda function permissions to publish in a specific SNS topic, which leads us to the final point: failure handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lambda Failure handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Currently Lambda functions executed asynchronously - as is the case of S3 triggered Lambdas - will always&lt;strong&gt;&lt;span&gt; retry twice&lt;/span&gt;&lt;/strong&gt; on failure. the only thing you have to do is to configure the Dead Letter Queue (DLQ) configured, by passing a SNS topic to publish in case the maximum number of retries is reached. Note: Please make sure you always double check &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/dlq.html" rel="noopener"&gt;in AWS documentation&lt;/a&gt; for updates to find the current limits and default behaviors.&lt;/p&gt;

&lt;p&gt;In our case, we have configured a SNS topic, so that subscribers can subscribe and be alerted of failure. For example, one can add an email subscriber, and be notified on Lambda failure. Unfortunately,  Terraform does not support the creation of SNS Email subscriptions as &lt;a href="https://www.terraform.io/docs/providers/aws/r/sns_topic_subscription.html" rel="noopener"&gt;explained here&lt;/a&gt;. Thus either subscribe manually, or use CloudFormation/custom script for this task.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploying the code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cool, we are ready to rock&amp;amp;roll. Just open your terminal and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
make apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will prompt for confirmation, before deploying.&lt;/p&gt;

&lt;p&gt;Go ahead and create a table in Redshift, such as for example "kpi". Next upload a new CSV file into your S3 bucket with a prefix "kpi" (so that a key "kpi/your_file.csv" is saved in the bucket). You should be able to see data in your Redshift table in less than a minute. Moreover, you can also consult your Cloudwatch logs, and verify that the Lambda function has executed successfully.&lt;/p&gt;

&lt;p&gt;Congratulations, you have deployed a asynchronous pipeline using infrastructure-as-code.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;As usual, let us summarize the sources used in this post:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://github.com/diogoaurelio/serverless-pipelines-blog-series" rel="noopener"&gt;Source repository for this blog post&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/diogoaurelio/terraform-aws-lambda-module" rel="noopener"&gt;Source repository for the lambda module&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html" rel="noopener"&gt;AWS SSM parameter store for storing secrets encrypted&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/dlq.html" rel="noopener"&gt;AWS Lambda DLQ documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;We hope you found this tutorial useful. Also please do not hesitate to contact us at &lt;a href="https://mklabs.io/" rel="noopener"&gt;mklabs&lt;/a&gt;, or me directly - diogo [at] mklabs [dot] io - if you need any help on your project, be it cloud/devOps/Big Data/ML.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>redshift</category>
      <category>terraform</category>
    </item>
    <item>
      <title>AWS Server-less data pipelines with Terraform - Part 1</title>
      <dc:creator>diogoaurelio</dc:creator>
      <pubDate>Mon, 03 Sep 2018 07:47:41 +0000</pubDate>
      <link>https://dev.to/diogoaurelio/aws-server-less-data-pipelines-with-terraform---part-1-9jd</link>
      <guid>https://dev.to/diogoaurelio/aws-server-less-data-pipelines-with-terraform---part-1-9jd</guid>
      <description>&lt;p&gt;This post is the first of sequence of posts focusing on AWS options to setup pipelines in a serverless fashion. The topics that we all cover throughout the whole series are:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://dev.to/diogoaurelio/aws-server-less-data-pipelines-with-terraform---part-1-9jd"&gt;Part 1: Python Lambda to load data into AWS Redshift datawarehouse&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://dev.to/diogoaurelio/aws-server-less-data-pipelines-with-terraform---part-2-3fhg" rel="noopener"&gt;Part 2: Terraform setup of Lambda function for automatic trigger&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;Part 3: Example AWS Step function to schedule a cron pipeline with AWS Lambda&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post we lean towards another strategy to setup data pipelines, namely event triggered. That is, rather than being scheduled to execute with a given frequency, our traditional pipeline code is executed immediately triggered by a given event. Our example consists of a demo scenario for immediately and automatically loading data that is stored in S3 into Redshift tutorial.&amp;lt;!--more--&amp;gt;&lt;/p&gt;

&lt;p&gt;Note that triggers are not something new exclusive from a Cloud paradigm. Most databases, for example, have triggers that one can setup to execute User Defined Functions. However, the multitude of integrations that AWS Lambda functions have with its own services is quite impressive and useful. In this case, it is AWS S3 that can trigger the execution of the Lambda function.&lt;/p&gt;

&lt;p&gt;The typical first use-case that people think for integrating S3 with Lambda functions via triggers is for image processing, such as thumbnails. In this post we are using it for a second use case, namely near real time data imports to AWS Redshift. From the developers perspective, the effort is quite minimal, since AWS does all the lifting in the background.&lt;/p&gt;

&lt;p&gt;Without further ado, let us dive into the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Lambda Function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Python code is a very simple Redshift loading code. We will later show in the terraform code, but important to note is that an S3 bucket will be configured to trigger/invoke our Lambda function whenever a new object/key is saved on that S3 bucket. This trigger is active for the whole Bucket, which means any new file copied into the bucket will trigger our Lambda function.&lt;/p&gt;

&lt;p&gt;AWS will pass to the lambda function's parameters the Bucket which triggered the function, as well as the new S3 key. Now there is a very important assumption that you need to know, namely that we assume that this key is created with a given prefix, which is the same as the target Redshift table you want it to be imported. For example, if you copy a new file into "kpis/new_file.csv", the lambda will split on "/", and use "kpis" as the table name in Redshift. And there you go, you are ready to see the code.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The lambda function code is quite simple. It simply builds a string with the Redshift Copy command, implicitly assuming a CSV file as the underlying format. Why use "Copy command"? This is one the &lt;a href="https://docs.aws.amazon.com/redshift/latest/dg/c_loading-data-best-practices.html" rel="noopener"&gt;Redshift best practices main recommendations&lt;/a&gt;, and provides two main benefits: speed (data is loaded in parallel) and data storage optimizations.&lt;/p&gt;

&lt;p&gt;As a side comment, please do not assume we are recommending using CSV file format. We just chose it due to the easiness that one can take the code in this tutorial and test it live, rather then using more optimized binary formats, such as Avro or Parquet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secrets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Note that the lambda function is receiving all relevant parameters and secrets via environment variables. So, besides the simple bureaucracies for the copy command, there is just one thing more we would just like to highlight. For Redshift's user password, we are using an additional AWS service, namely &lt;strong&gt;AWS SSM parameter store&lt;/strong&gt;. This is a relatively recent service (from 2016 if I am not mistaken) that allows you to store secrets encrypted using KMS key. Now the cool thing about it is that now you can control granularly exactly which instances and roles have access to what.&lt;/p&gt;

&lt;p&gt;This means that we need to make sure we provide via IAM policy permissions for this Lambda function to use the specified SSM paramter. We will show how to do this later in the terraform code.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Last thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we end our first post, we would like to add that there are a lot of things to be improved in this lambda. One suggestion would be to guarantee deduplication, namely that the same data does not get loaded twice into Redshift. One simple way to do this is by using a database, to guarantee synchronization. This would also allow better error handling.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;We hope you found this tutorial useful. Also please do not hesitate to contact us at &lt;a href="https://mklabs.io/" rel="noopener"&gt;mklabs&lt;/a&gt;, or me directly - diogo [at] mklabs [dot] io - if you need any help on your project, be it cloud/devOps/Big Data/ML.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>redshift</category>
      <category>terraform</category>
    </item>
  </channel>
</rss>
