<?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: Jonatas de Moraes Junior</title>
    <description>The latest articles on DEV Community by Jonatas de Moraes Junior (@honatas).</description>
    <link>https://dev.to/honatas</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%2F548692%2F180a4556-f981-41c1-a8c9-826b792ce627.jpg</url>
      <title>DEV Community: Jonatas de Moraes Junior</title>
      <link>https://dev.to/honatas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/honatas"/>
    <language>en</language>
    <item>
      <title>Factory Pattern with Polymorphism on Spring</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Thu, 28 Oct 2021 20:56:45 +0000</pubDate>
      <link>https://dev.to/honatas/factory-pattern-with-polymorphism-on-spring-47e</link>
      <guid>https://dev.to/honatas/factory-pattern-with-polymorphism-on-spring-47e</guid>
      <description>&lt;p&gt;The Factory Pattern is one of the most well-known design patterns described by the Gang of Four (&lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF&lt;/a&gt;). It allows for the caller to choose wich type of class needs to be instantiated, also hiding the creation logic from the caller.&lt;/p&gt;

&lt;p&gt;However, there is a very confusing Spring mehcanic available through this here &lt;a href="https://www.baeldung.com/spring-factorybean"&gt;FactoryBean&lt;/a&gt;. Event though it has Factory in its name, it does not represent a Factory as designed by GoF, because it only allows for the creation of a single type.&lt;/p&gt;

&lt;p&gt;In this article we will explore how to implement a full-compliant GoF Factory with Spring, where the created objects are also Spring controlled beans.&lt;/p&gt;

&lt;p&gt;Let's say you have an interface Animal and two implementations Cat and Dog:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeNoise&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;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Animal&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="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeNoise&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;"Meow!"&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;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Animal&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="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeNoise&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;"Bark!"&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;By definition: "&lt;strong&gt;Factory Method&lt;/strong&gt; is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created".&lt;/p&gt;

&lt;p&gt;Ok, boring. However, what you expect is an AnimalFactory class that allows you to choose wether to get an instance of either a Cat or a Dog, right?&lt;/p&gt;

&lt;p&gt;You could create a simple AnimalFactory class which just returns a new Cat or new Dog depending on a parameter you pass. The problem is: when you call &lt;strong&gt;new&lt;/strong&gt; by yourself, the bean is not being created by Spring.&lt;/p&gt;

&lt;p&gt;So, let's start by just doing that, let's show these classes to Spring and let it control their instances. Let's annotate them with @Component:&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="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Animal&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="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeNoise&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;"Meow!"&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="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Animal&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="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeNoise&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;"Bark!"&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 Spring knows Cat and Dog, and can give us instances of them when requested. Let's now create a very simple Factory that just fulfills our requirements:&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="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnimalFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="nf"&gt;getAnimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;animalType&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animalType&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cat&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dog"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animalType&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dog&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;Ok, it works. But what if you have a thousand different animals? Let's improve this factory a bit by putting the instances in a Map:&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;enum&lt;/span&gt; &lt;span class="nc"&gt;AnimalType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;CAT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;DOG&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="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnimalFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;EnumMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AnimalType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;animalsMap&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;AnimalFactory&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;animalsMap&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;EnumMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnimalType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&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;animalsMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnimalType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CAT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cat&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;animalsMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnimalType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DOG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dog&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="nc"&gt;Animal&lt;/span&gt; &lt;span class="nf"&gt;getAnimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnimalType&lt;/span&gt; &lt;span class="n"&gt;animalType&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;animalsMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animalType&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 time we have created an Enum with the types of the animals, and also a EnumMap to contain the instances of the animals. We also have changed the signature of the getAnimal method to take the enum as parameter.&lt;/p&gt;

&lt;p&gt;This is a much better approach, but still, if we have a huge number of animal types, this class will grow accordingly with nothing but boilerplate code. And if you create a new animal type and forget to put it in the map, you may get an error somewhere else.&lt;/p&gt;

&lt;p&gt;To apply the final touches to our Factory, we will make use of a lesser known functionality of Spring: an @Autowired constructor that takes a List of objects as parameter. Since Spring knows all Animal objects, when we inject a list of that type, Spring populates that List with all known objects of that type (Cat and Dog). Below is the full final code:&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;enum&lt;/span&gt; &lt;span class="nc"&gt;AnimalType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;CAT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;DOG&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;interface&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;AnimalType&lt;/span&gt; &lt;span class="nf"&gt;getType&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeNoise&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Animal&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="nc"&gt;AnimalType&lt;/span&gt; &lt;span class="nf"&gt;getType&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;AnimalType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CAT&lt;/span&gt;&lt;span class="o"&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="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeNoise&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;"Meow!"&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="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Animal&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="nc"&gt;AnimalType&lt;/span&gt; &lt;span class="nf"&gt;getType&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;AnimalType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DOG&lt;/span&gt;&lt;span class="o"&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="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeNoise&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;"Bark!"&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="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnimalFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;EnumMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AnimalType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;animalsMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AnimalFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Animal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;animals&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;animalsMap&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;EnumMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnimalType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="nl"&gt;animal:&lt;/span&gt; &lt;span class="n"&gt;animals&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;animalsMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getType&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;animal&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="nc"&gt;Animal&lt;/span&gt; &lt;span class="nf"&gt;getAnimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnimalType&lt;/span&gt; &lt;span class="n"&gt;animalType&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;animalsMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animalType&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;Here we have created a new method in the Animal interface: getType(), that return that animal's type. At the factory's constructor, we take the List of Animals and populate our map with them. This way the code for the AnimalFactory class does not need to be changed with every new Animal created; whenever you need a new Animal, just annotate it with @Component and the Factory can create it.&lt;/p&gt;

&lt;p&gt;This is it, I hope it helps.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why VDOM vs. DOM comparison is biased and unfair</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Wed, 30 Jun 2021 18:13:55 +0000</pubDate>
      <link>https://dev.to/honatas/why-vdom-vs-dom-comparison-is-biased-and-unfair-471m</link>
      <guid>https://dev.to/honatas/why-vdom-vs-dom-comparison-is-biased-and-unfair-471m</guid>
      <description>&lt;p&gt;The most commonly used argument to justify the use of Virtual DOM is how fast it is compared to direct DOM manipulation.&lt;/p&gt;

&lt;p&gt;Let's say you have to create a table with a hundred rows. If you create each element using vanilla javascript, it will be slower than creating them all in memory (vdom) and then dumping it to the real dom in a single iteration.&lt;/p&gt;

&lt;p&gt;Well, &lt;strong&gt;obviously&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Making a change to the dom includes re-rendering of the page, it is much more computation than just changing values in-memory.&lt;/p&gt;

&lt;p&gt;But you tell me: who on earth creates a hundred rows table by writing code for each element and then dumping element by element to the dom? Everybody knows this is not performant, and also this is just bad coding.&lt;/p&gt;

&lt;p&gt;What you would want to do in order to develop a Single Page Application (SPA) is basically the same you would do while developing a server-side rendering application: you would want to use a &lt;strong&gt;template engine&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Template engines are pieces of software capable of processing a preset (template) against data in order to create dinamically generated content depending on the data. If you are creating a SPA (client-side rendering), this template processing has to happen in the client (browser), with data originating from a REST backend.&lt;/p&gt;

