<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Leandro Lima</title>
    <description>The latest articles on Forem by Leandro Lima (@leandrostl).</description>
    <link>https://forem.com/leandrostl</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%2F380765%2Fde4d2a62-91cc-47a7-9ac4-9e777fb2eaec.jpg</url>
      <title>Forem: Leandro Lima</title>
      <link>https://forem.com/leandrostl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/leandrostl"/>
    <language>en</language>
    <item>
      <title>Demystifying CPF and CNPJ Check Digit Algorithms: A Clear and Concise Approach</title>
      <dc:creator>Leandro Lima</dc:creator>
      <pubDate>Mon, 02 Sep 2024 21:56:50 +0000</pubDate>
      <link>https://forem.com/leandrostl/demystifying-cpf-and-cnpj-check-digit-algorithms-a-clear-and-concise-approach-f3j</link>
      <guid>https://forem.com/leandrostl/demystifying-cpf-and-cnpj-check-digit-algorithms-a-clear-and-concise-approach-f3j</guid>
      <description>&lt;p&gt;I vividly rememeber my first encounter with the CPF (Brazillian ID) validation algorihm during my underagraduated studies. While applying for an internship at the Institute of Exact Sciences at UFMG, the Federal University of Minas Gerais, we were asked to write a Java code, by hand, to validate CPF check digits after a brief explanation of the algorithm.&lt;/p&gt;

&lt;p&gt;Since then, I've come across this problem several times in different professional contexts, often resorting to copying solutions from the internet and adding some unit tests. However, each time, I'm struck by the recurring issues in these solutions. They tend to be more rooted in an imperative paradigm than the exptected object-oriented approach for Java codes. But, what bothers me even more, the high cognitive load these implementations impose that turns impratical to read, and understand the code's intent.&lt;/p&gt;

&lt;p&gt;An interested developer who hasn't yet needed to implement this code can easily find solutions in any programming language. However, they all tend to be presented the same way: a naive replication of the explanation for how the CPF check digits are implemented. It seems that few people take the time to understand the reasoning behind this approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The collision problem
&lt;/h2&gt;

&lt;p&gt;In software development, the concept of collision avoidance is often encountered in hash code algorithms, particularly with the use of prime number modulus. The check digits in CPF (Brazillian ID) and CNPJ (Brazillian company ID) function similarly, fucusing on avoiding collisions. This ensures that a simple summation of digits doesn't mistakenly validate incorrect entries, as multiple combinations can produce the same sum.&lt;/p&gt;

&lt;p&gt;To mitigate this, a common practice is to apply weighted sums, miltiplying each digit by a specific factor. You can think of this as spreading the digits out along a line; the multiplication makes it less likely for multiple digits land in the same position. It makes sense, then, that the digit's position in the number determines its weight. &lt;/p&gt;

&lt;p&gt;To further enhance reliability and minimize the risk of collisions, the sum is taken modulo 11, and this result is subtracted from the same prime number. To ensure that the check digit remains a single digit, results of 10 and 11 are converted to 0.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cognitive load
&lt;/h2&gt;

&lt;p&gt;The algorithm used to calculate the check digits for CPF and CNPJ can be difficult to understand. While the overall motivation behind the algorithm might be clear, it's ofen challenging to grasp the specific role of each part. This complexit arises partly because the caculation involves a series of mathematical computations that are often lumped together in a single, large method. Additionally, the weights, tipically presented as an inexplicable array, can appear illogical.&lt;/p&gt;

&lt;p&gt;To combat this, I focus on reducing the amount of code that laks self-explanation. By adhering to the Single Responsability Principal (the "S" in SOLID), I strive to create simpler, more understandlable methods. I also make an effor to define key concepts through meaningful variable names, aiming to establish a ubiquitous language within the codebase. With this approach, I sought to identify what differentiates the method used for CPF check digits from that used for CNPJ, as software that requires one often needs the other. The core functionality of the code is showed below, also, for a further view, including the complete code and associated unit tests, please visit my &lt;a href="https://github.com/leandrostl/document-validator" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getCheckDigits&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;document&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxWeight&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lengthWithoutCheckDigits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getBaseDigitsLength&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;firstWeightedSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;secondWeightedSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;lengthWithoutCheckDigits&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Character&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNumericValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lengthWithoutCheckDigits&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;reverseIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;maxIndex&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;firstWeightedSum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;calculateWeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverseIndex&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxWeight&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// Index is incremented, starting from 3, skipping first check digit.&lt;/span&gt;
      &lt;span class="c1"&gt;// The first part will be added later as the calculated first check digit times its corresponding weight.&lt;/span&gt;
      &lt;span class="n"&gt;secondWeightedSum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;calculateWeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reverseIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxWeight&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;firstDigit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getCheckDigit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstWeightedSum&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Add the first part as the first check digit times the first weight.&lt;/span&gt;
    &lt;span class="n"&gt;secondWeightedSum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="no"&gt;MIN_WEIGHT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;firstDigit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;secondDigit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getCheckDigit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secondWeightedSum&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;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstDigit&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;secondDigit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;calculateWeight&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;complementaryIndex&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxWeight&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;complementaryIndex&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxWeight&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="no"&gt;MIN_WEIGHT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getCheckDigit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;weightedSum&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;checkDigit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enhanceCollisionAvoidance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weightedSum&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;checkDigit&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;checkDigit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;enhanceCollisionAvoidance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;weightedSum&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;weightSumLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;weightSumLimit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;weightedSum&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;weightSumLimit&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;Compare the result that calculates check digits for both CNPJ and CPF with the tipical solution found in Internet:&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;class&lt;/span&gt; &lt;span class="nc"&gt;ValidaCNPJ&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isCNPJ&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;CNPJ&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// considera-se erro CNPJ's formados por uma sequencia de numeros iguais&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CNPJ&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="s"&gt;"00000000000000"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;CNPJ&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="s"&gt;"11111111111111"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="no"&gt;CNPJ&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="s"&gt;"22222222222222"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;CNPJ&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="s"&gt;"33333333333333"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="no"&gt;CNPJ&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="s"&gt;"44444444444444"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;CNPJ&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="s"&gt;"55555555555555"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="no"&gt;CNPJ&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="s"&gt;"66666666666666"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;CNPJ&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="s"&gt;"77777777777777"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="no"&gt;CNPJ&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="s"&gt;"88888888888888"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;CNPJ&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="s"&gt;"99999999999999"&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="no"&gt;CNPJ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;dig13&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dig14&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// "try" - protege o código para eventuais erros de conversao de tipo (int)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// Calculo do 1o. Digito Verificador&lt;/span&gt;
      &lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// converte o i-ésimo caractere do CNPJ em um número:&lt;/span&gt;