&lt;p&gt;Let's take a look on how this would work while using &lt;a href="https://handlebarsjs.com/"&gt;Handlebars&lt;/a&gt;, a very popular template engine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At first, you will create your html template in its own *.hbs file;&lt;/li&gt;
&lt;li&gt;You will &lt;strong&gt;precompile&lt;/strong&gt; the templates to javascript functions at build time;&lt;/li&gt;
&lt;li&gt;The functions will be executed against data in runtime (browser memory) and they will return a string;&lt;/li&gt;
&lt;li&gt;This string, which represents a portion of HTML, will be dumped to the dom &lt;strong&gt;in a single iteration&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means you can put the hundred rows table in a template and, in the end, the template itself will have just a few rows and the data will define how big the table will be.&lt;/p&gt;

&lt;p&gt;The same principle of the VDOM applies: change everything you need to change in-memory, and only dump these changes to the dom when you're finished, using as less dom manipulation as necessary.&lt;/p&gt;

&lt;p&gt;Of course VDOM has other advantages like data-binding, but bragging about "blazing-fast speed" while making a biased comparison against bad code seems just wrong to me. We have to be critical and learn to understand when you apple is being compared to another apple or to an orange.&lt;/p&gt;

&lt;p&gt;If you wish to learn more about Handlebars, in this other post I talk about &lt;a href="https://dev.to/honatas/properly-precompile-handlebars-templates-and-partials-with-gulp-4g91"&gt;properly precompiling Handlebars templates&lt;/a&gt;. Happy coding!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>virtualdom</category>
    </item>
    <item>
      <title>DRY principle and the S of SOLID</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Thu, 10 Jun 2021 17:21:39 +0000</pubDate>
      <link>https://dev.to/honatas/dry-principle-and-the-s-of-solid-3haa</link>
      <guid>https://dev.to/honatas/dry-principle-and-the-s-of-solid-3haa</guid>
      <description>&lt;p&gt;Let's say an arbitrary and completely fictional javascript developer named Aristotle has to create a method that performs some area calculations based on a length. Let's watch him do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;calculateArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;squareArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then Aristotle has been requested to do a very similar calculation, this time based on radius. So in order to respect the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt; (Don't Repeat Yourself) principle, he decides to rewrite the same method with new parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;calculateArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;length&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;squareArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;circleArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is okay, right? Because he is not creating two methods for calculating area, so Aristotle is not repeating himself. But then Aristotle realizes rectangles do exist, so he proceeds to do another small adjustment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;calculateArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;length&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;squareArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rectangleArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;circleArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope at this point you have realized what a mess this is becoming. Imagine having to deal with every shape in existence.&lt;/p&gt;

&lt;p&gt;The problem here is with interpretation of the principle. Aristotle thinks that by having a single method for calculating areas, there will be no area calculations repeated and spread throughout his application. He is centralizing all area calculations in a single entry point. What Aristotle does not know though, is about the &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle"&gt;S of SOLID&lt;/a&gt;, or the Single Responsibility Principle.&lt;/p&gt;

&lt;p&gt;If you think a bit deeper and couple these two principles together, you will realize that the calculateArea method didn't actually need to exist in the first place. This kind of method quickly grows in complexity thus also increasing cost of maintenance. The other methods for area calculation are self-suficient, isolated, and there is no repetition involved. Calculating the area of a square is a different responsibility than calculating the area of a circle.&lt;/p&gt;

&lt;p&gt;Maybe this is a bit too exaggerated, but a similar pattern I often see is the boolean last parameter. When you have two very similar responsibilities, instead of creating two methods, you go and add a boolean parameter to the method signature, forking the flow with an if inside the method implementation. All is good, until you realize there is more than a single difference between them, so the boolean is not enough anymore, then you end up adding more than a boolean and more than a single if. And this goes on and on and on ...&lt;/p&gt;

&lt;p&gt;When you see that pattern of nested ifs forming, take a step back and "check your principles". ;)&lt;/p&gt;

</description>
      <category>solid</category>
      <category>dry</category>
      <category>patterns</category>
      <category>clean</category>
    </item>
    <item>
      <title>A WebComponent journey</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Fri, 28 May 2021 17:56:45 +0000</pubDate>
      <link>https://dev.to/honatas/a-webcomponent-journey-1kma</link>
      <guid>https://dev.to/honatas/a-webcomponent-journey-1kma</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL:DR&lt;/strong&gt;; This is the &lt;a href="https://www.npmjs.com/package/@honatas/multi-select-webcomponent"&gt;multi-select-webcomponent&lt;/a&gt; this post is about. MIT license, feel free to do whatever you want with it.&lt;/p&gt;




&lt;p&gt;Have you ever heard of &lt;a href="https://www.webcomponents.org"&gt;WebComponents&lt;/a&gt;? This is a standard specification which all major browsers implement, and it allows for an application to provide its own html tags. Of course you can pack those tag definitions in modules, and here lies the beauty of WebComponents: standardized components that can be reutilized in any application, in any modern browser.&lt;/p&gt;

&lt;p&gt;But are they that beautiful in the real world? I'll talk about some things I found out while developing my own WebComponent:&lt;/p&gt;

&lt;h3&gt;
  
  
  Shadow DOM
&lt;/h3&gt;

&lt;p&gt;This is a feature of the specification that consists in encapsulating the component's DOM from the DOM where it is being included, so no styling rule applied to the component's parent will take effect in the component itself. It allows for your component to preserve its appearance and functionality regardless of whatever happens to the rest of the page.&lt;/p&gt;

&lt;p&gt;The big problem I see here is that by doing this you are locking the style of your component, making it hard to fit in any application other than the one where the component was designed to fit.&lt;/p&gt;

&lt;p&gt;When developing my component I chose to do not use Shadow DOM, ship it completely "naked" and give many tools for whoever is using the component to style it according to its own needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Templating
&lt;/h3&gt;

&lt;p&gt;The specification allows for using chunks of HTML as the template for your components, but these chunks must be present at the DOM. If you are thinking about modularity and intend to use the component in many projects, you'll have to come up with a way of hacking into the DOM where the component is being inserted to add your own HTML to it, so you can retrieve it later to use inside the component.&lt;/p&gt;

&lt;p&gt;This can lead to disaster, so I chose to do not use any templating and create all the component's structure in javascript, which isn't very nice. Maybe I can come up with a way to use string literals but that's for another update.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modularity
&lt;/h3&gt;

&lt;p&gt;You can create your components in UMD modules and ship them like that, but this would not allow for straightforward usage, so I chose to create an iife module everybody is more familiar with. This allows for anyone to just pick it up from a CDN and include in their page, or with a bit more knowledge add it to a SPA bundle (that's what I did in my project, using &lt;a href="https://gulpjs.com"&gt;Gulp&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Summing Up
&lt;/h3&gt;

&lt;p&gt;At the end I was very satisfied with the results. Even though the code has gotten a bit complex because of no templating, the component itself has got a lot of functionality and can be easily used in any other future application.&lt;/p&gt;

&lt;p&gt;So, what do you think of WebComponents? Are you considering making one of your own after reading this? I hope so. ;)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webcomponents</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Como precompilar seus templates e partials de Handlebars com Gulp</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Thu, 22 Apr 2021 18:11:00 +0000</pubDate>
      <link>https://dev.to/honatas/como-precompilar-seus-templates-e-partials-de-handlebars-com-gulp-1fj</link>
      <guid>https://dev.to/honatas/como-precompilar-seus-templates-e-partials-de-handlebars-com-gulp-1fj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Leia em inglês: &lt;a href="https://dev.to/honatas/properly-precompile-handlebars-templates-and-partials-with-gulp-4g91"&gt;aqui&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Caso você esteja usando o &lt;a href="https://handlebarsjs.com"&gt;Handlebars&lt;/a&gt; como sua engine de templates no front-end da sua aplicação web, é interessante enviar os templates precompilados para o browser ao invés de deixar para o cliente o trabalho de ter que compilar cada template de que ele precisa.&lt;/p&gt;