&lt;span class="c1"&gt;// por exemplo, transforma o caractere '0' no inteiro 0&lt;/span&gt;
&lt;span class="c1"&gt;// (48 eh a posição de '0' na tabela ASCII)&lt;/span&gt;
        &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="no"&gt;CNPJ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;11&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="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
         &lt;span class="n"&gt;dig13&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'0'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;dig13&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;)((&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Calculo do 2o. Digito Verificador&lt;/span&gt;
      &lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="no"&gt;CNPJ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)-&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;11&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="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
         &lt;span class="n"&gt;dig14&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'0'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;dig14&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;)((&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Verifica se os dígitos calculados conferem com os dígitos informados.&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;dig13&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;CNPJ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dig14&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;CNPJ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InputMismatchException&lt;/span&gt; &lt;span class="n"&gt;erro&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="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This piece of code is just for CNPJ!&lt;/p&gt;

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

&lt;p&gt;While the result code may appear somewhat verbose, my emphasis on clarity and self-explanation led to an outcome that I am satisfied with. The code is designed to be more intuitive, offering greater confidence in its correctness and, also, most of the core functionality is visible without scrolling down the page.&lt;/p&gt;

&lt;p&gt;I welcome any suggestions for further improvement, so please feel free to share your feedback.&lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
      <category>cleancode</category>
      <category>ddd</category>
    </item>
    <item>
      <title>[Code Compare] 2. Collections.singletonList vs List.of</title>
      <dc:creator>Leandro Lima</dc:creator>
      <pubDate>Tue, 06 Aug 2024 23:41:46 +0000</pubDate>
      <link>https://forem.com/leandrostl/code-compare-collectionssingletonlist-vs-listof-385</link>
      <guid>https://forem.com/leandrostl/code-compare-collectionssingletonlist-vs-listof-385</guid>
      <description>&lt;p&gt;In this serie of posts, I'm comparing different ways to code the same functionality. &lt;a href="https://dev.to/leandrostl/code-compare-1-arraylist-vs-collectionssingletonlist-3cno"&gt;Last post&lt;/a&gt; compared &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html" rel="noopener noreferrer"&gt;Collections.singletonList&lt;/a&gt; and &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html" rel="noopener noreferrer"&gt;ArrayList&lt;/a&gt; for creating a single-element list.&lt;/p&gt;

&lt;p&gt;In this post I'll compare &lt;code&gt;Collections.singletonList&lt;/code&gt; whith another well-known &lt;a href="https://refactoring.guru/design-patterns/factory-method/java/example" rel="noopener noreferrer"&gt;Factory Method&lt;/a&gt;, &lt;a href="https://docs.oracle.com/en%2Fjava%2Fjavase%2F22%2Fdocs%2Fapi%2F%2F/java.base/java/util/List.html#of(java.lang.Object[])" rel="noopener noreferrer"&gt;List.of&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collections::singletonList
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Method signature
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; singletonList(T o)&lt;/code&gt;&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singletonList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"742 Evergreen Terrace"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Springfield"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"New York"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"13468"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"US"&lt;/span&gt;
        &lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addresses&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;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;This method returns an immutable list containing only the specified object. It was introduced in Java 1.3. The advantages over ArrayList were covered in the last post, but to recap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inline implementation:&lt;/strong&gt; Initialize with the desired element in a single line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutability:&lt;/strong&gt; The list's size and content of its single element cannot be changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Allocation:&lt;/strong&gt; The &lt;code&gt;SingletonList&lt;/code&gt; class contains only one field for the single element.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPU usage:&lt;/strong&gt; The &lt;code&gt;SingletonList&lt;/code&gt; constructor accepts the single element as a parameter, requiring no resizing or array maniputalion.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  List::of
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Method signature
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;static &amp;lt;E&amp;gt; List&amp;lt;E&amp;gt; of()&lt;/code&gt;&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;addresses2&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;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"1007 Mountain Drive"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Bristol Township"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"New Jersey"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"US"&lt;/span&gt;
        &lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addresses2&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;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;List.of(E e)&lt;/code&gt; method is also a Factory Method that returns an unmodifiable list. Unlike &lt;code&gt;Collections.singletonList(E e)&lt;/code&gt;, which supports only one element, &lt;code&gt;List.of&lt;/code&gt; supports 0 to 10 elements, as well as arrays with multiple elements. It was introduced in Java 9, 17 years after &lt;code&gt;singletonList&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's interesting note that, unlike &lt;code&gt;SingletonList&lt;/code&gt;, which has the comment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Returns an &lt;strong&gt;immutable list&lt;/strong&gt; containing only the specified object.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;the &lt;code&gt;Array.of&lt;/code&gt; states that it is an &lt;em&gt;Unmodifiable List&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Returns an unmodifiable list containing one element.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;This reflects a new understand of immutability of collections. According this &lt;a href="https://docs.oracle.com/en/java/javase/16/core/java-core-libraries-developer-guide.pdf" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;A collection is considered unmodifiable if elements cannot be added, removed, or replaced. However, an unmodifiable collection is only immutable if the elements contained in the collection are immutable.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Dispite this differences in terminology, both factory methods have almost the same functionality. Looking deeper inside the &lt;code&gt;UnmodifiableList&lt;/code&gt;, we can find:&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;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;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="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e1&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;new&lt;/span&gt; &lt;span class="nc"&gt;ImmutableCollections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;List12&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;e1&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;What a surprise, they went with the not-so-precise term &lt;em&gt;Immutable&lt;/em&gt;, though!&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;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;List12&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt;     
    &lt;span class="nc"&gt;AbstractImmutableList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nd"&gt;@Stable&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="nd"&gt;@Stable&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="nc"&gt;List12&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e0&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;e0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e0&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;e1&lt;/span&gt; &lt;span class="o"&gt;=&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractImmutableList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt;
  &lt;span class="nc"&gt;AbstractImmutableCollection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;implements&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="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="nc"&gt;RandomAccess&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

      &lt;span class="c1"&gt;// all mutating methods throw UnsupportedOperationException&lt;/span&gt;
      &lt;span class="nd"&gt;@Override&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;    &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;uoe&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="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;uoe&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="no"&gt;E&lt;/span&gt;       &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;uoe&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="kt"&gt;void&lt;/span&gt;    &lt;span class="nf"&gt;replaceAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnaryOperator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;uoe&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="no"&gt;E&lt;/span&gt;       &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;uoe&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="kt"&gt;void&lt;/span&gt;    &lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;uoe&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only difference is that &lt;code&gt;List12&lt;/code&gt; has two fields for potentially two elements, which also results in a negligible memory footprint unless dealing with large objects.&lt;/p&gt;

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

&lt;p&gt;This time, we compared &lt;code&gt;Collections.singletonList&lt;/code&gt; and &lt;code&gt;List.of&lt;/code&gt; factory methods to create a single-element list. We discussed about the semantics of &lt;em&gt;immutable&lt;/em&gt; and &lt;em&gt;unmodifiable&lt;/em&gt; and showed that both methods are efficient, concise, and resource-light. If you can use a more recent Java version, it's prefferable for its familiarity, clarity and because we use &lt;code&gt;List&lt;/code&gt; interface much more than &lt;code&gt;Collections&lt;/code&gt;. If restritcted to an older Java version, &lt;code&gt;Collections.singletonList&lt;/code&gt; remains a solid choice.&lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>[Code Compare] 1. ArrayList vs Collections.singletonList</title>
      <dc:creator>Leandro Lima</dc:creator>
      <pubDate>Tue, 06 Aug 2024 02:54:50 +0000</pubDate>
      <link>https://forem.com/leandrostl/code-compare-1-arraylist-vs-collectionssingletonlist-3cno</link>
      <guid>https://forem.com/leandrostl/code-compare-1-arraylist-vs-collectionssingletonlist-3cno</guid>
      <description>&lt;p&gt;I am starting a new thread to compare different ways to code the same functionality. In this post, I'll compare two common methods to create a simple list with only one element. Specifically, I'll examine the most commonly used &lt;code&gt;List&lt;/code&gt; implementation constructor and the &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html" rel="noopener noreferrer"&gt;Collections.singletonList&lt;/a&gt;, a straightforward &lt;a href="https://refactoring.guru/design-patterns/factory-method/java/example" rel="noopener noreferrer"&gt;Factory Method&lt;/a&gt; for creating an immutable list containing a single element. &lt;/p&gt;

&lt;h2&gt;
  
  
  Array List
&lt;/h2&gt;

&lt;p&gt;Everytime you initialize an &lt;code&gt;ArrayList&lt;/code&gt; without specifying its initial capacity, it starts with an empty array. When you add the first element, the &lt;code&gt;ArrayList&lt;/code&gt; resizes using a relatively havy algorithm that involves copying the array. Let's take a look at the &lt;code&gt;ArrayList&lt;/code&gt; structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;DEFAULT_CAPACITY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="no"&gt;DEFAULTCAPACITY_EMPTY_ELEMENTDATA&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="nf"&gt;ArrayList&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;elementData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DEFAULTCAPACITY_EMPTY_ELEMENTDATA&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="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;modCount&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
    &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&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;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;s&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="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;elementData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grow&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;grow&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="nf"&gt;grow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;grow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;minCapacity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;elementData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                      &lt;span class="n"&gt;newCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minCapacity&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;newCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;minCapacity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// overflow-conscious code&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;minCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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="n"&gt;elementData&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;DEFAULTCAPACITY_EMPTY_ELEMENTDATA&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DEFAULT_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minCapacity&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="n"&gt;minCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// overflow&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OutOfMemoryError&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;minCapacity&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="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;MAX_ARRAY_SIZE&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;newCapacity&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hugeCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minCapacity&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's what happens step-by-step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An initial empty array &lt;code&gt;elementData&lt;/code&gt; is created.&lt;/li&gt;
&lt;li&gt;When you add the first element, the current size (which is zero) is compared to the length of the array.&lt;/li&gt;
&lt;li&gt;Since it found out that the its size is zero, the array needs to grow to accomodate the new element.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;grow&lt;/code&gt; method is called, which calculates the new capacity.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;newCapacity&lt;/code&gt; is initially increased by half the old capacity, which let us with &lt;code&gt;0 + 0/2 = 0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Since &lt;code&gt;newCapacity&lt;/code&gt; is not sufficient to accomodate the element, it continues.&lt;/li&gt;
&lt;li&gt;As it found out that &lt;code&gt;elementData&lt;/code&gt; is the same initial empty array, it finally returns maximum between the required size (1) and the &lt;code&gt;DEFAULT_CAPACTIY&lt;/code&gt; (10), resulting in an array of size 10.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This resizing process is quite complex when you only need a simple list that will always contain a single element.&lt;/p&gt;

&lt;p&gt;That said, let's talk about our alternative!&lt;/p&gt;

&lt;h2&gt;
  
  
  Collection::singletonList
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Method signature:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; singletonList(T o)&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;This method returns an immutable list containing only the specified object. Introducted in Java 1.3, &lt;code&gt;singletonList&lt;/code&gt; has several advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inline implementation:&lt;/strong&gt; You can initialize it with the desired element in a single line.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Immutability:&lt;/strong&gt; Let's take a look at its implementation:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SingletonList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RandomAccess&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nc"&gt;SingletonList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;AbstractList&lt;/code&gt;, from which &lt;code&gt;SingletonList&lt;/code&gt; inherits, defines all mutable methods like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;e&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;true&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnsupportedOperationException&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="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnsupportedOperationException&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="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnsupportedOperationException&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;p&gt;This ensures that it's impossible to chante the list's size or the content of its single element.&lt;/p&gt;

&lt;p&gt;Immutability is a highly advantageous feature. While I won't delve into it here, interested developers can learn more from this &lt;a href="https://docs.oracle.com/javase%2Ftutorial%2F/essential/concurrency/immutable.html" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Allocation:&lt;/strong&gt; The &lt;code&gt;SingletonList&lt;/code&gt; class contains only one simple field to accommodate the single element, unlike &lt;code&gt;ArrayList&lt;/code&gt;, which uses an array that, using simple &lt;code&gt;ArrayList&lt;/code&gt; simple constructor, will leave us with an array with size of 10 after element addition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU usage:&lt;/strong&gt; The &lt;code&gt;SingletonList&lt;/code&gt; constructor accepts the single element as a parameter, requiring no resizing, array copy or maniputalion. This is far more efficient compared to the &lt;code&gt;ArrayList&lt;/code&gt; &lt;code&gt;add&lt;/code&gt; method.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;In this post, we compared two ways to create a simple list with a single element: using the &lt;code&gt;ArrayList&lt;/code&gt;constructor and the &lt;code&gt;Collection.singletonList&lt;/code&gt; method. While &lt;code&gt;ArrayList&lt;/code&gt; is a flexible and commonly used data structure, it comes with some unnecessary overhead, particularly in terms of memory allocation and CPU usage when adding elements. This overhead includes resizing and copying arrays, which can be redundant for a list that is meant to hold only one element. However, if you need to change this element, &lt;code&gt;ArrayList&lt;/code&gt; is a suitable solution.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;code&gt;Collection.singletonList&lt;/code&gt; offers a more efficient alternative for creating a single-element list. This method is not only more concise and easier to use but also ensures immutability, which can be a significant advantage in many scenarios. It has a minimal memory footprint and requires almost no CPU resources compared to &lt;code&gt;ArrayList&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In summary, for a simple, immutable list containing only one element, &lt;code&gt;Collection.singletonList&lt;/code&gt; is a superior choice due to its efficiency, simplicity, and immutability. However, if you need to modify the element in the list, the &lt;code&gt;ArrayList&lt;/code&gt; could be an more appropriate choice.&lt;/p&gt;

&lt;p&gt;On the next post I'll compare another alternative for a single-element list: &lt;code&gt;List.of&lt;/code&gt; factory method. See you later!&lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>LocalStack: O poder da AWS direto da sua máquina</title>
      <dc:creator>Leandro Lima</dc:creator>
      <pubDate>Tue, 14 Jun 2022 21:48:44 +0000</pubDate>
      <link>https://forem.com/leandrostl/localstack-o-poder-da-aws-direto-da-sua-maquina-34mh</link>
      <guid>https://forem.com/leandrostl/localstack-o-poder-da-aws-direto-da-sua-maquina-34mh</guid>
      <description>&lt;h2&gt;
  
  
  O que você vai ver nesse artigo
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;AWS services: APIGateway, Lambda, DynamoDB&lt;/li&gt;
&lt;li&gt;LocalStack Community&lt;/li&gt;
&lt;li&gt;NodeJs&lt;/li&gt;
&lt;li&gt;Docker Compose&lt;/li&gt;
&lt;li&gt;Terraform&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  O que vamos fazer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Definição da nossa POC (Proof of Concept)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd07uy81jr2ojhqrzmt49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd07uy81jr2ojhqrzmt49.png" alt="Diagrama do nosso Projeto: Um ApiGateway que recebe requisições que são tratadas por dois Lambdas, um para métodos GET e outro para métodos POST; uma fila SQS onde as mensagens são gravadas e capturadas por outro Lambda que as persiste em um banco de dados DynamoDB."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O objetivo desse artigo é exemplificar o uso da LocalStack e o que é necessário para rodar um projeto simples. Para além do que usamos aqui, a ferramenta possui inúmeros outros recursos, bem como outros serviços ofertados pela AWS, que não abordarei.&lt;/p&gt;

&lt;p&gt;Nossa POC é portanto muito simples. Trata-se de uma solução que envolve um APIGateway que recebe requisições para busca, listagem e criação de mensagens de vilões famosos. As requests de criação são tratadas por um Lambda criado com NodeJs que grava essas mensagens em uma fila SQS que por sua vez tem um gatilho para que outro Lambda recupere essa frase e a persista em um banco DynamoDB. Na parte de listagem e detalhamento da mensagem, usamos outro Lambda que busca a mensagem da base de dados e retorna para o usuário.&lt;/p&gt;

&lt;p&gt;Toda a configuração da aplicação foi feita usando o Terraform com arquivos de configuração bastante simples de entender.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repositório
&lt;/h3&gt;

&lt;p&gt;Todo esse projeto e os códigos completos estão disponíveis no seguinte &lt;a href="https://github.com/leandrostl/localstack-terraform-tutorial" rel="noopener noreferrer"&gt;repositório&lt;/a&gt;. Este texto contém alguns&lt;br&gt;
pedaços de códigos que podem não estar completos.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;TL;DR&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Para quem quer um passo-a-passo rápido de como verificar e executar essa POC, continue nessa sessão. Se você prefere uma explicação bastante minuciosa das decisões e formas para alcançar o resultado do projeto, pule para a sessão seguinte.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparando o ambiente:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clone o projeto do &lt;a href="https://github.com/leandrostl/LocalStack-terraform-tutorial" rel="noopener noreferrer"&gt;repositório&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Instale o Docker a partir da &lt;a href="https://docs.docker.com/engine/install/ubuntu/" rel="noopener noreferrer"&gt;documentação&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Instale o docker-compose:

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo chmod +x /usr/local/bin/docker-compose&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Instale o Python seguindo a &lt;a href="https://python.org.br/instalacao-linux/" rel="noopener noreferrer"&gt;documentação oficial&lt;/a&gt;;&lt;/li&gt;

&lt;li&gt;Instale o AWS CLI: &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;página oficial&lt;/a&gt;;&lt;/li&gt;

&lt;li&gt;Instale o Localstack: &lt;code&gt;sudo python3 -m pip install localstack&lt;/code&gt;
&lt;/li&gt;

&lt;li&gt;Instale o awscli-local: &lt;code&gt;pip install awscli-local&lt;/code&gt;
&lt;/li&gt;

&lt;li&gt;Siga a &lt;a href="https://www.terraform.io/downloads" rel="noopener noreferrer"&gt;orientação oficial&lt;/a&gt; para instalar o Terraform;&lt;/li&gt;

&lt;li&gt;NodeJs:

&lt;ol&gt;
&lt;li&gt; NVM: &lt;a href="https://github.com/nvm-sh/nvm#install--update-script" rel="noopener noreferrer"&gt;repositório oficial&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; NodeJs: &lt;a href="https://github.com/nvm-sh/nvm#usage" rel="noopener noreferrer"&gt;comando descrito no repositório&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  Rodando a aplicação:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;No diretório raiz execute o comando: &lt;code&gt;docker-compose up -d&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No diretório terraform execute: 

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;terraform init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;terraform apply --auto-approve&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Para testar:

&lt;ol&gt;
&lt;li&gt;Instale a extensão &lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" rel="noopener noreferrer"&gt;REST Client&lt;/a&gt; para o VSCode;&lt;/li&gt;
&lt;li&gt;Abra o arquivo &lt;code&gt;test.http&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Altere a variável &lt;code&gt;API_ID&lt;/code&gt; para o id informado na saída do terraform;&lt;/li&gt;
&lt;li&gt;Clique em send request para envio da request de POST;&lt;/li&gt;
&lt;li&gt;Verifique os serviços e logs da sua aplicação em &lt;a href="https://app.localstack.cloud/" rel="noopener noreferrer"&gt;https://app.localstack.cloud/&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Verifique, após alguns segundos, se a frase está salva na base de dados, enviando a request de GET com o seu vilão favorito.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  Matando a aplicação:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Use o comando &lt;code&gt;terraform destroy --auto-approve&lt;/code&gt; a partir do diretório terraform para remover os serviços AWS&lt;/li&gt;
&lt;li&gt;Do diretório raiz, utilize o comando &lt;code&gt;docker-compose down -v&lt;/code&gt; para apagar todos os recursos criados através do docker-compose.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Versão estendida: tudo o que você precisa para criar a sua própria POC
&lt;/h2&gt;

&lt;p&gt;Na sessão anterior, fizemos um passo-a-passo rápido para rodar a aplicação. Nessa sessão vamos ir mais a fundo, e explicar tudo o que for necessário para a criação da sua própria POC, do zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configurando o ambiente
&lt;/h3&gt;

&lt;p&gt;Estou usando uma máquina rodando Ubuntu 20.04.3 LTS. Tudo o que for feito aqui também é possível usando uma máquina Windows ou Mac. Porém, os métodos para instalação mudam.&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker
&lt;/h4&gt;

&lt;p&gt;Vamos começar instalando o Docker. Segui precisamente a documentação da página oficial para instalação no Ubuntu. Você pode verificar a versão instalada no seu ambiente com o comando &lt;code&gt;docker -v&lt;/code&gt;. Para mim, ele retorna:  &lt;code&gt;Docker version 20.10.12, build e91ed57.&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker Compose
&lt;/h4&gt;

&lt;p&gt;Docker Compose foi um pouco mais complicado para instalar. A página do Docker aponta para uma versão muito antiga do &lt;em&gt;compose&lt;/em&gt;. Preferi entrar no &lt;a href="https://github.com/docker/compose/releases" rel="noopener noreferrer"&gt;repositório do github&lt;/a&gt; para verificar e alterar o endereço no comando fornecido na página do Docker. Desta forma, executei os seguintes comandos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo chmod +x /usr/local/bin/docker-compose&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agora, a versão que tenho do docker-compose instalada é:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    leandro@leandro-desktop ~&amp;gt; docker-compose &lt;span class="nt"&gt;-v&lt;/span&gt;
    Docker Compose version v2.2.3


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Python
&lt;/h4&gt;

&lt;p&gt;A &lt;em&gt;LocalStack&lt;/em&gt; usa o compilador Python. Assim precisei instalá-lo, além do gerenciador de pacotes. Segui a &lt;a href="https://python.org.br/instalacao-linux/" rel="noopener noreferrer"&gt;documentação oficial&lt;/a&gt;. Instalei as seguintes versões:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

   leandro@leandro-desktop:~&lt;span class="nv"&gt;$ &lt;/span&gt;python3 &lt;span class="nt"&gt;--version&lt;/span&gt;
   Python 3.8.10
   leandro@leandro-desktop:~&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nt"&gt;--version&lt;/span&gt;
   pip 20.0.2 from /usr/lib/python3/dist-packages/pip &lt;span class="o"&gt;(&lt;/span&gt;python 3.8&lt;span class="o"&gt;)&lt;/span&gt;


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  AWS CLI
&lt;/h4&gt;

&lt;p&gt;Para rodar comandos no terminal para acesso aos dados de serviços da AWS, mesmo que na LocalStack, é necessário usar o &lt;em&gt;AWS CLI&lt;/em&gt;. Para sua instalação, eu segui o passo a passo informado na &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;página oficial&lt;/a&gt;. Verificando a versão, obtive:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

leandro@leandro-desktop ~&amp;gt; aws &lt;span class="nt"&gt;--version&lt;/span&gt;
aws-cli/2.4.11 Python/3.8.8 Linux/5.4.0-94-generic exe/x86_64.ubuntu.20 prompt/off


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  LocalStack
&lt;/h4&gt;

&lt;p&gt;Para instalar o LocalStack eu tentei seguir o repositório oficial que dizia que não deveria ser instalado usando &lt;em&gt;sudo&lt;/em&gt;, mas não funcionou. Instalei com o seguinte comando:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

   &lt;span class="nb"&gt;sudo &lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;localstack


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

&lt;/div&gt;

&lt;p&gt;e a versão que tenho instalada é:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

leandro@leandro-desktop:~&lt;span class="nv"&gt;$ &lt;/span&gt;LocalStack &lt;span class="nt"&gt;--version&lt;/span&gt;
0.13.3.1


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

&lt;/div&gt;

&lt;p&gt;Também instalei o awscli-local com o comando &lt;code&gt;pip install awscli-local&lt;/code&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Terraform
&lt;/h4&gt;

&lt;p&gt;O Terraform é uma ferramenta de código de infraestrutura ou &lt;em&gt;infrastructure as a code&lt;/em&gt;. É open source e mantido pela HashCorp. Para instalar, segui a &lt;a href="https://www.terraform.io/downloads" rel="noopener noreferrer"&gt;orientação oficial&lt;/a&gt;. Após instalado, testei a versão para:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

leandro@leandro-desktop:~&lt;span class="nv"&gt;$ &lt;/span&gt;terraform &lt;span class="nt"&gt;-v&lt;/span&gt;
Terraform v1.1.3
on linux_amd64


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  NodeJs
&lt;/h4&gt;

&lt;p&gt;A escolha de &lt;em&gt;NodeJs&lt;/em&gt; para esse tutorial foi bastante concorrida com &lt;em&gt;Python&lt;/em&gt;. Mas pesou o conhecimento e a reutilização do &lt;em&gt;JavaScript&lt;/em&gt; em front-end. Aqui vai uma &lt;a href="https://dashbird.io/blog/most-efficient-lambda-language/" rel="noopener noreferrer"&gt;análise bem interessante&lt;/a&gt; sobre as possíveis linguagens para desenvolvimento para &lt;em&gt;AWS Lambdas&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Para instalar o Node no meu ambiente eu optei por usar o &lt;a href="https://nodejs.org/en/download/package-manager/#nvm" rel="noopener noreferrer"&gt;NVM, gerenciador de versão do NodeJs&lt;/a&gt;. Esse gerenciador pode ser baixado do &lt;a href="https://github.com/nvm-sh/nvm#install--update-script" rel="noopener noreferrer"&gt;repositório oficial&lt;/a&gt;. Após instalado o NVM, basta seguir o &lt;a href="https://github.com/nvm-sh/nvm#usage" rel="noopener noreferrer"&gt;comando descrito no repositório&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Com isso a versão do Node na minha máquina ficou:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

leandro@leandro-desktop:~&lt;span class="nv"&gt;$ &lt;/span&gt;node &lt;span class="nt"&gt;-v&lt;/span&gt;
v16.13.2
leandro@leandro-desktop:~&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nt"&gt;-v&lt;/span&gt;
8.1.2


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  AWS Cloud
&lt;/h3&gt;

&lt;p&gt;Escolhi abordar os seguintes serviços da AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/cli/latest/reference/apigateway/index.html" rel="noopener noreferrer"&gt;API Gateway&lt;/a&gt;: Permite criar endpoints e associá-los a um back-end.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudwatch/index.html?highlight=cloudwatch" rel="noopener noreferrer"&gt;Cloudwatch&lt;/a&gt;: Permite monitorar a aplicação com alarmes e logs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/index.html" rel="noopener noreferrer"&gt;Lambda&lt;/a&gt;: Permite executar uma função sem a necessidade de provisionar ou gerenciar um servidor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/index.html" rel="noopener noreferrer"&gt;DynamoDB&lt;/a&gt;: Banco de dados não relacional, &lt;em&gt;NoSQL&lt;/em&gt;, da AWS.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sqs/index.html" rel="noopener noreferrer"&gt;SQS - Simple Queue Service&lt;/a&gt;: Como o nome bem informa, é um serviço de filas de mensagens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As escolhas são baseadas em necessidades pessoais e naquilo que a LocalStack oferece gratuitamente.&lt;/p&gt;
&lt;h3&gt;
  
  
  LocalStack
&lt;/h3&gt;

&lt;p&gt;Para iniciar nosso projeto, é necessário subir a LocalStack em um container com as configurações adequadas para o ele. Para isso usei o docker-compose e criei um script seguindo a &lt;a href="https://docs.LocalStack.cloud/get-started/#docker-compose" rel="noopener noreferrer"&gt;página oficial&lt;/a&gt;. Além disso, busquei compreender e alterar alguns pontos, conforme a &lt;a href="https://docs.LocalStack.cloud/localstack/configuration/" rel="noopener noreferrer"&gt;documentação de configuração&lt;/a&gt;. Com isso, meu &lt;code&gt;docker-compose&lt;/code&gt; ficou assim:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

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

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;localstack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Determino o nome do container principal da aplicação.&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${LOCALSTACK_DOCKER_NAME-localstack-terraform-tutorial}&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localstack/localstack&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:4566:4566"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:4571:4571"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Como eu resolvi trocar o nome do container principal eu preciso informar em uma&lt;/span&gt;
      &lt;span class="c1"&gt;# variável de ambiente.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MAIN_CONTAINER_NAME=${LOCALSTACK_DOCKER_NAME-localstack-terraform-tutorial}&lt;/span&gt;
      &lt;span class="c1"&gt;# Informo os serviços da AWS que desejo usar.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SERVICES=${SERVICES-dynamodb,lambda,apigateway,sqs,cloudwatch}&lt;/span&gt;
      &lt;span class="c1"&gt;# Diretório para salvar dados localmente.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATA_DIR=${DATA_DIR-tmp/localstack/data}&lt;/span&gt;
      &lt;span class="c1"&gt;# Como nossas funções lambda serão executadas. Nesse caso escolho o padrão&lt;/span&gt;
      &lt;span class="c1"&gt;# rodar as funções dentro de containers para cada uma.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR-docker}&lt;/span&gt;
      &lt;span class="c1"&gt;# Esse parâmetro diz respeito a como a função será passada para o container. &lt;/span&gt;
      &lt;span class="c1"&gt;# Se ela será montada no container ou será copiada. Nesse caso, escolhi copiar&lt;/span&gt;
      &lt;span class="c1"&gt;# todo o arquivo zip para dentro do container.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LAMBDA_REMOTE_DOCKER=true&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${TMPDIR:-/tmp}/localstack:/tmp/localstack"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock"&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Para rodar o docker-compose, utilizei o comando &lt;code&gt;docker-compose up&lt;/code&gt;, ele vai subir todo o ambiente. Se quiser continuar a usar o mesmo terminal para outras coisas, adicione o &lt;code&gt;-d&lt;/code&gt; de &lt;em&gt;detach&lt;/em&gt;. Para finalizar e se desfazer de todo o ambiente, basta rodar o &lt;code&gt;docker-compose down -v&lt;/code&gt;. O &lt;code&gt;-v&lt;/code&gt; informa que você também quer que os volumes criados sejam excluídos, liberando todos os recursos do computador.&lt;/p&gt;

&lt;p&gt;Uma vez em execução, é possível verificar se está tudo funcionando corretamente através da URL &lt;a href="http://localhost:4566/health" rel="noopener noreferrer"&gt;http://localhost:4566/health&lt;/a&gt; e do &lt;a href="https://app.localstack.cloud/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt; oferecido pela LocalStack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform
&lt;/h3&gt;

&lt;p&gt;Agora vamos prover os serviços e suas configurações através do Terraform, especificando os recursos em arquivos &lt;code&gt;.tf&lt;/code&gt; que coloquei na pasta &lt;code&gt;terraform&lt;/code&gt;. &lt;br&gt;
Seguindo a &lt;a href="https://docs.localstack.cloud/integrations/terraform/" rel="noopener noreferrer"&gt;documentação da LocalStack&lt;/a&gt;, primeiro declaramos o &lt;code&gt;provider "aws"&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
  &lt;span class="nx"&gt;secret_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
  &lt;span class="nx"&gt;skip_credentials_validation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;skip_metadata_api_check&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;skip_requesting_account_id&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;endpoints&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;apigateway&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;cloudwatch&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;dynamodb&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;iam&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;lambda&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_endpoint&lt;/span&gt;
    &lt;span class="nx"&gt;sqs&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default_endpoint&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;Observe que é necessário apontar os serviços da AWS para o LocalStack. Aqui, eu preferi criar uma variável &lt;code&gt;default_endpoint&lt;/code&gt; para manter o endereço:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"default_endpoint"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Endpoint padrão para os serviços AWS local."&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://localhost:4566"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  API
&lt;/h4&gt;

&lt;p&gt;A declaração da api, o recurso quotes e os métodos são bem fáceis de compreender. E tem duas formas de se fazer isso. A primeira, é declarar blocos para cada api, recurso, integração, método:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# Declarando nossa api para acesso de frases e os métodos&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_rest_api"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Quotes"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Api para consumo e envio de frases para a aplicação."&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_resource"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;rest_api_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;parent_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root_resource_id&lt;/span&gt;
  &lt;span class="nx"&gt;path_part&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_method"&lt;/span&gt; &lt;span class="s2"&gt;"get_quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;rest_api_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;resource_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;http_method&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GET"&lt;/span&gt;
  &lt;span class="nx"&gt;authorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"NONE"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_method"&lt;/span&gt; &lt;span class="s2"&gt;"post_quote"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;rest_api_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;resource_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;http_method&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"POST"&lt;/span&gt;
  &lt;span class="nx"&gt;authorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"NONE"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_integration"&lt;/span&gt; &lt;span class="s2"&gt;"quote_receiver"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;rest_api_id&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;resource_id&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;http_method&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post_quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http_method&lt;/span&gt;
  &lt;span class="nx"&gt;integration_http_method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"POST"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AWS_PROXY"&lt;/span&gt;
  &lt;span class="nx"&gt;uri&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote_receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invoke_arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_deployment"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;rest_api_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;stage_name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Uma forma mais interessante de fazer isso é usando o &lt;a href="https://spec.openapis.org/oas/v3.1.0" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt; para declarar nossa api. Com isso, o nosso arquivo &lt;code&gt;rest-api.tf&lt;/code&gt; fica bem mais simples:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_rest_api"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Quotes API"&lt;/span&gt;
  &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"./openapi.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;quote_receiver&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${aws_lambda_function.quote_receiver.invoke_arn}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;quote_recover&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${aws_lambda_function.quote_recover.invoke_arn}"&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_deployment"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;rest_api_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_api_gateway_stage"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;deployment_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_deployment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;rest_api_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_api_gateway_rest_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;stage_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Eu prefiro declarar o OpenApi usando yaml, mas, por alguma razão, o Terraform não aceita yaml na sua definição do body. Por isso, instalei a extensão &lt;a href="https://marketplace.visualstudio.com/items?itemName=philosowaffle.openapi-designer" rel="noopener noreferrer"&gt;openapi-designer&lt;/a&gt; que compila os arquivos yaml para um único arquivo json. Minha definição para a API ficou assim:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.0.3&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Quotes Api&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Api para consumo e envio de frases para a aplicação.&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/quotes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Permite gravar uma nova frase vilanesca!&lt;/span&gt;
      &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Quote"&lt;/span&gt;
      &lt;span class="na"&gt;x-amazon-apigateway-auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
      &lt;span class="na"&gt;x-amazon-apigateway-integration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${quote_receiver}&lt;/span&gt;
        &lt;span class="na"&gt;httpMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POST&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS_PROXY&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;201"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Frase vilanesca gravada com sucesso!&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retorna as frases vilanesca de um vilão.&lt;/span&gt;
      &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;author&lt;/span&gt;
          &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;query&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;O grade vilão por trás das frases.&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;x-amazon-apigateway-auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
      &lt;span class="na"&gt;x-amazon-apigateway-integration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${quote_recover}&lt;/span&gt;
        &lt;span class="na"&gt;httpMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POST&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS_PROXY&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;200"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;As frases vilanescas para o vilão selecionado.&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
                &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Quote"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Nossa API, portanto, tem um recurso &lt;code&gt;quote&lt;/code&gt; que é disponível no path de &lt;code&gt;/quotes&lt;/code&gt; e permite os métodos &lt;code&gt;POST&lt;/code&gt; e &lt;code&gt;GET&lt;/code&gt; sem necessidade de qualquer autorização de acesso.&lt;/p&gt;

&lt;p&gt;Como vimos em nosso diagrama, o objetivo do projeto é que as frases enviadas sejam enviadas para uma fila por uma função Lambda e depois recuperada por outra função e gravada no banco de dados. Aqui, já declaramos a integração também com a função lambda. Vale notar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Observe que a integração agora é passada como parte do método através da propriedade &lt;code&gt;x-amazon-apigateway-integration&lt;/code&gt;. O mesmo para a authorization com a propriedade &lt;code&gt;x-amazon-apigateway-auth&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;O Terraform trata o arquivo pelo método &lt;em&gt;templatefile&lt;/em&gt; que troca os valores como &lt;code&gt;${quote_receiver}&lt;/code&gt; pelo valor passado como parâmetro.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;integration_http_method&lt;/code&gt; tem que ser do tipo &lt;code&gt;POST&lt;/code&gt; para integração com Lambda. Ele informa como a api vai interagir com o backend;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; deve ser, no nosso caso, &lt;code&gt;AWS_PROXY&lt;/code&gt;. Isso permite que a integração chame um recurso da AWS, no nosso caso a Lambda, e passe a request para a Lambda tratar.&lt;/li&gt;
&lt;li&gt;No arquivo yaml acima, observe que falta a parte de &lt;code&gt;components&lt;/code&gt;, que pode ser encontrada no repositório.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Lambdas
&lt;/h4&gt;

&lt;p&gt;Para receber a mensagem da API, declaramos no nosso &lt;code&gt;lambda.tf&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# Lambdas para processar as frases&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"archive_file"&lt;/span&gt; &lt;span class="s2"&gt;"quote_receiver"&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="s2"&gt;"zip"&lt;/span&gt;
  &lt;span class="nx"&gt;output_path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../lambdas/dist/quote_receiver.zip"&lt;/span&gt;
  &lt;span class="nx"&gt;source_dir&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../lambdas/quote-receiver/"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"quote_receiver"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"quote_receiver"&lt;/span&gt;
  &lt;span class="nx"&gt;filename&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;archive_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote_receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output_path&lt;/span&gt;
  &lt;span class="nx"&gt;source_code_hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;archive_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote_receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output_base64sha256&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.handler"&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nodejs14.x"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"fake_role"&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;SQS_URL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${resource.aws_sqs_queue.quotes.url}"&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;---&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_event_source_mapping"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event_source_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_sqs_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote_persister&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Geramos aqui um arquivo que foi criado na execução do terraform a partir da compactação dos dados dentro da pasta &lt;code&gt;lambdas/quote-receiver&lt;/code&gt;. O arquivo compactado é referenciado na criação da função. O mesmo ocorre para nossas outras funções, de persistência dos dados e de recuperação.&lt;/p&gt;

&lt;p&gt;Como é possível notar, temos um mapeamento da função &lt;code&gt;quote_persister&lt;/code&gt; com a fila &lt;code&gt;SQS&lt;/code&gt;. Isso nos permite receber eventos com as informações inseridas na fila sempre que forem adicionadas novas mensagens à ela.&lt;/p&gt;

&lt;p&gt;Um ponto interessante é que é possível passar variáveis de ambiente para a função, como é visto na passagem da variável &lt;code&gt;SQS_URL&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fila SQS
&lt;/h4&gt;

&lt;p&gt;Declarar a fila também é muito simples:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_sqs_queue"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Quotes"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  DynamoDB
&lt;/h4&gt;

&lt;p&gt;O provisionamento de uma tabela nova no dynamo demanda apenas os campos a seguir:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_dynamodb_table"&lt;/span&gt; &lt;span class="s2"&gt;"quotes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Quotes"&lt;/span&gt;
    &lt;span class="nx"&gt;hash_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"author"&lt;/span&gt;
    &lt;span class="nx"&gt;billing_mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PAY_PER_REQUEST"&lt;/span&gt;
    &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"author"&lt;/span&gt;
      &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S"&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;Poderíamos informar os demais atributos, mas apenas &lt;code&gt;hash_key&lt;/code&gt; é obrigatória.&lt;br&gt;
Esse atributo é equivalente para a AWS ao &lt;code&gt;partition key&lt;/code&gt;. Caso eu desejasse criar uma &lt;code&gt;sort key&lt;/code&gt; eu deveria passá-la como &lt;br&gt;
&lt;code&gt;range_key&lt;/code&gt; e também informar os dados do atributo. No código exemplo usei &lt;code&gt;sort key&lt;/code&gt; para me permitir usar frases diferentes&lt;br&gt;
do mesmo autor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Código
&lt;/h3&gt;

&lt;p&gt;Temos apenas três funções muito simples escritas usando NodeJs: uma para receber quotes, uma para persistir e outra para recuperar. Os códigos completos estão no repositório, mas &lt;br&gt;
vale a pena pontuar alguns detalhes:&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;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BatchWriteItemCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-dynamodb&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Marshaller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws/dynamodb-auto-marshaller&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;client&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;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LOCALSTACK_HOSTNAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:4566`&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;marshaller&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;Marshaller&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="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BatchWriteItemCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;RequestItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Quotes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;quotes&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;marshaller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;marshallItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;PutRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;



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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;O código para persistência de dados no Dynamo mostra o uso da SDK para JavaScript V3. &lt;/li&gt;
&lt;li&gt;Diferente da V2, essa versão permite importar apenas módulos que realmente serão necessários para a aplicação, deixando a Lambda muito mais leve. &lt;/li&gt;
&lt;li&gt;É necessário configurar o endpoint para os serviços da AWS.&lt;/li&gt;
&lt;li&gt;Usei a biblioteca &lt;code&gt;Marshaller&lt;/code&gt; que é um mapper entre valores nativos JavaScript e AttributeValues do DynamoDB.&lt;/li&gt;
&lt;li&gt;A melhor forma de ver logs da aplicação é pelo &lt;a href="https://app.localstack.cloud/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt; da LocalStack.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rodando nossa aplicação
&lt;/h3&gt;

&lt;p&gt;Uma vez que o ambiente está rodando através do docker-compose, podemos entrar na pasta &lt;code&gt;terraform&lt;/code&gt; e executar o comando &lt;code&gt;terraform init&lt;/code&gt;. Este comando irá criar uma pasta &lt;code&gt;.terraform&lt;/code&gt; e outros arquivos no projeto. Quando terminado é a vez do comando &lt;code&gt;terraform apply --auto-approve&lt;/code&gt; que realmente provisiona todos os recurso que declaramos no nossos arquivos &lt;code&gt;.tf&lt;/code&gt;. Ao final, o comando irá disponibilizar como retorno a &lt;code&gt;API_ID&lt;/code&gt;, necessária para testarmos a api em um http client.&lt;/p&gt;

&lt;p&gt;Assim que a aplicação subir, podemos testar sua funcionalidade com a collection de requests disponível no arquivo &lt;code&gt;test.http&lt;/code&gt;. Para rodar os testes nesse arquivo é necessário ter instalada a extensão &lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" rel="noopener noreferrer"&gt;REST Client&lt;/a&gt; para o Visual Studio Code. Uma vez instalada, troque o valor da variável @API_ID para aquele retornado pelo terraform e clique em send request. &lt;/p&gt;

&lt;p&gt;Para encerrar nossa aplicação, basta rodar o comando &lt;code&gt;docker-compose down -v&lt;/code&gt; a partir do diretório raiz do projeto.&lt;/p&gt;

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

&lt;p&gt;A LocalStack é uma ótima ferramenta para rodar a aplicação em ambiente local, durante o desenvolvimento. Ela elimina a preocupação de&lt;br&gt;
se &lt;em&gt;sujar&lt;/em&gt; um ambiente compartilhado por mais desenvolvedores ou de se acabar tendo gastos financeiros por uso indevido da AWS, melhorando muito o processo de criação do código. Essas funcionalidades ficam ainda mais&lt;br&gt;
interessantes quando se é um iniciante em Cloud por que não há riscos de se acabar pagando por algo que estava nas entrelinhas.&lt;/p&gt;

&lt;p&gt;Um aspecto que não foi abordado mas vale a pena pesquisar são as bibliotecas e integração da LocalStack com testes de integração. É possível rodar testes automatizados sem onerar a cloud.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>node</category>
      <category>tutorial</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Crie testes unitários mais amigáveis e mais rapidamente com Spock</title>
      <dc:creator>Leandro Lima</dc:creator>
      <pubDate>Mon, 10 Aug 2020 18:57:02 +0000</pubDate>
      <link>https://forem.com/leandrostl/crie-testes-unitarios-mais-amigaveis-e-mais-rapidamente-com-spock-4bgi</link>
      <guid>https://forem.com/leandrostl/crie-testes-unitarios-mais-amigaveis-e-mais-rapidamente-com-spock-4bgi</guid>
      <description>&lt;p&gt;Testes e especificações quase sempre são uma dor de cabeça para o desenvolvedor. Gastamos muito tempo escrevendo testes, às vezes muito mais tempo do que gastamos com o desenvolvimento. É difícil também nos ater exclusivamente à linguagem do negócio e escrever algo significativo. Bem mais fácil é nos apoiar nos resultados esperados do código. Assim qualquer alternativa para focar no negócio e fazer testes mais rapidamente é válida.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://spockframework.org/" rel="noopener noreferrer"&gt;Spock&lt;/a&gt;, a ferramenta, é um framework que traz o poder do &lt;a href="https://groovy-lang.org/" rel="noopener noreferrer"&gt;Groovy&lt;/a&gt; para tornar testes em geral mais expressivos, mais rápidos de escrever, mais agradáveis de ler e entender seguindo de maneira mais descritiva os passos de uma &lt;a href="http://xunitpatterns.com/Four%20Phase%20Test.html" rel="noopener noreferrer"&gt;especificação&lt;/a&gt; de quatro fases.&lt;/p&gt;

&lt;p&gt;O objetivo desse artigo é fazer uma varredura superficial das funcionalidades desse framework.&lt;/p&gt;

&lt;p&gt;O código usado nesse material está disponível &lt;a href="https://github.com/leandrostl/spock-test" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependências
&lt;/h2&gt;

&lt;p&gt;Criaremos um projeto sem arquétipo através do &lt;a href="http://maven.apache.org/" rel="noopener noreferrer"&gt;Maven&lt;/a&gt; e adicionaremos o plugin do &lt;a href="https://groovy.github.io/GMavenPlus/" rel="noopener noreferrer"&gt;GMaven&lt;/a&gt;, necessário para integrar o Groovy ao Maven, e o &lt;a href="https://bytebuddy.net/" rel="noopener noreferrer"&gt;Byte Buddy&lt;/a&gt;, sem dependências, necessário para criação de Mocks.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0"&lt;/span&gt;
         &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
         &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.leandro&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spock-maven-test&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Projeto para estudar como aplicar testes com Spock.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;maven.compiler.source&amp;gt;&lt;/span&gt;11&lt;span class="nt"&gt;&amp;lt;/maven.compiler.source&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;maven.compiler.target&amp;gt;&lt;/span&gt;11&lt;span class="nt"&gt;&amp;lt;/maven.compiler.target&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.spockframework&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spock-core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0-M2-groovy-3.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.jupiter&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-jupiter-engine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.6.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Byte Buddy permite manipular bytecodes em tempo de execução.
        Isso permite ao Spock criar Mocks sem necessidade de qualquer outra
        biblioteca dedicada. Outra alternativa ao Byte Buddy é a CGLIB. --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;net.bytebuddy&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;byte-buddy&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.10.13&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Opcional para usar banco de dados H2 --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.h2database&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;h2&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.200&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Permite criar relatórios para os testes. --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.athaydes&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spock-reports&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0-RC2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- Garante não afetar a versão do Groovy/Spock --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;exclusions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;exclusion&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;*&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/exclusion&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/exclusions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Necessário para criar relatórios --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.slf4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;slf4j-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.7.30&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.slf4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;slf4j-simple&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.7.30&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- O GMaven Plus permite código Groovy ser
            compilado e executado em projetos Maven. --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.codehaus.gmavenplus&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;gmavenplus-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.9.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;compileTests&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-surefire-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.0.0-M5&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;useFile&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/useFile&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*Test.java&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*Spec.java&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Segue um &lt;a href="https://www.jrebel.com/blog/java-code-generation-libraries-comparison" rel="noopener noreferrer"&gt;comparativo&lt;/a&gt; entre o Byte Buddy e o CGLIB.&lt;/p&gt;

&lt;p&gt;Os testes usando o Spock serão colocados na pasta &lt;code&gt;src/test/groovy*.*&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Vamos começar sentindo o gosto do framework criando um teste simples, mas que apresenta um pouco do poder de expressão:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Specification&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Unroll&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MaxTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Specification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Unroll&lt;/span&gt;
    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Verificar se o máximo entre #a e #b é #c"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;expect:&lt;/span&gt;
        &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;

        &lt;span class="nl"&gt;where:&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
        &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="mi"&gt;5&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&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;Dados três números, a, b e c, desejamos verificar se nossa aplicação, que calcula o máximo entre a e b, retorna c para cada um dos casos na tabela.&lt;/p&gt;

&lt;p&gt;Os resultados esperados são esses:&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%2Fj8hnjdx84xxui085rsb4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj8hnjdx84xxui085rsb4.png" alt="Resultados esperados"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com o Spock, escrevemos especificações, e para isso, estendemos a classe &lt;em&gt;Specification&lt;/em&gt;. Uma especificação é composta de&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Especificacao&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Specification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// fields&lt;/span&gt;
  &lt;span class="c1"&gt;// fixture methods&lt;/span&gt;
  &lt;span class="c1"&gt;// feature methods&lt;/span&gt;
  &lt;span class="c1"&gt;// helper methods&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Fields
&lt;/h2&gt;

&lt;p&gt;São equivalentes aos campos de classes Java, variáveis com escopo de classe. Entretanto, há uma diferença, a inicialização junto da declaração é equivalente a inicia-los dentro de um método anotado com &lt;code&gt;@BeforeEach&lt;/code&gt;. O framework faz dessa forma para isolar os métodos. É uma boa prática inicializa os campos no mesmo local da declaração.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Campos são variáveis de escopo de classe com instâncias individuais por escopo de método.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quando temos objetos muito grandes, que precisam de muito processamento para serem instanciados, é conveniente manter uma instância única e compartilha-la entre os métodos de teste. Para isso, o Spock utiliza a anotação &lt;code&gt;@Shared&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dessa forma, esperamos que os seguintes testes sejam executados com sucesso:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Shared&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Specification&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CamposTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Specification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;normal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="nd"&gt;@Shared&lt;/span&gt; &lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;

    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Se alterar o valor do campo, deve ser verificável"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;given:&lt;/span&gt; &lt;span class="s1"&gt;'Valor dos campos foram alterados'&lt;/span&gt;
        &lt;span class="n"&gt;normal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
        &lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

        &lt;span class="nl"&gt;expect:&lt;/span&gt; &lt;span class="s1"&gt;'O novo valor seja observado no resultado'&lt;/span&gt;
        &lt;span class="n"&gt;normal&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
        &lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Sem qualquer alteração, mantem o valor do campo alterado anteriormente"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;given:&lt;/span&gt; &lt;span class="s1"&gt;'Não há novas alterações nos campos'&lt;/span&gt;
        &lt;span class="nl"&gt;expect:&lt;/span&gt; &lt;span class="s1"&gt;'Campo normal deve ter o valor antigo'&lt;/span&gt;
        &lt;span class="n"&gt;normal&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="nl"&gt;and:&lt;/span&gt; &lt;span class="s1"&gt;'Campo shared deve ter o valor definido no método anterior'&lt;/span&gt;
        &lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&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;Outra possibilidade é usar &lt;code&gt;static final fields&lt;/code&gt;. A documentação sugere dar preferência pelo&lt;code&gt;@Shared&lt;/code&gt; e deixar esse caso apenas para constantes por uma questão semântica.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixture Methods
&lt;/h2&gt;

&lt;p&gt;São responsáveis por configurar o ambiente de testes, inicializando e finalizando os testes. São eles:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Equivale ao @BeforeAll/@BeforeClass do JUnit. Roda apenas uma vez // antes que os testes se iniciem.&lt;/span&gt;
&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setupSpec&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;    
&lt;span class="c1"&gt;// Equivale ao @Before do JUnit. Roda antes de cada método.&lt;/span&gt;
&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;    
&lt;span class="c1"&gt;// Equivale ao @After do JUnit. Roda logo após cada método.    &lt;/span&gt;
&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cleanup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;     
&lt;span class="c1"&gt;// Equivale ao @AfterAll/AfterClass do JUnit. Roda uma única vez ao //término do último teste.&lt;/span&gt;
&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cleanupSpec&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;h2&gt;
  
  
  Feature Methods
&lt;/h2&gt;

&lt;p&gt;O coração de tudo! Descrevem a especificação, o comportamento esperado da sua aplicação. São métodos nomeados por frases auto-explicativas e compostos por blocos indicando as fases da especificação:&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/http%3A%2F%2Fspockframework.org%2Fspock%2Fdocs%2F1.3%2Fimages%2FBlocks2Phases.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fspockframework.org%2Fspock%2Fdocs%2F1.3%2Fimages%2FBlocks2Phases.png" alt="Fluxo de fases da especificação. Fonte: [Spock](http://spockframework.org/spock/docs/1.3/spock_primer.html)"&gt;&lt;/a&gt;&lt;/p&gt;
Fluxo de fases da especificação. Fonte: &lt;a href="http://spockframework.org/spock/docs/1.3/spock_primer.html" rel="noopener noreferrer"&gt;Spock&lt;/a&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GIVEN&lt;/strong&gt;: onde você faz a inicialização do teste, isto é, inicializa variáveis. Pode estar implícito, ou seja, não precisa ser declarado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WHEN&lt;/strong&gt;: representa um estímulo ao teste, uma entrada, uma ação externa. Sempre que acontece um estímulo, esperamos então (&lt;em&gt;then&lt;/em&gt;) uma resposta.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;THEN&lt;/strong&gt;: resposta a um estímulo, o que esperar após um bloco &lt;em&gt;when&lt;/em&gt;. De fato, esses blocos ocorrem juntos e pode haver mais de um par when/then no método.&lt;br&gt;
Da mesma forma que &lt;em&gt;expect&lt;/em&gt;, esse bloco sempre trata de resultado de condições. Vamos tratar de condições mais a frente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;EXPECT&lt;/strong&gt;: parecido com o &lt;em&gt;then&lt;/em&gt;, é mais natural para casos onde não é interessante usar um bloco &lt;em&gt;when&lt;/em&gt;. Isso ocorre especialmente em métodos puramente funcionais, isto é, sem efeitos colaterais. &lt;br&gt;
Juntando o estímulo do teste à resposta em uma única expressão, temos uma apresentação mais concisa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLEANUP&lt;/strong&gt;: o local adequado para finalizar o uso de recursos como acesso a arquivos, streams, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WHERE&lt;/strong&gt;: é utilizado para escrever testes parametrizados. Cada conjunto de dados dentro do bloco &lt;em&gt;where&lt;/em&gt; é tratado como um novo teste.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Condições
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Explícitas ou implícitas
&lt;/h3&gt;

&lt;p&gt;Condições ou &lt;em&gt;assertions&lt;/em&gt;, testam a sua aplicação. Elas podem ser implícitas, dentro dos blocos &lt;em&gt;when/then&lt;/em&gt; ou dentro do bloco &lt;em&gt;expect&lt;/em&gt;. Tudo declarado dentro desses blocos compõem uma ou mais condições. Elas também podem ser explícitas, fora desses blocos. Para tanto, usa-se a palavra-chave &lt;code&gt;assert&lt;/code&gt;, ex.: &lt;code&gt;assert stack.empty&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Exceções
&lt;/h3&gt;

&lt;p&gt;Tratam casos em que se espera uma exceção do código testado. Para testar exceções, usam-se os métodos &lt;code&gt;thrown()&lt;/code&gt; e &lt;code&gt;notThrown()&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Specification&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emptyList&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExcecaoTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Specification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Lançar exceção quando tentar tirar um elemento de uma lista vazia"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;given:&lt;/span&gt; &lt;span class="s1"&gt;'Uma lista vazia'&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;lista&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emptyList&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

        &lt;span class="nl"&gt;when:&lt;/span&gt; &lt;span class="s1"&gt;'Tentar remover um elemento desta lista'&lt;/span&gt;
        &lt;span class="n"&gt;lista&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pop&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

        &lt;span class="nl"&gt;then:&lt;/span&gt; &lt;span class="s1"&gt;'Deve lançar exceção do tipo NoSuchElementException'&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thrown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NoSuchElementException&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nl"&gt;and:&lt;/span&gt; &lt;span class="s1"&gt;'Causa deve ser nula'&lt;/span&gt;
        &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cause&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Não lançar exceção quando tentar incluir uma chave nula num mapa"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;given:&lt;/span&gt; &lt;span class="s1"&gt;'Um hashmap'&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;mapa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

        &lt;span class="nl"&gt;when:&lt;/span&gt; &lt;span class="s1"&gt;'Tentar inserir um par chave/valor com chave nula'&lt;/span&gt;
        &lt;span class="n"&gt;mapa&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="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="nl"&gt;then:&lt;/span&gt; &lt;span class="s1"&gt;'Não deve ocorrer qualquer exceção'&lt;/span&gt;
        &lt;span class="n"&gt;noExceptionThrown&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Groovy == equivale a equals em Java e é nullsafe"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;when:&lt;/span&gt; &lt;span class="s1"&gt;'Comparar null com qualquer objeto'&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;isLeiaNula&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"General Leia Organa"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;isHanNulo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Han Solo"&lt;/span&gt;
        &lt;span class="nl"&gt;then:&lt;/span&gt; &lt;span class="s1"&gt;'Deve retornar false e não gerar exceção de null pointer'&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isLeiaNula&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isHanNulo&lt;/span&gt;
        &lt;span class="n"&gt;notThrown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NullPointerException&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;É possível acessar o conteúdo da exceção atribuindo o resultado do método a uma variável, &lt;code&gt;def e = thrown(EmptyStackException)&lt;/code&gt; ou ainda, &lt;code&gt;EmptyStackException e = thrown()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Help Methods
&lt;/h3&gt;

&lt;p&gt;Usando outros frameworks de teste unitário é comum adotarmos métodos utilitários para não duplicar código. No &lt;em&gt;Groovy&lt;/em&gt; não seria diferente. O exemplo a seguir mostra o poder da linguagem.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Specification&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelpMethodsTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Specification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Verificar se email obedece padrão"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;expect:&lt;/span&gt; &lt;span class="s1"&gt;'Meu email fake seja válido!'&lt;/span&gt;
        &lt;span class="s2"&gt;"é um email válido"&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"leandro@leandro.com.br"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"é um email válido"&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".com.br"&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;Para identificar melhor onde está o problema, sugere-se usar o &lt;code&gt;assert&lt;/code&gt; dentro do método utilitário para cada linha condicional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usando o método &lt;code&gt;with&lt;/code&gt; para verificar campos
&lt;/h3&gt;

&lt;p&gt;O &lt;a href="http://docs.groovy-lang.org/docs/next/html/documentation/style-guide.html#_using_code_with_code_and_code_tap_code_for_repeated_operations_on_the_same_bean" rel="noopener noreferrer"&gt;Groovy&lt;/a&gt; oferece uma gama muito grande de syntactic sugars que nos permitem deixar o código muito mais simples. Um deles é o método &lt;code&gt;with&lt;/code&gt; que permite testar as propriedades de um objeto em poucas linhas até que qualquer dessas propriedades seja falsa. Uma alternativa ao &lt;code&gt;with&lt;/code&gt; é o &lt;code&gt;verifyAll&lt;/code&gt; que testa todos os campos sem o curto circuito.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;groovy.transform.ToString&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Shared&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Specification&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Unroll&lt;/span&gt;

&lt;span class="nd"&gt;@Unroll&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WithTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Specification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Shared&lt;/span&gt;
            &lt;span class="n"&gt;mulheresImportantes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
                    &lt;span class="s2"&gt;"Ada Lovelace"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s2"&gt;"Grace Hopper"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s2"&gt;"Margaret Hamilton"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s2"&gt;"Katie Bouman"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s2"&gt;"Barbara Liskov"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;

    &lt;span class="nd"&gt;@ToString&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PessoasImportanteDaTI&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;
        &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sexo&lt;/span&gt;
        &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;descricao&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Verificar se #pessoa.nome é uma mulher importante das ciências da computação"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;verifyAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pessoa&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mulheresImportantes&lt;/span&gt;
            &lt;span class="n"&gt;sexo&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nl"&gt;where:&lt;/span&gt;
        &lt;span class="n"&gt;pessoa&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PessoasImportanteDaTI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s2"&gt;"Ada Lovelace"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;sexo:&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;descricao:&lt;/span&gt; &lt;span class="s2"&gt;"Escreveu o primeiro algoritmo\
                    para ser processado por uma máquina. "&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PessoasImportanteDaTI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s2"&gt;"Grace Hopper"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;sexo:&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;descricao:&lt;/span&gt; &lt;span class="s2"&gt;"Criou uma linguagem que foi a \
                    base para o COBOL."&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PessoasImportanteDaTI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s2"&gt;"Katie Bouman"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;sexo:&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;descricao:&lt;/span&gt; &lt;span class="s2"&gt;"Criou algotimos para processar \
                    a primeira imagem de um buraco negro."&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PessoasImportanteDaTI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s2"&gt;"Barbara Liskov"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;sexo:&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;descricao:&lt;/span&gt; &lt;span class="s2"&gt;"Criou o Princípio da Substituição de Liskov, \
                    foi a primeira mulher a obter um PhD em Ciência da Computação \
                    nos Estados Unidos e inventou o Tipo Abstrato de Dado."&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PessoasImportanteDaTI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s2"&gt;"Margaret Hamilton"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;sexo:&lt;/span&gt; &lt;span class="s1"&gt;'F'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;descricao:&lt;/span&gt; &lt;span class="s2"&gt;"Desenvolveu o programa de voo usado no projeto Apollo 11."&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PessoasImportanteDaTI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s2"&gt;"Dennis Ritchie"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;sexo:&lt;/span&gt; &lt;span class="s1"&gt;'M'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;descricao:&lt;/span&gt; &lt;span class="s2"&gt;"Criou a linguagem de programação C."&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;Esse é o resultado esperado do teste acima utilizando a biblioteca &lt;a href="https://github.com/renatoathaydes/spock-reports" rel="noopener noreferrer"&gt;Spock Report Extension&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Folm28xc5fertmgvsx1n2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Folm28xc5fertmgvsx1n2.png" alt="Avaliando as grandes mulheres das Ciências da Computação"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aqui está nosso intruso! &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%2Fnhw2dfzzx44tqkcoca5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnhw2dfzzx44tqkcoca5k.png" alt="Dennis Ritchie é um grande personagem da computação, mas não luta como uma mulher!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mocking
&lt;/h2&gt;

&lt;p&gt;Um Teste Unitário só pode ser chamado assim se for isolado do mundo externo, isto quer dizer, testa apenas aquela unidade de código mínima e mock as dependências. O Spock oferece meios bastante elegantes para isso.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;groovy.sql.Sql&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;groovy.transform.EqualsAndHashCode&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spock.lang.Specification&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MockTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Specification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@EqualsAndHashCode&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Carta&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
        &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MagicRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Sql&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;

        &lt;span class="nf"&gt;MagicRepository&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"jdbc:h2:mem:"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"org.h2.Driver"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'''
              CREATE TABLE carta (
                id INTEGER PRIMARY KEY AUTO_INCREMENT, 
                nome VARCHAR(64)
              )'''&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;Carta&lt;/span&gt; &lt;span class="nf"&gt;addCarta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt; &lt;span class="s2"&gt;"INSERT INTO carta(nome) VALUES ${nome}"&lt;/span&gt;
            &lt;span class="n"&gt;findByNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;Carta&lt;/span&gt; &lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;mapCarta&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;firstRow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"select * from carta where id = ${id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;Carta&lt;/span&gt; &lt;span class="nf"&gt;findByNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;mapCarta&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;firstRow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"select * from carta where nome = ${nome}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Carta&lt;/span&gt; &lt;span class="nf"&gt;mapCarta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retorno&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Carta&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;tap&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;retorno&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ID&lt;/span&gt;
                &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;retorno&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NOME&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;class&lt;/span&gt; &lt;span class="nc"&gt;MagicService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;MagicRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;

        &lt;span class="n"&gt;Carta&lt;/span&gt; &lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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="kt"&gt;def&lt;/span&gt; &lt;span class="s1"&gt;'Stub permite apenas definir comportamento de métodos'&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;given:&lt;/span&gt; &lt;span class="s1"&gt;'Repository é apenas um stub'&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;carta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Carta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s1"&gt;'Mana Crypt'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;stubRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stub&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MagicRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;carta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tap&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;id&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="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MagicService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;repository:&lt;/span&gt; &lt;span class="n"&gt;stubRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="nl"&gt;expect:&lt;/span&gt; &lt;span class="s1"&gt;'O carta encontrada deve ser a carta do stub'&lt;/span&gt;
        &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;carta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tap&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Spy permite saber quantas interações ocorreram e o retorno do método espiado"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;given:&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;esperada1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Carta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s1"&gt;'Black Lotus'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;esperada2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Carta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s1"&gt;'Mana Crypt'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;spyRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Spy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MagicRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;esperada2&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;spyRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addCarta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Black Lotus"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;spyRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addCarta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Mox Pearl"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MagicService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;repository:&lt;/span&gt; &lt;span class="n"&gt;spyRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="nl"&gt;when:&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;carta1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nl"&gt;then:&lt;/span&gt;
        &lt;span class="n"&gt;carta1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;esperada1&lt;/span&gt;
        &lt;span class="n"&gt;spyRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;esperada1&lt;/span&gt;
        &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;spyRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="nl"&gt;when:&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;carta2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nl"&gt;then:&lt;/span&gt;
        &lt;span class="n"&gt;carta2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;esperada2&lt;/span&gt;
        &lt;span class="n"&gt;spyRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;esperada2&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="s2"&gt;"Mock pode tanto ver a quantidade de interações \
        quanto redefinir comportamento do método"&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;given:&lt;/span&gt; &lt;span class="s1"&gt;'Repositório será chamado três vezes'&lt;/span&gt;

        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;esperada1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Carta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s1"&gt;'Mox Pearl'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;esperada2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Carta&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;nome:&lt;/span&gt; &lt;span class="s1"&gt;'Mox Emerald'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;mockRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MagicRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;esperada1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;esperada2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
            &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;esperada2&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MagicService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;repository:&lt;/span&gt; &lt;span class="n"&gt;mockRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nl"&gt;when:&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;carta1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;carta2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;carta3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nl"&gt;then:&lt;/span&gt;
        &lt;span class="n"&gt;carta1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;esperada1&lt;/span&gt;
        &lt;span class="n"&gt;carta2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;esperada2&lt;/span&gt;
        &lt;span class="n"&gt;carta3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;esperada2&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;O Spock permite usar três categorias de mock:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mock&lt;/strong&gt;: Substitui o comportamento da classe quando ela é chamada e permite verificar como ela é usada. É o mais conhecido e tem foco em definir um “contrato” de como ele deve ser chamado, que deve responder e quantas vezes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Spy&lt;/strong&gt;: Não substitui o comportamento, mas permite verificar quando o método real da classe é chamado, o argumento e os resultados;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stub&lt;/strong&gt;: Apenas substitui comportamento, mas não permite verificar chamadas ao stub e nem testar esse acesso. É uma caixa preta que não pretende ser chamada, mas se for, retorna uma resposta padrão.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Para continuar estudando…
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/leandrostl/spock-test" rel="noopener noreferrer"&gt;Código desse material&lt;/a&gt;: vai que a gente melhora algo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://martinfowler.com/articles/mocksArentStubs.html" rel="noopener noreferrer"&gt;Mocks aren’t stubs&lt;/a&gt;: Excelente texto do tio Bob&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dzone.com/articles/spock-and-testing-restful-api" rel="noopener noreferrer"&gt;Spock and testing RESTful Api&lt;/a&gt;: Como ser um framework de testes sem teste de API RESTful?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/renatoathaydes/spock-reports" rel="noopener noreferrer"&gt;Spock Report Extension&lt;/a&gt;: Uma extensão bastante útil para mostrar para o chefe.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bdd</category>
      <category>tutorial</category>
      <category>testing</category>
      <category>java</category>
    </item>
    <item>
      <title>Validação de regras: evitando blocos de ifs</title>
      <dc:creator>Leandro Lima</dc:creator>
      <pubDate>Fri, 31 Jul 2020 19:29:33 +0000</pubDate>
      <link>https://forem.com/leandrostl/validacao-de-regras-evitando-blocos-de-ifs-96f</link>
      <guid>https://forem.com/leandrostl/validacao-de-regras-evitando-blocos-de-ifs-96f</guid>
      <description>&lt;h2&gt;
  
  
  O Problema 🤯
&lt;/h2&gt;

&lt;p&gt;Lembro de trabalhar em um projeto em que eu tinha que validar vários dados que vinham de uma entrada de usuário e as validações eram regras de negócio complexas. Naquela época eu escrevi um método que possuía uma quantidade grande de &lt;em&gt;if's&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Fiquei bastante contrariado com aquele código. Ele não era escalável, ele desobedecia à ideia de &lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;&lt;em&gt;single responsability&lt;/em&gt;&lt;/a&gt;. Me sentia envergonhado com ele, mas não fui capaz de achar uma solução com o prazo apertado que tinha e ele foi ficando na minha cabeça sem solução. &lt;/p&gt;

&lt;p&gt;Imagine que temos uma esteira onde um pacote de pão de queijo, como bom mineiro, adoro o ouro de Minas, é verificado quanto à sua qualidade e quantidade:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Quantidade de pães de queijo correta&lt;/li&gt;
&lt;li&gt;Peso da embalagem&lt;/li&gt;
&lt;li&gt;Volume de cada pão de queijo&lt;/li&gt;
&lt;li&gt;Peso de cada pão de queijo&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nossa principal entidade é pão de queijo.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.Data&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nd"&gt;@Data&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaoDeQueijo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;circumferencia&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;getVolume&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="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;circumferencia&lt;/span&gt;&lt;span class="o"&gt;/(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="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;Um pacote de pães de queijo nada mais é do que uma lista.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PacotePaoQueijo&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;&amp;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;h2&gt;
  
  
  Solução com vergonha 😞
&lt;/h2&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;class&lt;/span&gt; &lt;span class="nc"&gt;VerificadorPacotePaoQueijoOld&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;QUANTIDADE_PAO_DE_QUEIJO_PACOTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="no"&gt;PESO_PACOTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="no"&gt;MIN_VOLUME_PAO_DE_QUEIJO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="no"&gt;MAX_PAO_DE_QUEIJO_VOLUME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="no"&gt;MIN_PESO_PAO_QUEIJO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="no"&gt;MAX_PESO_PAO_QUEIJO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isPaoDeQueijoValido&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PacotePaoQueijo&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;PacoteDefeituosoException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&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="n"&gt;quantidade&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;QUANTIDADE_PAO_DE_QUEIJO_PACOTE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PacoteDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Quantidade de pães de queijo errada. Esperava %d e "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                            &lt;span class="s"&gt;"encontrou %d."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;QUANTIDADE_PAO_DE_QUEIJO_PACOTE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;pesoPacote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;PaoDeQueijo:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getPeso&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="nl"&gt;Double:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sum&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="n"&gt;pesoPacote&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;PESO_PACOTE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PacoteDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"O peso do pacote de pães de queijo não está correto. "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                            &lt;span class="s"&gt;"Esperava %f g e encontrou %f g."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="no"&gt;PESO_PACOTE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pesoPacote&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;PaoDeQueijo&lt;/span&gt; &lt;span class="n"&gt;paoDeQueijo&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;validarPaoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaoDeQueijoDefeituosoException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PacoteDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Esse pacote possui pães de queijo defeituosos."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validarPaoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PaoDeQueijo&lt;/span&gt; &lt;span class="n"&gt;paoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;PaoDeQueijoDefeituosoException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPeso&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="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;MIN_PESO_PAO_QUEIJO&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MAX_PESO_PAO_QUEIJO&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PaoDeQueijoDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"O pão de queijo encontra-se fora da faixa de peso permitida."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                    &lt;span class="s"&gt;"Esperava entre %f g e %f g e encontrou %f g."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MIN_PESO_PAO_QUEIJO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MAX_PESO_PAO_QUEIJO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;


        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVolume&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="n"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;MIN_VOLUME_PAO_DE_QUEIJO&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MAX_PAO_DE_QUEIJO_VOLUME&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PaoDeQueijoDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pão de queijo com volume errado. Esperava valores entre "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                    &lt;span class="s"&gt;"%f e %f e encontrou %f"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MIN_VOLUME_PAO_DE_QUEIJO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MAX_PAO_DE_QUEIJO_VOLUME&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="o"&gt;));&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;Nessa solução até separamos os métodos para verificar pacote e pão de queijo, usamos exceções adequadas, mas perceba, tratamos dois tipos de dados diferentes e temos inúmeros if's. O que aconteceria se você precisasse adicionar mais validações? Poderíamos validar temperatura, quantidade de queijo, sal, etc. Essa classe iria crescer e ficar monstruosa. Mesmo que separássemos a parte de regras para pão de queijo em uma nova classe ainda sim, seria ruim.&lt;/p&gt;

&lt;p&gt;Imagine quanto é chato testar esse código, um método que valida tanta coisa geraria testes com várias validações. Fica claro que o &lt;em&gt;single responsability principle&lt;/em&gt; não é respeitado.&lt;/p&gt;

&lt;h2&gt;
  
  
  A solução do livramento 🙌
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Log4j&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;EsteiraAvaliacaoPaesDeQueijo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&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;Regra&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PaoDeQueijoDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;regrasPaoDeQueijo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&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;RegraVolumePaoQueijo&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;RegraPesoPaoQueijo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&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;Regra&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PacotePaoQueijo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PacoteDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;regrasPacotePaoQueijo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&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;RegraQuantidadePaesPacote&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;RegraPesoPacote&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;


    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validarPacote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PacotePaoQueijo&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;)&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;regra&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;regrasPacotePaoQueijo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;regra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PacoteDefeituosoException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Defeito no pacote."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaoDeQueijo&lt;/span&gt; &lt;span class="n"&gt;paoDeQueijo&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;)&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;regra&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;regrasPaoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;regra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaoDeQueijoDefeituosoException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Defeito no pão de queijo."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&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;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;Nossas regras implementam uma interface única, mas poderia haver regras para pacote e regras para pão de queijo separadas.&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;Regra&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="no"&gt;E&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;Vamos ver aqui uma das regras, para verificação de peso do pacote.&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;class&lt;/span&gt; &lt;span class="nc"&gt;RegraPesoPacote&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Regra&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PacotePaoQueijo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PacoteDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="no"&gt;PESO_PACOTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PacotePaoQueijo&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;PacoteDefeituosoException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;pesoPacote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;PaoDeQueijo:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getPeso&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.,&lt;/span&gt; &lt;span class="nl"&gt;Double:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sum&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="n"&gt;pesoPacote&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;PESO_PACOTE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PacoteDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"O peso do pacote de pães de queijo não está correto. "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"Esperava %f g e encontrou %f g."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PESO_PACOTE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pesoPacote&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;Todas as regras seguem esse estilo, uma classe simples, com o método validar que lança uma exceção caso ela não seja validada. &lt;br&gt;
Observe como fica auto-contido todo o universo da regra! &lt;/p&gt;
&lt;h2&gt;
  
  
  Plus com injeção Spring
&lt;/h2&gt;

&lt;p&gt;Eu não testei essa funcionalidade com outros injetores de dependências, mas sei que com o Spring funciona bem. &lt;/p&gt;

&lt;p&gt;O Spring consegue de forma simples injetar uma lista com todas as classes que implementam uma interface. Assim, nossa esteira fica ainda mais simples.&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;@AllArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@Log4j&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;EsteiraAvaliacaoPaesDeQueijo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&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;Regra&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PaoDeQueijoDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;regrasPaoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&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;Regra&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PacotePaoQueijo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PacoteDefeituosoException&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;regrasPacotePaoQueijo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validarPacote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PacotePaoQueijo&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;)&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;regra&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;regrasPacotePaoQueijo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;regra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PacoteDefeituosoException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Defeito no pacote."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaoDeQueijo&lt;/span&gt; &lt;span class="n"&gt;paoDeQueijo&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pacote&lt;/span&gt;&lt;span class="o"&gt;)&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;regra&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;regrasPaoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;regra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paoDeQueijo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaoDeQueijoDefeituosoException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Defeito no pão de queijo."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&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;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;Importante observação, não fique tentado a achar que se trata de um &lt;a href="https://pt.wikipedia.org/wiki/Chain_of_Responsibility" rel="noopener noreferrer"&gt;&lt;em&gt;Chain of Responsabilities&lt;/em&gt;&lt;/a&gt;. Esse padrão prevê que uma responsabilidade está ligada à outra e compõem uma ordem definida. Já este não acopla as regras e, desta forma, se torna muito mais escalável. Outro ponto é que podemos criar regras que são reaproveitáveis, bastando que os objetos a validar possuam uma interface em comum.&lt;/p&gt;

&lt;p&gt;O código desse projeto pode ser encontrado &lt;a href="https://github.com/leandrostl/validacao-regras/tree/master" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>designpatterns</category>
      <category>java</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Builder seguro e elegante</title>
      <dc:creator>Leandro Lima</dc:creator>
      <pubDate>Fri, 24 Jul 2020 20:59:58 +0000</pubDate>
      <link>https://forem.com/leandrostl/builder-seguro-e-elegante-cfi</link>
      <guid>https://forem.com/leandrostl/builder-seguro-e-elegante-cfi</guid>
      <description>&lt;p&gt;&lt;a href="https://pt.wikipedia.org/wiki/Builder" rel="noopener noreferrer"&gt;Builder&lt;/a&gt; é um dos padrões de projeto da classe dos criacionais da &lt;a href="https://www.amazon.com.br/Padr%C3%B5es-Projetos-Solu%C3%A7%C3%B5es-Reutiliz%C3%A1veis-Orientados/dp/8573076100/ref=asc_df_8573076100/?tag=googleshopp00-20&amp;amp;linkCode=df0&amp;amp;hvadid=379748659420&amp;amp;hvpos=&amp;amp;hvnetw=g&amp;amp;hvrand=16168119258048787299&amp;amp;hvpone=&amp;amp;hvptwo=&amp;amp;hvqmt=&amp;amp;hvdev=c&amp;amp;hvdvcmdl=&amp;amp;hvlocint=&amp;amp;hvlocphy=1001566&amp;amp;hvtargid=pla-812887614857&amp;amp;psc=1" rel="noopener noreferrer"&gt;bíblia da Gangue dos Quadro&lt;/a&gt;. Esse padrão permite construir objetos complexos passo a passo e um efeito colateral disso é uma construção fluente para os objetos.&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pessoa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"João"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;sobrenome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"das Couve"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma, o que observamos do uso de builder e sua popularização está muito mais ligado à substituição de um construtor com muitos parâmetros por um design mais fluente do que propriamente o a intenção da &lt;a href="https://www.amazon.com.br/Padr%C3%B5es-Projetos-Solu%C3%A7%C3%B5es-Reutiliz%C3%A1veis-Orientados/dp/8573076100/ref=asc_df_8573076100/?tag=googleshopp00-20&amp;amp;linkCode=df0&amp;amp;hvadid=379748659420&amp;amp;hvpos=&amp;amp;hvnetw=g&amp;amp;hvrand=16168119258048787299&amp;amp;hvpone=&amp;amp;hvptwo=&amp;amp;hvqmt=&amp;amp;hvdev=c&amp;amp;hvdvcmdl=&amp;amp;hvlocint=&amp;amp;hvlocphy=1001566&amp;amp;hvtargid=pla-812887614857&amp;amp;psc=1" rel="noopener noreferrer"&gt;GoF&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"...separação da construção de um objeto complexo da sua representação, de forma que o mesmo processo de construção possa criar diferentes representações."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para diferenciar essa inteção do builder padrão, é comum chama-lo de &lt;em&gt;Fluent Interface Builder&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O pattern está disponível nas IDEs para ser auto criado e ficou ainda mais conhecido no mundo Java através do &lt;a href="https://projectlombok.org/features/Builder" rel="noopener noreferrer"&gt;Projeto Lombok&lt;/a&gt; que tirou um grande boilerplate e transformou em uma simples anotação.&lt;/p&gt;

&lt;p&gt;Esse builder costuma ter o seguinte padrão:&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;builder&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;Pessoa&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sobrenome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&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;Pessoa&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;nome&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;sobrenome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&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;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nome&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;sobrenome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sobrenome&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;idade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PessoaBuilder&lt;/span&gt; &lt;span class="nf"&gt;builder&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;new&lt;/span&gt; &lt;span class="nc"&gt;PessoaBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Getters and setters&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PessoaBuilder&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;String&lt;/span&gt; &lt;span class="n"&gt;nome&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;String&lt;/span&gt; &lt;span class="n"&gt;sobrenome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&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;PessoaBuilder&lt;/span&gt; &lt;span class="nf"&gt;nome&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;nome&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;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nome&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="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PessoaBuilder&lt;/span&gt; &lt;span class="nf"&gt;sobrenome&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;sobrenome&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;sobrenome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sobrenome&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="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PessoaBuilder&lt;/span&gt; &lt;span class="nf"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&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;idade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idade&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="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="nf"&gt;build&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;new&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sobrenome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idade&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;Mas sempre me incomodou que o builder, possuindo muitos passos, poderia contribuir para que o desenvolvedor desatento chame o &lt;em&gt;build()&lt;/em&gt; prematuramente, isto é, com o objeto ainda incompleto. Isso só seria percebido em tempo de execução com uma exceção, ou pior, com a tentativa frustrada de acesso àquela propriedade esquecida. &lt;/p&gt;

&lt;p&gt;Quando temos um construtor podemos impor que certos campos sejam &lt;em&gt;final&lt;/em&gt; e isso obriga o desenvolvedor a preencher aqueles parâmetros, mas com o builder padrão, isso não é possível.&lt;/p&gt;

&lt;p&gt;Esse incômodo, felizmente, acabou quando achei o artigo brilhante &lt;a href="https://dev.to/siy/simple-implementation-of-fluent-builder-safe-alternative-to-traditional-builder-3m1d"&gt;Simple Implementation of Fluent Builder - Safe Alternative To Traditional Builder&lt;/a&gt; do &lt;a href="https://dev.to/siy"&gt;Sergiy Yevtushenko&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Esse gênio resolveu o problema e ainda de uma forma extremamente elegante!&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;builder&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;Pessoa&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sobrenome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&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;Pessoa&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;nome&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;sobrenome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&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;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nome&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;sobrenome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sobrenome&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;idade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PessoaBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Stage0&lt;/span&gt; &lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sobrenome&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sobrenome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PessoaBuilder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Stage0&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Stage1&lt;/span&gt; &lt;span class="nf"&gt;nome&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;nome&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Stage1&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Stage2&lt;/span&gt; &lt;span class="nf"&gt;sobrenome&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;sobrenome&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Stage2&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Stage3&lt;/span&gt; &lt;span class="nf"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Stage3&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="nf"&gt;build&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;Aqui, definimos, de forma obrigatória, os parâmetros e a ordem em que eles devem ser preenchidos. Nosso builder é construído com passos representados por interfaces funcionais. Por conveniência, inseri esses passos dentro de uma interface que se comporta aqui como um &lt;em&gt;namespace&lt;/em&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O método builder retorna o primeiro estágio, uma classe que tem apena o método nome;&lt;/li&gt;
&lt;li&gt;Este retorna uma classe que tem também um único método que, sobrenome;&lt;/li&gt;
&lt;li&gt;Sobrenome retorna a Stage3 com o método build(),&lt;/li&gt;
&lt;li&gt;O build cria um objeto Pessoa.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;O builder padrão é excelente quando se deseja dar ao desenvolvedor a flexibilidade de preencher os parâmetros que achar necessário, mantendo valores padrões para aqueles que não preencher. Para uma situação em que certos parâmetros não são opcionais, a solução apresentada é uma alternativa bastante enxuta e elegante.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pt.wikipedia.org/wiki/Builder" rel="noopener noreferrer"&gt;Builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com.br/Padr%C3%B5es-Projetos-Solu%C3%A7%C3%B5es-Reutiliz%C3%A1veis-Orientados/dp/8573076100/ref=asc_df_8573076100/?tag=googleshopp00-20&amp;amp;linkCode=df0&amp;amp;hvadid=379748659420&amp;amp;hvpos=&amp;amp;hvnetw=g&amp;amp;hvrand=16168119258048787299&amp;amp;hvpone=&amp;amp;hvptwo=&amp;amp;hvqmt=&amp;amp;hvdev=c&amp;amp;hvdvcmdl=&amp;amp;hvlocint=&amp;amp;hvlocphy=1001566&amp;amp;hvtargid=pla-812887614857&amp;amp;psc=1" rel="noopener noreferrer"&gt;Padrões de Projetos: Soluções Reutilizáveis de Software Orientados a Objetos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projectlombok.org/features/Builder" rel="noopener noreferrer"&gt;Lombok - Builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/siy/simple-implementation-of-fluent-builder-safe-alternative-to-traditional-builder-3m1d"&gt;Simple Implementation of Fluent Builder safe alternative to traditional builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/siy"&gt;Sergiy Yevtushenko&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>designpatterns</category>
      <category>java</category>
      <category>builder</category>
      <category>fluentapi</category>
    </item>
  </channel>
</rss>