&lt;p&gt;Apresento aqui um script do &lt;a href="https://gulpjs.com"&gt;Gulp&lt;/a&gt; que eu tenho usado já há algum tempo. Ele pega qualquer arquivo .hbs na sua pasta src, compila, e gera um único arquivo templates.js na sua pasta dist/js. Ele também pega qualquer arquivo que comece com _ e marca ele como um partial do handlebaras, de modo que ele possa ser incluído em outros templates (se lembre de omitir o caractere _ quando for incluir, ou seja, &lt;code&gt;_meuInclude.hbs&lt;/code&gt; vira &lt;code&gt;{{&amp;gt;meuInclude}}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No seu código javascript, você vai recuperar o template assim:&lt;br&gt;
&lt;code&gt;const stringTemplate = Hbs['nome_do_template'];&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Sem mais, segue o código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;series&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-concat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;declare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-declare&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;del&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;del&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handlebars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-handlebars&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;merge2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-rename&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-wrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/*.hbs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handlebars&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Handlebars.template(&amp;lt;%= contents %&amp;gt;)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hbs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;noRedeclare&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;partials&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/_*.hbs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handlebars&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Handlebars.registerPartial(&amp;lt;%= processPartialName(file.relative) %&amp;gt;, Hbs[&amp;lt;%= processPartialName(file.relative) %&amp;gt;]);&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;processPartialName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;hbs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;partials&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;templates.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;hbs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A pegadinha aqui está nos partials. Pro Handlebars, qualquer template pode ser um partial, mas pra isso o template precisa existir primeiro. O que esse script faz é precompilar todos os templates (inclusive os partials) e, pra cada arquivo que começa com _, marca ele como um partial.&lt;/p&gt;

&lt;p&gt;Claro, se você está usando o Gulp pra fazer o build da sua aplicação, você não vai ter vários gulpfiles, então a melhor coisa a se fazer aqui é pegar alguns desses métodos e adicioná-los ao seu próprio gulpfile. O que eu costumo fazer nos meus gulpfiles é não gerar a saída em um arquivo de templates, mas sim juntar essa saída com o resto do meu javascript gerado e criar um único arquivo e, caso o build seja pra produção, minificar o resultado.&lt;/p&gt;

&lt;p&gt;Espero que isso ajude acelerar a sua jornada pra se livrar dos frameworks da modinha. =)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>handlebars</category>
      <category>gulp</category>
      <category>portugues</category>
    </item>
    <item>
      <title>Properly precompile Handlebars templates and partials with Gulp</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Thu, 22 Apr 2021 17:50:42 +0000</pubDate>
      <link>https://dev.to/honatas/properly-precompile-handlebars-templates-and-partials-with-gulp-4g91</link>
      <guid>https://dev.to/honatas/properly-precompile-handlebars-templates-and-partials-with-gulp-4g91</guid>
      <description>&lt;p&gt;&lt;strong&gt;Read in portuguese: &lt;a href="https://dev.to/honatas/como-precompilar-seus-templates-e-partials-de-handlebars-com-gulp-1fj"&gt;here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are using &lt;a href="https://handlebarsjs.com"&gt;Handlebars&lt;/a&gt; as your web front-end's template engine, it is generally a good idea to send precompiled templates to the browser instead of leaving to the the client the job of compiling every single template it requires.&lt;/p&gt;

&lt;p&gt;I'll present here a &lt;a href="https://gulpjs.com"&gt;Gulp&lt;/a&gt; script I've been using for this task for some time now. It will seek any .hbs files in your src folder, precompile it, and output a single templates.js file on your dist/js folder. It will also pick any file whose filename starts with _ and set it up as a handlebars partial, so it can be included in other templates (just remember to omit the _ character when including, eg, &lt;code&gt;_myInclude.hbs&lt;/code&gt; becomes &lt;code&gt;{{&amp;gt;myInclude}}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In your javascript code, you will get the template like this:&lt;br&gt;
&lt;code&gt;const stringTemplate = Hbs['your_template_name_here'];&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Without futher delay, here is the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;series&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-concat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;declare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-declare&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;del&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;del&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handlebars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-handlebars&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;merge2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-rename&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wrap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gulp-wrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/*.hbs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handlebars&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Handlebars.template(&amp;lt;%= contents %&amp;gt;)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hbs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;noRedeclare&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;partials&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/_*.hbs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handlebars&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Handlebars.registerPartial(&amp;lt;%= processPartialName(file.relative) %&amp;gt;, Hbs[&amp;lt;%= processPartialName(file.relative) %&amp;gt;]);&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;processPartialName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;hbs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;partials&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;templates.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;hbs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The big catch here are the partials. For Handlebars, any template can be identified as a partial, but before you can do that, you have to create the template first. So, what this script does is to precompile every template (including the partials) and then, for every file that starts with _, set it up as a partial.&lt;/p&gt;

&lt;p&gt;Of course, if you are using Gulp to build your application, you will not use a variety of gulp files, so the best thing to do here is to pick up some of those methods and add them to your own gulpfile. One thing that I do in my gulpfiles is to do not output the precompiled templates to a file, but rather concatenate its output with the rest of the javascript I generate and, if this is a production build, minify it.&lt;/p&gt;

&lt;p&gt;It took me a while to figure all this out, so I hope this helps speeding up your journey of getting away from mainstream frameworks. =)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>handlebars</category>
      <category>gulp</category>
      <category>frameworkless</category>
    </item>
    <item>
      <title>Uma abordagem diferenciada à Sessões de Usuário em Microsserviços usando Redis</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Thu, 04 Feb 2021 15:03:44 +0000</pubDate>
      <link>https://dev.to/honatas/uma-abordagem-diferenciada-a-sessoes-de-usuario-em-microsservicos-usando-redis-2mim</link>
      <guid>https://dev.to/honatas/uma-abordagem-diferenciada-a-sessoes-de-usuario-em-microsservicos-usando-redis-2mim</guid>
      <description>&lt;h5&gt;
  
  
  Read in english: &lt;a href="https://dev.to/honatas/a-different-approach-to-user-sessions-in-microservices-5bpi"&gt;click here&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;Você decidiu quebrar o seu velho e ultrapassado monolito em uma arquitetura mais moderna e eficiente de microsserviços. Um dos primeiros problemas que certamente irá surgir vem do fato de que ter uma arquitetura distribuída significa que suas novas pequenas peças não estão mais amarradas umas às outras, elas vão precisar se conversar através de serviços e não mais conseguirão compartilhar áreas de memória. Bem, acontece que um dos dados mais importantes da sua aplicação era mantido em memória e compartilhado entre todos os módulos da aplicação: &lt;strong&gt;a sessão do usuário&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Quando você faz uma pesquisa rápida sobre autenticação e autorização em microsserviços, uma certa tecnologia aparece como sendo a melhor, senão a única, solução: &lt;a href="https://jwt.io/"&gt;JWT&lt;/a&gt;. Basicamente, essa abordagem sugere que você coloque todos os seus dados de sessão em um hash assinado e encriptado (a token) e envie isso de volta para o cliente que se logou na sua aplicação. Então, a cada requisição, o cliente deve enviar de volta essa token (geralmente no cabeçalho da requisição), e então podemos verificar a autenticidade dessa token e extrair dela os dados da sessão. Com os dados em mãos, podemos enviá-los para qualquer serviço que necessite deles até que a requisição seja respondida. Podemos subir uma função serverless para desencriptar e verificar a assinatura da token, ou até mesmo delegar essa tarefa para o nosso API Gateway.&lt;/p&gt;

&lt;p&gt;Parece muito bonito e elegante à primeira vista, mas espera um pouco ... isso está parecendo bem mais complexo do que costumava ser, certo? Vamos dar uma olhada em como isso funcionava no nosso monolito, e porquê teve que mudar tão drasticamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Os velhos tempos
&lt;/h2&gt;

&lt;p&gt;Antigamente, sessões de usuário em HTTP eram armazenadas na memória do servidor, indexadas por um hash gerado aleatoriamente e que não tinha significado - inclusive o termo "token opaca" surgiu pra identificar essa token sem dado algum nela. Essa token sem dados era então enviada de volta ao browser, e o servidor gentilmente pedia a ele que salvasse esta token em um &lt;a href="https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Cookies"&gt;Cookie&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pela sua natureza, os Cookies são automaticamente enviados de volta ao servidor a cada requisição feita posteriormente, então depois de o usuário estar logado, a próxima requisição ao mesmo servidor certamente irá conter o cookie, que por sua vez irá conter a token necessária para recuperar os dados do usuário da memória do servidor.&lt;/p&gt;

&lt;p&gt;Essa abordagem vem sendo utilizada por mais de uma década por vários servidores de nível enterprise (jboss, weblogic, etc), e é considerada segura. Mas agora nós temos microsserviços, então não podemos contar mais com isso, pois cada serviço é isolado dos outros, então não temos mais uma área comum para armazenar esses dados.&lt;/p&gt;

&lt;p&gt;A solução então, conforme proposta, é enviar os dados ao cliente, deixá-lo com a responsabilidade de guardar esses dados, e enviá-los de volta quando necessário. Isso apresenta uma enorme quantidade de problemas que não tínhamos antes, e eu vou tentar explicar alguns deles agora:&lt;/p&gt;

&lt;h2&gt;
  
  
  Problemas de segurança
&lt;/h2&gt;

&lt;p&gt;A maioria das implementações com JWT sugere que você envie a token do cliente de volta ao servidor através de um cabeçalho HTTP chamado "Authorization". Para poder fazer isso, o seu client precisa ter a capacidade de receber, armazenar e recuperar a token. O problema é, se o client tem acesso a esses dados, então qualquer código malicioso também tem. De posse da token, o malfeitor pode tentar decriptá-la para visualizar os dados, ou apenas utilizá-la para obter acesso à aplicação.&lt;/p&gt;

&lt;p&gt;No monolito, o servidor simplesmente enviava a token opaca ao browser em um cabeçalho HTTP chamado SetCookie, então o código no cliente não precisava lidar com a informação pois o browser faz isso automaticamente. Até mesmo o cookie pode ser setado de uma forma que sequer possa ser acessado via javascript, sendo assim códigos maliciosos jamais conseguiriam acesso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problemas de performance
&lt;/h2&gt;

&lt;p&gt;Para poder manter tudo seguro, você deve assinar a token rodando um algoritmo de criptografia para que ninguém possa alterar seu conteúdo, e também encriptar a token pra ter certeza de que ninguém poderá ler facilmente esse conteúdo.&lt;/p&gt;

&lt;p&gt;Além disso, pra cada requisição recebida no servidor, o mesmo deverá rodar a desencriptação da token, bem como rodar novamente o algoritmo de criptografia que gera a assinatura a fim de verificar sua validade. Todos nós sabemos o quanto esses algoritmos de criptografia são custosos computacionalmente, e nada disso era necessário no nosso velho monolito, salvo pela única execução no momento de comparar as senhas durante o login - mas essa execução também é necessária quando se usa JWT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problemas de usabilidade
&lt;/h2&gt;

&lt;p&gt;As tokens JWT não são muito boas em controlar expiração de sessão por inatividade. Quando se gera uma token, ela é dada como válida até a sua data de expiração, que é armazenada na própria token. Ou seja, ou você gera uma nova token a cada requisição, ou você gera uma outra token chamada de Refresh Token com uma expiração maior, e a utiliza unicamente para conseguir uma nova token quando a sua expirar. Mas perceba, isso só transfere o problema de um lugar para outro - a sessão de fato expirará quando a Refresh Token expirar, a menos que você também a atualize.&lt;/p&gt;

&lt;p&gt;Como você pode perceber, a solução proposta traz consigo uma série de problemas não resolvidos. Mas como então podemos conseguir um gerenciamento de sessão de usuário efetivo e seguro em uma arquitetura de microsserviços?&lt;/p&gt;

&lt;h2&gt;
  
  
  Trazendo velhos conceitos ao novo mundo
&lt;/h2&gt;

&lt;p&gt;Vamos nos focar no problema real: a sessão de usuário costumava ser armazenada na memória do servidor, e muitos servidores enterprise podiam replicar esse trecho de memória entre suas várias instâncias dentro do cluster, o que a tornava acessível em qualquer situação. Porém, nós mal temos servidores de aplicação hoje, sendo que a maioria dos módulos de microsserviços são aplicações standalone java / node / python / go / (escolha sua tecnologia). Como então eles irão compartilhar uma única porção de memória?&lt;/p&gt;

&lt;p&gt;Na verdade é bastante simples: &lt;strong&gt;crie um servidor central de sessão&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A idéia aqui é armazenar a sessão do usuário da mesma forma que antes: deve-se gerar uma token opaca para ser usada como chave, e então pode-se adicionar a quantidade de dados que você quiser para ser indexado por essa chave. Faremos isso em um lugar que seja central e acessível por qualquer microsserviço na sua rede, sendo que quando qualquer um deles necessite dos dados, eles estarão a apenas uma chamada de distância.&lt;/p&gt;

&lt;p&gt;A melhor ferramenta para esse trabalho é o &lt;a href="https://redislabs.com/"&gt;Redis&lt;/a&gt;. O Redis é um banco de dados em memória que trabalha com pares chave-valor, e tem latência menor que um milissegundo. Seus microsserviços conseguirão ler os dados de sessão como se estivessem armazenados diretamente em sua própria memória (bem, quase, mas é rápido). Além disso, o Redis tem uma funcionalidade que é imprescindível pro nosso caso: conseguimos setar um timeout para um par chave-valor, sendo que assim que o tempo expira, o par é deletado do banco. O tempo pode ser resetado sob demanda. Soa exatamente como timeout de sessão, certo?&lt;/p&gt;

&lt;p&gt;Pra tudo isso funcionar, precisaremos de pelo menos dois módulos:&lt;/p&gt;

&lt;h2&gt;
  
  
  1 - Módulo de autenticação
&lt;/h2&gt;

&lt;p&gt;Você terá que criar um microsserviço responsável pela autenticação dos seus usuários. Ele irá receber a requisição com o login e a senha, irá checar se a senha é válida, e então criar a sessão no Redis.&lt;/p&gt;

&lt;p&gt;Para isso ele irá gerar a token opaca, recuperar os dados do usuário do seu banco relacional (ou nosql, depende do seu caso), e então armazenar esses dados no Redis usando a token como chave. Em seguida, irá retornar a chave ao cliente que requisitou o login, de preferência em um header SetCookie caso o cliente seja um browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - Módulo de autorização
&lt;/h2&gt;

&lt;p&gt;Eu particularmente prefiro que esse módulo seja parte integrante de cada um dos microsserviços, mas você pode colocá-lo dentro do seu API Gateway caso prefira. Sua responsabilidade é a de interceptar cada requisição feita, recuperar a token opaca, e com ela ir ao Redis e recuperar os dados de sessão, repassando esses dados junto com a requisição até o serviço que irá tratá-la.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j_Cyt7Fw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/titrfns0fv40oldlkou9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j_Cyt7Fw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/titrfns0fv40oldlkou9.jpg" alt="arquitetura"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Como você pode perceber, a solução aqui proposta é muito mais simples, rápida e segura do que utilizar JWT para gerenciar sessões de usuário. Mas tenha em mente o seguinte:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Se você estiver utilizando uma única shard do Redis, esse pode ser seu "single point of failure", ou seja, se ele falhar, você fica sem login. Eu recomendo utilizar um setup de produção mais robusto, com mais shards e replicação de dados entre eles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Os dados de sessão podem ser modificados por qualquer módulo que tenha acesso ao Redis, sendo assim use uma abordagem de "sempre adicionar, nunca deletar", da mesma forma que era feito nos velhos tempos com o monolito.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Espero que isso ajude.&lt;/p&gt;

&lt;p&gt;Como um bônus, deixo aqui uma classe SessionManager pra ajudar na implementação em Java usando &lt;a href="https://github.com/redis/jedis"&gt;Jedis&lt;/a&gt; e o gerador de token do Tomcat, que já é normalmente incluído no Spring Boot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/Honatas/e64d59a015f28f7bab01686055072d64"&gt;SessionManager&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/Honatas/097a5dff24b99b688d40e433ebfae2bb"&gt;RedisClient&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bom divertimento!&lt;/p&gt;

</description>
      <category>redis</category>
      <category>portugues</category>
      <category>microsservicos</category>
      <category>autenticacao</category>
    </item>
    <item>
      <title>O Hibernate realmente vale a pena?</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Wed, 03 Feb 2021 14:06:58 +0000</pubDate>
      <link>https://dev.to/honatas/o-hibernate-realmente-vale-a-pena-1a1j</link>
      <guid>https://dev.to/honatas/o-hibernate-realmente-vale-a-pena-1a1j</guid>
      <description>&lt;h5&gt;
  
  
  Read in english: &lt;a href="https://dev.to/honatas/is-hibernate-really-worth-it-1cmi"&gt;click here&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;Quando a gente vai criar um projeto novo de backend, uma api REST pra um banco relacional por exemplo, a primeira coisa que vem à cabeça é &lt;a href="https://hibernate.org/"&gt;Hibernate&lt;/a&gt;. Mas por quê? Você já parou pra pensar em como de fato essa ferramenta deixa seu trabalho mais fácil (ou difícil)? Você considerou as exatas necessidades da sua arquitetura e pensou em um bom motivo pra incluir ou não a ferramenta?&lt;/p&gt;

&lt;p&gt;Estou aqui pra apresentar &lt;a href="https://pt.wikipedia.org/wiki/The_Good,_the_Bad_and_the_Ugly"&gt;o bom, o mau e o feio&lt;/a&gt; sobre o Hibernate (e &lt;a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping"&gt;ORM&lt;/a&gt;s em geral), como eles podem atravancar o seu projeto mais do que você imagina, e é claro apresentar uma excelente alternativa.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Bom
&lt;/h2&gt;

&lt;p&gt;Vamos encarar os fatos: escrever um &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete"&gt;CRUD&lt;/a&gt; em &lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc"&gt;JDBC&lt;/a&gt; puro é muito sofrido. Quando o Hibernate surgiu, foi a luz no fim do túnel. Mesmo na sua primeira versão (lançada em meados de 2001), o mapeamento baseado em XML era mil vezes melhor que aquelas tranqueiras de EJB Entity Beans. Ele evoluiu, ganhou annotations, e rapidamente virou o padrão mais popularmente aceito pra qualquer aplicação Java.&lt;/p&gt;

&lt;p&gt;Escrever um CRUD em Hibernate é bem rápido e relativamente simples. A complexidade só aumenta conforme os relacionamentos entre as suas tabelas no banco também ficam mais complexos. E isto nos leva ao próximo ponto:&lt;/p&gt;

&lt;h2&gt;
  
  
  O Mau
&lt;/h2&gt;

&lt;p&gt;Vou resumir em uma só palavra: mapeamentos. Sim, você ganhou bastante tempo escrevendo seu CRUD com Hibernate em comparação a tê-lo escrito em JDBC. Mas você já parou pra contar quanto tempo você desperdiçou no Google e no &lt;a href="https://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt; tentando entender porquê aquele maldito mapeamento que deveria ser tão simples não está funcionando? E não se orgulhe dos seus 15 anos de experiência com os quais você consegue praticamente mapear qualquer coisa, porque aquele desenvolvedor junior no seu time também está apanhando e perdendo o mesmo tanto de tempo que você já perdeu. Quando já passaram dois dias e você ainda não conseguiu fazer o mapeamento funcionar, você começa a querer poder fazer aquele bom e velho SQL e se safar com isso.&lt;/p&gt;

&lt;p&gt;Na real, porque não? E isso nos leva ao pior de tudo:&lt;/p&gt;

&lt;h2&gt;
  
  
  O Feio
&lt;/h2&gt;

&lt;p&gt;Native Queries. Não mente pra mim, dá até um frio na espinha, né não? Por quê diabos você vai querer escrever SQL nativo quando você já está usando uma ferramenta ORM extremamente moderna e poderosa? Essas "pestinhas" acabam com todo o propósito de se ter um ORM, sem deixar você trocar o banco da aplicação por exemplo, entre outras coisas.&lt;/p&gt;

&lt;p&gt;Hibernate é só flores enquanto o projeto está na fase dos CRUDs. Mas quando chegam os relatórios, onde você tem que criar joins imensas de muitas tabelas, consultas cheias de subqueries, e etc e tal, aí as coisas começam a ficar complicadas. Primariamente por conta daqueles mapeamentos mal resolvidos. Não tem um único projeto com Hibernate que eu tenha visto em toda a minha carreira (já são 16 anos) que seja totalmente livre de queries nativas. Alguém, em algum ponto do projeto, não tinha o tempo nem o conhecimento pra fazer da forma correta, lançou um ás da manga e meteu-lhe uma native query pra poder entregar no prazo.&lt;/p&gt;

&lt;p&gt;Outro ponto feio que ninguém gosta de falar envolve performance. Não, eu não estou dizendo que Hibernate é lento, mas quando o DBA vem correndo da mesa dele reclamando que uma certa consulta está degradando a performance do banco e precisa de tuning imediatamente, a gente só olha pra ele com cara de dó e fala: "cara, aqui é Hibernate, eu não controlo como as queries são criadas, não vai rolar tuning não". Aí ele vai e fala com o gerente dele, que por sua vez fala com o seu gerente, e olha lá: nasce mais uma native query.&lt;/p&gt;

&lt;p&gt;É claro que tudo isso gira em torno de falta de conhecimento com relação aos mapeamentos. Infelizmente, esse não é um tópico simples e, ao menos na minha humilde opinião, a documentação não é muito clara. Ainda estou pra conhecer um desenvolvedor que consiga encher o peito pra dizer: "Eu consigo mapear com precisão qualquer relacionamento que aparecer". As coisas só pioram quando quem está criando as tabelas e quem está criando o código Java não são a mesma pessoa.&lt;/p&gt;

&lt;p&gt;Vamos pensar um pouco então. Ganhei um bom tempo na parte do CRUD, perdi todo ele ou talvez mais nos relatórios, e perdi todo o propósito disso escrevendo várias native queries. Qual foi a vantagem no fim? Usar um ORM realmente foi bom? Mas, se não foi bom, então pra onde eu corro?&lt;/p&gt;

&lt;h2&gt;
  
  
  A Alternativa
&lt;/h2&gt;

&lt;p&gt;Você conhece o &lt;a href="https://spring.io/"&gt;Spring&lt;/a&gt;, certo? Provavelmente você até já está usando ele na sua aplicação. O Spring Boot é uma base excelente pra qualquer aplicação Java e traz consigo muitas funcionalidades interessantes. Mesmo se você não gosta do Boot, o próprio core do Spring e até mesmo o Spring MVC são parte integrante de muitas aplicações Java hoje. E se eu te dissesse que você não precisa de nada além disso pra conseguir trabalhar com SQL sem lançar mão de ORMs e sem precisar usar JDBC diretamente?&lt;/p&gt;

&lt;p&gt;Vamos dar uma olhada na documentação do Spring Framework, Data Access, capítulo 3: &lt;a href="https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/data-access.html#jdbc"&gt;Data Access with JDBC&lt;/a&gt;. Ele apresenta um conjuto de classes utilitárias que abstraem todo o trabalho árduo e te deixa apenas com o processamento dos dados propriamente ditos. Isso, se aliado à anotação @Transactional também do Spring, te dá uma abordagem muito próxima do que você já está acostumado com o Hibernate em termos de controle de transação automático, mas sem a bagunça dos mapeamentos e com acesso direto ao SQL.&lt;/p&gt;

&lt;p&gt;De acordo com a própria documentação, você só vai ter que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Definir os parâmetros de conexão (uma vez apenas)&lt;/li&gt;
&lt;li&gt;Escrever as queries (selects, basicamente)&lt;/li&gt;
&lt;li&gt;Prover os parâmetros&lt;/li&gt;
&lt;li&gt;Processar os dados que retornam.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Você NÃO vai ter que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abrir / fechar conexões com o banco&lt;/li&gt;
&lt;li&gt;Se preocupar com detalhes da execução&lt;/li&gt;
&lt;li&gt;Escrever um laço pra iterar nas linhas retornadas&lt;/li&gt;
&lt;li&gt;Comitar / fazer rollback das transações e tratar exceções&lt;/li&gt;
&lt;li&gt;Fechar recursos (close resources)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uma das melhores classes aqui é o BeanPropertyRowMapper. Ele consegue automaticamente popular uma lista de POJOs dado que na query você dê sinônimos (aliases) às colunas com nomes idênticos aos dos atributos do pojo. Quase um mapeamento, mas não exige consistência. Pra inserts, updates e deletes, você sequer vai precisar escrever SQL; passar o nome da tabela e um Map com nome da coluna + valor é suficiente.&lt;/p&gt;

&lt;p&gt;Eu não vou aqui escrever um tutorial pra esse pedacinho de mau caminho porque esse não é o intuito desse artigo. Aqui eu só quero mostrar que existem excelentes alternativas pra uma ferramenta que causou (ao menos pra mim) mais problemas do que aqueles que ela deveria solucionar. Já escrevi alguns sistemas usando essa abordagem e meu sentimento é que em todos eles, o desenvolvimento no que se refere ao acesso ao banco de dados foi muito mais suave do que usando Hibernate. Digo, se você já sabe que vai ter que escrever um monte de SQL de qualquer jeito, por quê já não começar assim e pular as dores de cabeça de ter que escrever aqueles mapeamentos, tudo enquanto mantendo o mesmo controle automático de transação?&lt;/p&gt;

&lt;p&gt;Caso você queira já começar a brincar com essa parte do Spring, eu preparei aqui umas classes wrapper pra dar um impulso inicial:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/Honatas/8a04b33efe2b5160dc4aa73de305db98"&gt;BaseDAO&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gist.github.com/Honatas/b67a3dd0f6cf0556f1c42c30aaf6acb4"&gt;BaseModel&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Eu sou uma pessoa realista e eu escrevi esse artigo baseado na minha experiência pessoal em vários projetos com vários times diferentes, usando Hibernate. Eu considero a criação de mapeamentos mais difícil do que deveria ser, e também trabalho desnecessário quando você já sabe SQL muito bem. Se o seu projeto não tem uma seção de relatórios e/ou você se sente confortável com os mapeamentos do Hibernate, então ele é sua melhor escolha. De outra forma, eu fortemente recomendo que você procure alternativas. Dá pra achar coisa muito boa fora da "modinha".&lt;/p&gt;

</description>
      <category>java</category>
      <category>portugues</category>
      <category>hibernate</category>
      <category>spring</category>
    </item>
    <item>
      <title>Is Hibernate Really Worth It ?</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Mon, 28 Dec 2020 18:09:49 +0000</pubDate>
      <link>https://dev.to/honatas/is-hibernate-really-worth-it-1cmi</link>
      <guid>https://dev.to/honatas/is-hibernate-really-worth-it-1cmi</guid>
      <description>&lt;h5&gt;
  
  
  Leia em português: &lt;a href="https://dev.to/honatas/o-hibernate-realmente-vale-a-pena-1a1j"&gt;clique aqui&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;If you are creating a new Java project for your REST backend over a relational database, you will probably not even blink before saying: &lt;a href="https://hibernate.org"&gt;Hibernate&lt;/a&gt;. But why? Did you really give a good thought on how this tool actually makes your work easier (or harder)? Did you consider the accurate needs of your architecture and have a good reason to include or not include it?&lt;/p&gt;

&lt;p&gt;I'm here to present the good, the bad and the ugly about Hibernate (and &lt;a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping"&gt;ORM&lt;/a&gt;s in general), how can it actually hinder your project more than you can even imagine, and of course present an awesome alternative to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The good
&lt;/h2&gt;

&lt;p&gt;Let's face it: writing a &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete"&gt;CRUD&lt;/a&gt; in pure &lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc"&gt;JDBC&lt;/a&gt; is a huge pain. Hibernate was a ray of light shed on a swampy wasteland. Even in its first version (launched circa 2001), the XML-based mapping was way better than those pesky EJB Entity Beans. It evolved, got annotations, and quickly became the de-facto stardard for any Java application.&lt;/p&gt;

&lt;p&gt;Writing a CRUD in Hibernate is pretty fast and quite easy. The complexity only rises as the relationships between your tables also get complex. And this brings us to the next topic:&lt;/p&gt;

&lt;h2&gt;
  
  
  The bad
&lt;/h2&gt;

&lt;p&gt;I'll wrap it up in a single word: mappings. Sure, you have saved a lot of time while writing your CRUD with Hibernate in comparison to writing it on JDBC. But have you calculated how much time you have wasted on Google and &lt;a href="https://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt; trying to understand why that particular mapping isn't working? And don't be proud of your 15 years expertise mapping knowledge where you just know how to make any kind of mapping, because that junior developer on your team is also struggling and wasting the same amount of time. When two days have already passed and you just can't make that mapping work, you wish you could just write plain SQL and get away with it.&lt;/p&gt;

&lt;p&gt;Then again, why not? And this brings us to the worst of it:&lt;/p&gt;

&lt;h2&gt;
  
  
  The ugly
&lt;/h2&gt;

&lt;p&gt;Native Queries. Don't lie to me, you just felt shivers running down your spine. Why should you write SQL when you are using a very modern and powerful ORM tool? These little brats break the whole point of using an ORM, not allowing you to switch your database provider for an instance, amongst other bad and nasty things.&lt;/p&gt;

&lt;p&gt;Hibernate is all flowers while the project is in the CRUD stage. But when you get to the Reports stage, where you have to create huge joins and subqueries involving lots of tables, things start getting complicated, primarily because of those not-so-neatly resolved mappings. There is not a single Hibernate project I have seen in my whole career that is free of native queries. Someone, in some point of time, didn't have the timespan to be able to do it right, pulled off a little trick and delivered in time. And there was born another native query.&lt;/p&gt;

&lt;p&gt;Another ugly almost no one talks about involves performance. I'm not saying Hibernate is slow, but when the DBA comes running from his desk alerting us that a query is degrading the database performance and it needs tunning immediately, we just look at his desperate face and say: "Sorry dude, no tunning for you, its Hibernate, I don't control how queries are made". Then he talks to his manager who talks to your manager and this ends in another native query.&lt;/p&gt;

&lt;p&gt;Of course all of this revolves around poor knowledge about creating these mappings. Unfortunately, this is not a simple subject and, at least in my humble opinion, the documentation isn't that clear. I've yet to meet a developer who can fill his chest with pride and say "I can precisely map any relationship you present to me". This only gets worse when the person creating the tables is not the same person who is creating the Java code.&lt;/p&gt;

&lt;p&gt;Let's just think a bit about it then. I have saved some time on the CRUD, lost it all or maybe more on the mappings/reports, and then lost all the meaning of it while writing native SQL. What was the advantage in the end? Did using an ORM really paid off? But, if it wasn't that good, then what?&lt;/p&gt;

&lt;h2&gt;
  
  
  The alternative
&lt;/h2&gt;

&lt;p&gt;You know &lt;a href="https://spring.io"&gt;Spring&lt;/a&gt;, right? Much probably you are already using it on your project. Spring Boot is a fantastic bootstrap for any Java project and it brings a really good amount of functionality to your application. Even if you don't like Boot, just the Spring core itself or even Spring MVC are part of many Java applications today. What if you didn't need to add anything else to be able to do good work with SQL without JPA and without the hurdle of using JDBC directly?&lt;/p&gt;

&lt;p&gt;Let's take a look at the Spring Framework documentation, Data Access, chapter 3: &lt;a href="https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/data-access.html#jdbc"&gt;Data Access with JDBC&lt;/a&gt;. It presents a set of utility classes that abstract all the hard work and leave to you only the actual processing of the data itself. This, coupled with the @Transactional annotation also from Spring, give you an approach very close to what you are used to with Hibernate in terms of automatic transaction control, but without the messy mappings and closer to SQL.&lt;/p&gt;

&lt;p&gt;According to this very own documentation, you will only have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define connection parameters (only once)&lt;/li&gt;
&lt;li&gt;Write queries (selects, mostly)&lt;/li&gt;
&lt;li&gt;Provide parameters&lt;/li&gt;
&lt;li&gt;Process the data retrieved.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will NOT have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open/close connections&lt;/li&gt;
&lt;li&gt;Worry about execution details&lt;/li&gt;
&lt;li&gt;Write the loop over every row retrieved&lt;/li&gt;
&lt;li&gt;Commit/rollback transactions and handle exceptions&lt;/li&gt;
&lt;li&gt;Close resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the best classes in this set is the BeanPropertyRowMapper. It can automatically populate a List of POJOs given the columns retrieved in the query are aliased with names identical to the POJO's attributes names. Almost like a mapping, but it does not enforce consistency. For inserts, updates and deletes, you will not even have to write SQL; providing the table name and a Map of column name + value is enough.&lt;/p&gt;

&lt;p&gt;I'll not be writing a tutorial for this tiny piece of bliss because this is not the intent with this article. I'm only here to show you there are very good alternatives to a tool that has caused (at least to me) more problems than those it was supposed to solve. I've already wrote a few systems using this approach and my feeling is that in all of them, development regarding database access went much more smoothly than when using Hibernate. I mean, if you are supposed to write a lot of SQL anyway, then why not start out like that already and skip the headaches of having to write concise mappings, all while having the same automatic transaction control?&lt;/p&gt;

&lt;p&gt;If you want to jump right in, here's a couple of wrapper classes to get you started:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/Honatas/8a04b33efe2b5160dc4aa73de305db98"&gt;BaseDAO&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gist.github.com/Honatas/b67a3dd0f6cf0556f1c42c30aaf6acb4"&gt;BaseModel&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I'm a realistic person and I wrote this article based on my personal experience over many projects with many different teams using Hibernate. I consider creating mappings way harder than it should be, and also unecessary work when you already know a good amount of SQL. If your project does not have an intensive report generation and/or you're comfortable with ORM mapping, Hibernate is your best choice. Otherwise, I strongly recommend checking out for alternatives. You may find wonderful things outside the mainstream.&lt;/p&gt;

</description>
      <category>java</category>
      <category>orm</category>
      <category>hibernate</category>
      <category>spring</category>
    </item>
    <item>
      <title>A different approach to User Sessions in Microservices using Redis</title>
      <dc:creator>Jonatas de Moraes Junior</dc:creator>
      <pubDate>Mon, 28 Dec 2020 12:30:24 +0000</pubDate>
      <link>https://dev.to/honatas/a-different-approach-to-user-sessions-in-microservices-5bpi</link>
      <guid>https://dev.to/honatas/a-different-approach-to-user-sessions-in-microservices-5bpi</guid>
      <description>&lt;p&gt;Leia em portugês: &lt;a href="https://dev.to/honatas/uma-abordagem-diferenciada-a-sessoes-de-usuario-em-microsservicos-usando-redis-2mim"&gt;clique aqui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have decided to break your old and outdated monolith application into a more modern and efficient microservices architecture. One of the first problems that will arise comes from the fact that a distributed architecture means your small pieces aren't tied to each other anymore, they will have to talk to each other through a pattern of communication called REST, and no longer they will share in-memory data among them. Well, it just happens that one of the most important pieces of data for your whole application is kept in-memory and shared throughout all modules of your application: &lt;strong&gt;the user session&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you do a little research on microservices authentication and authorization, one technology comes up as the best, if not the only, solution: &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT&lt;/a&gt;. Basically, this approach suggests that you put all of your session data into a signed / encrypted hash (the token) and send it back to the client that has logged into your application. So, with every request, the client will send back that token (usually in the request header), and then you can verify the authenticity of the token and extract the session data from it. Session data in hands, you can send it to any service you need until you fulfill that request. You can set up a serverless function to decrypt and verify the signature of the token, or even delegate this task to you API Gateway.&lt;/p&gt;

&lt;p&gt;This looks so neat and elegant at first, but wait a minute ... it looks fairly more complex than what it used to be, right? Let's take a look at how it used to work with our monolith application, and why did it have to change so drastically.&lt;/p&gt;

&lt;h3&gt;
  
  
  The old days
&lt;/h3&gt;

&lt;p&gt;For quite a while, HTTP user sessions have been stored in the server's memory, indexed by a randomly generated hash with no meaning - the term "Opaque Token" has even arisen to identify a token with no data in it. This data-less token is then sent back to the browser, and then the server gently asks the browser to store it in a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies" rel="noopener noreferrer"&gt;Cookie&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By nature, Cookies are automatically sent back to the server with every request, so after you are logged in, your next request to the server will certainly contain the Cookie, which in turn will contain the token needed to retrieve the respective user data from the server's memory.&lt;/p&gt;

&lt;p&gt;This approach has been used for more than a decade by many enterprise-grade application servers, and is considered to be secure. But now we have microservices, so we can't rely on this anymore. Every service is isolated from each other, so we don't have a common place to store this data.&lt;/p&gt;

&lt;p&gt;The solution then, as proposed, is to send this data to the client, let it keep the data and send it back whenever needed. This poses a huge bunch of issues we didn't have before, and I'll try to describe some of them now:&lt;/p&gt;

&lt;h3&gt;
  
  
  Security issues
&lt;/h3&gt;

&lt;p&gt;Most of the implementations suggest that you send the token back to the server using an HTTP header called "Authorization". While doing so, your client has to have the ability to receive, store and retrieve the token. Problem is, if your client has access to this data, then any malicious code also has. In possession of the token, any attacker can try to decrypt it in order to access the data within it, or just use it to access the application.&lt;/p&gt;

&lt;p&gt;On the monolith, the server just sent the opaque token back in a SetCookie header, so the client code didn't have to deal with the information because the browser does this automatically. And the Cookie can be set in a way that it can't even be accessed by javascript, so malicious code can't reach it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance issues
&lt;/h3&gt;

&lt;p&gt;In order to keep everything safe, you have to sign the token by running an encryption algorithm so no one will tamper with the data, and also encrypt it to make sure no one will be able to read it.&lt;/p&gt;

&lt;p&gt;Also, with every request received, your servers will have to run an unencryption as well as verify the signature by running another encryption. We all know how encryption algorithms are expensive in terms of computing, and none of this encryption / unencryption had to happen with our old monolith, saved by the single run when you have to compare the passwords for login - which you also have to run when using JWT.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usability issues
&lt;/h3&gt;

&lt;p&gt;JWTs are not the best on tracking session expiration by inactivity. Once you issue a token, it is valid until its own expiration, which is set inside the token. So, either you issue a new token with every request, or you issue another token called Refresh Token with a longer expiration and use it only to get a new token after your token expires. As you may have realized, this just places the same problem elsewhere - the session will expire as soon as the refresh token expires, unless you also refresh it.&lt;/p&gt;

&lt;p&gt;As you can see, the solution proposed brings with it a lot of unsolved problems. But how can we achieve effective and secure user session management in a microservices architecture ?&lt;/p&gt;

&lt;h3&gt;
  
  
  Bringing old concepts to a new world
&lt;/h3&gt;

&lt;p&gt;Remember the actual problem: the user session used to be stored in the server's memory, and many enterprise servers could replicate this chunk of memory among all of its instances in a cluster, so it would be accessible no matter what. But now we hardly have enterprise servers anymore, being that many microservice modules are standalone java / node / python / go / (insert your tech here) applications. How can they share a single portion of memory?&lt;/p&gt;

&lt;p&gt;It's actually rather simple: &lt;strong&gt;add a central session server&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The idea here is to keep session data in the same fashion as before: create a opaque token to use as key, and then you can add as much data as you want to be indexed by that key. You do it in a place that is central and accessible by every microservice on your network, so whenever any of them needs the data, such data is just a call away.&lt;/p&gt;

&lt;p&gt;The best tool for this job is &lt;a href="https://redislabs.com" rel="noopener noreferrer"&gt;Redis&lt;/a&gt;. Redis is an in-memory key-value database with sub-milissecond latency. Your microservices can read user session data as if it was stored directly within their own memory (well, almost, but it is fast). Also, Redis has a feature that is key to this application: it can set a timeout to a key-value pair, so as soon as the time expires, the pair is deleted from the database. The timeout can be reset by issuing a command. Sounds exactly like session timeout, right?&lt;/p&gt;

&lt;p&gt;In order for this to work, you will need two things:&lt;/p&gt;

&lt;h3&gt;
  
  
  1 - The Authentication module
&lt;/h3&gt;

&lt;p&gt;You will have to create one microservice responsible for the authentication of your users. It will receive the request with the username and password, check if the password is correct, and then create the session data on Redis.&lt;/p&gt;

&lt;p&gt;It will have to generate the opaque token, retrieve the user data from your database, and then store the token and the data on Redis. Also, as soon as this is done, it will have to return the token to the client who requested the login, preferably in a SetCookie header if the client is a web browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 - The Authorization module
&lt;/h3&gt;

&lt;p&gt;I prefer to make this module sit within every microservice, but you can also set this up on your API Gateway if you like. Its responsibility is to fetch the request and extract the opaque token from it, then reach Redis to retrieve the user session data and make it available to the module that will process that request.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  To sum it up
&lt;/h3&gt;

&lt;p&gt;As you can see, the solution is much simpler, faster and more secure than using JWT for user session control. But have in mind these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you are using a single shard of Redis, this can be your single point of failure. I recommend using a more robust production setup with more shards and data replication.&lt;/li&gt;
&lt;li&gt;Session data can be modified by every module with access to Redis - use an "only add never delete" approach, just as you would in the old days.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this helps.&lt;/p&gt;

&lt;p&gt;As a bonus, here is a SessionManager to help with the implementation in Java using Jedis and Tomcat's token generator, usually included in Spring Boot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/Honatas/e64d59a015f28f7bab01686055072d64" rel="noopener noreferrer"&gt;SessionManager&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://gist.github.com/Honatas/097a5dff24b99b688d40e433ebfae2bb" rel="noopener noreferrer"&gt;RedisClient&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

</description>
      <category>redis</category>
      <category>microservices</category>
      <category>security</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
