<?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: Ewerton</title>
    <description>The latest articles on Forem by Ewerton (@ewertoncodes).</description>
    <link>https://forem.com/ewertoncodes</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%2F188253%2F1f90f275-c6bb-4e76-a853-381b32e5c468.jpeg</url>
      <title>Forem: Ewerton</title>
      <link>https://forem.com/ewertoncodes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ewertoncodes"/>
    <language>en</language>
    <item>
      <title>Como eu penso e escrevo meus testes</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Fri, 27 Mar 2026 18:19:51 +0000</pubDate>
      <link>https://forem.com/ewertoncodes/como-eu-penso-e-escrevo-meus-testes-4j26</link>
      <guid>https://forem.com/ewertoncodes/como-eu-penso-e-escrevo-meus-testes-4j26</guid>
      <description>&lt;p&gt;Testes são uma parte fundamental do desenvolvimento de software. Eles nos ajudam a garantir que nosso código funcione como esperado e que possamos fazer alterações sem quebrar funcionalidades existentes.&lt;/p&gt;

&lt;p&gt;Antes de criar uma aplicação, eu gosto de pensar em como vou testá-la. Isso me ajuda a projetar meu código de forma que ele seja mais fácil de testar.&lt;/p&gt;

&lt;p&gt;Piramide de testes é uma forma de organizar os testes em uma aplicação. Ela é dividida em três camadas.&lt;br&gt;
Na base temos os testes unitários, no meio os testes de integração e no topo os testes de ponta a ponta.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8ts8626sx3qkcyp7w5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8ts8626sx3qkcyp7w5w.png" alt=" " width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O próximo conceito de como escrever testes é o TDD (Test-Driven Development). &lt;br&gt;
No TDD, escrevemos o teste antes de escrever o código. O fluxo é o seguinte:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Escreva um teste que falhe.&lt;/li&gt;
&lt;li&gt;Escreva o código mínimo necessário para que o teste passe.&lt;/li&gt;
&lt;li&gt;Refatore o código para que ele fique mais limpo e organizado.&lt;/li&gt;
&lt;li&gt;Repita o processo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Anatomia de um teste. Eu divido em 3 partes, setup, ação e verificação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# setup&lt;/span&gt;
&lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Ewerton"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# ação&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;

&lt;span class="c1"&gt;# verificação&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_persisted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pensando em casos de uso, eu gosto de pensar em como o usuário vai interagir com o sistema. &lt;br&gt;
O BDD (Behavior-Driven Development) é uma forma de escrever testes que foca no comportamento do sistema.&lt;br&gt;
Eu usei bastante na minha carreira uma gem para testes chamada rspec. O rspec é uma biblioteca de testes para Ruby que implementa o BDD. Aqui eu penso em 3 palavras, Given, When e Then.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Given (Dado que): Eu tenho uma calculadora e os números 5 e 10.&lt;/li&gt;
&lt;li&gt;When (Quando): Eu executo a operação de soma.&lt;/li&gt;
&lt;li&gt;Then (Então): O resultado deve ser igual a 15.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"Calculator"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"addition"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:calculator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s2"&gt;"when adding two positive numbers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"returns the sum of the two numbers"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&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="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse exemplo é bem simples, mas ele ilustra bem o conceito de BDD. Isso é um pouco de como penso e como escrevo testes. Mas esses conceitos são um mundo a ser explorado. Não cabe em um único artigo e pretendo escrever mais sobre testes em breve. &lt;/p&gt;

</description>
      <category>ruby</category>
      <category>tests</category>
      <category>rspec</category>
      <category>tdd</category>
    </item>
    <item>
      <title>Compartilhando Comportamentos usando Herança no Ruby</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Tue, 17 Mar 2026 15:04:12 +0000</pubDate>
      <link>https://forem.com/ewertoncodes/compartilhando-comportamentos-usando-heranca-no-ruby-3blf</link>
      <guid>https://forem.com/ewertoncodes/compartilhando-comportamentos-usando-heranca-no-ruby-3blf</guid>
      <description>&lt;p&gt;Um dos pilares da programação orientada a objetos é a herança, que é um conceito que permite que uma classe herde atributos e métodos de outra classe. No Ruby, a herança é feita usando o operador &lt;code&gt;&amp;lt;&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Vamos criar uma classe base simples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Character&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attack&lt;/span&gt;
    &lt;span class="s2"&gt;"Attack"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  O uso básico do &lt;code&gt;super&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;super&lt;/code&gt; é a palavra-chave usada para invocar um método da classe pai a partir de uma classe filha. Veja o exemplo de um &lt;strong&gt;Guerreiro (Warrior)&lt;/strong&gt; que herda de &lt;code&gt;Character&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Warrior&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Character&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attack&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;" with sword"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Warrior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attack&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Attack with sword"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste caso, chamar &lt;code&gt;super&lt;/code&gt; funciona perfeitamente. A classe &lt;code&gt;Warrior&lt;/code&gt; herda os métodos de &lt;code&gt;Character&lt;/code&gt; e sobrescreve o método &lt;code&gt;attack&lt;/code&gt;. A chamada para &lt;code&gt;super&lt;/code&gt; executa o &lt;code&gt;attack&lt;/code&gt; da classe pai.&lt;/p&gt;

&lt;h3&gt;
  
  
  A diferença entre &lt;code&gt;super&lt;/code&gt; e &lt;code&gt;super()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A confusão começa quando o método da classe filha exige argumentos que a classe pai não espera (ou vice-versa).&lt;/p&gt;

&lt;p&gt;Por padrão, &lt;strong&gt;chamar apenas &lt;code&gt;super&lt;/code&gt;&lt;/strong&gt; invoca o método da classe pai repassando de forma implícita &lt;strong&gt;todos os mesmos argumentos&lt;/strong&gt; que foram entregues ao método da classe filha. &lt;/p&gt;

&lt;p&gt;Se tentarmos criar um &lt;strong&gt;Mago (Mage)&lt;/strong&gt; cujo ataque recebe o nome de uma magia (&lt;code&gt;spell&lt;/code&gt;), o uso apenas de &lt;code&gt;super&lt;/code&gt; causará um erro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Character&lt;/span&gt;
  &lt;span class="c1"&gt;# O método filho espera 1 argumento (spell)&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt; &lt;span class="c1"&gt;# Isso automaticamente tentará passar o 'spell' para o método pai!&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Mage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Fireball"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "ArgumentError: wrong number of arguments (given 1, expected 0)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O erro &lt;code&gt;ArgumentError&lt;/code&gt; ocorre porque o argumento &lt;code&gt;spell&lt;/code&gt; (no caso, &lt;code&gt;"Fireball"&lt;/code&gt;) foi repassado automaticamente por debaixo dos panos para o método &lt;code&gt;Character#attack&lt;/code&gt;, mas a classe &lt;code&gt;Character&lt;/code&gt; estava esperando &lt;strong&gt;zero argumentos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para resolver isso, precisamos usar &lt;strong&gt;&lt;code&gt;super()&lt;/code&gt;&lt;/strong&gt; com os parênteses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Character&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;" with spell &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;spell&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Mage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Fireball"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; "Attack with spell Fireball"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Resumo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;super&lt;/code&gt;&lt;/strong&gt;: Invoca o método da classe pai repassando exatamente os &lt;strong&gt;mesmos argumentos&lt;/strong&gt; que o método atual recebeu.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;super()&lt;/code&gt;&lt;/strong&gt;: Invoca o método da classe pai explicitamente &lt;strong&gt;sem nenhum argumento&lt;/strong&gt;, não importa quantos argumentos o método atual tenha recebido.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como sempre, ser explícito no seu código é uma boa prática e evita comportamentos inesperados ao sobrescrever métodos!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>backend</category>
      <category>oop</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Otimizando consultas no PostgreSQL Com Gin Index</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Fri, 27 Feb 2026 19:11:44 +0000</pubDate>
      <link>https://forem.com/ewertoncodes/jsonb-e-gin-index-otimizando-consultas-no-postgresql-3n0p</link>
      <guid>https://forem.com/ewertoncodes/jsonb-e-gin-index-otimizando-consultas-no-postgresql-3n0p</guid>
      <description>&lt;p&gt;O PostgreSQL é um dos sgbds que mais usei durante minha carreira. Ele é robusto, confiável e possui uma série de recursos avançados que o tornam uma escolha popular para muitos desenvolvedores. Um desses recursos é o suporte a tipos de dados JSON e JSONB, que permitem armazenar e consultar dados semi-estruturados de forma eficiente. Neste post, vamos explorar como usar o tipo JSONB em conjunto com o Gin Index para otimizar consultas no PostgreSQL.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é JSONB?
&lt;/h2&gt;

&lt;p&gt;O JSONB é uma versão binária do tipo de dados JSON no PostgreSQL. Ele armazena os dados em um formato otimizado para consultas, o que o torna mais rápido do que o tipo JSON tradicional. O JSONB suporta operações de indexação, o que significa que você pode criar índices para acelerar as consultas em campos específicos dentro do JSONB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando um índice Gin para JSONB
&lt;/h2&gt;

&lt;p&gt;O índice Gin (Generalized Inverted Index) é uma estrutura de dados que permite indexar valores dentro de um campo JSONB. Ele é especialmente útil para consultas que filtram por atributos específicos dentro do JSONB, como no exemplo abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 1. Criação da Tabela&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- 2. Inserção de Dados&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="s1"&gt;'Card '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;generate_series&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;jsonb_build_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Creature'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;-- Subtipo com poucas variações para aumentar a amostragem&lt;/span&gt;
        &lt;span class="s1"&gt;'subtype'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Dragon'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Goblin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Human'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Elf'&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="n"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="s1"&gt;'stats'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonb_build_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'power'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="s1"&gt;'toughness'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="c1"&gt;-- Habilidade rara: apenas 'Phasing' será fácil de filtrar&lt;/span&gt;
        &lt;span class="s1"&gt;'abilities'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;CASE&lt;/span&gt; 
            &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&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="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;jsonb_build_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Phasing'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;jsonb_build_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Flying'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;END&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;CARDS&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&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;name&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;
&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="c1"&gt;---+---------+----------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="o"&gt;//&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Card&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"Creature"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"stats"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"power"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"toughness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nv"&gt;"subtype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"Goblin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"abilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;"Flying"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;span class="o"&gt;//&lt;/span&gt;  &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Card&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"Creature"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"stats"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"power"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"toughness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nv"&gt;"subtype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"Elf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"abilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;"Flying"&lt;/span&gt;&lt;span class="p"&gt;]}&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="n"&gt;Card&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"Creature"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"stats"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"power"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"toughness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nv"&gt;"subtype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"Human"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"abilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;"Flying"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;

&lt;span class="c1"&gt;-- Atualiza as estatísticas para o Planejador de Consultas&lt;/span&gt;
&lt;span class="k"&gt;ANALYZE&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos analizar o desempenho das consultas sem o índice e depois com o índice Gin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Consulta sem índice&lt;/span&gt;
&lt;span class="k"&gt;EXPLAIN&lt;/span&gt; &lt;span class="k"&gt;ANALYZE&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="o"&gt;@&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'{"type": "Creature", "subtype": "Dragon"}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Seq Scan on cards  (cost=0.00..36891.00 rows=179403 width=163) (actual time=0.037..944.492 rows=250022 loops=1)"&lt;/span&gt;
&lt;span class="s2"&gt;"  Filter: (attributes @&amp;gt; '{""type"": ""Creature"", ""subtype"": ""Dragon""}'::jsonb)"&lt;/span&gt;
&lt;span class="s2"&gt;"  Rows Removed by Filter: 749978"&lt;/span&gt;
&lt;span class="s2"&gt;"Planning Time: 0.303 ms"&lt;/span&gt;
&lt;span class="s2"&gt;"Execution Time: 1441.434 ms"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veja que temos um scan sequencial na tabela, o que pode ser muito lento em tabelas grandes. Veja o Rows Removed by Filter, que indica que o PostgreSQL teve que ler todas as linhas da tabela para encontrar as correspondências. &lt;/p&gt;

&lt;p&gt;Vamos criar o índice Gin e analisar a consulta novamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Criando o índice Gin&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_cards_attributes&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Consulta com índice&lt;/span&gt;
&lt;span class="k"&gt;EXPLAIN&lt;/span&gt; &lt;span class="k"&gt;ANALYZE&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="o"&gt;@&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'{"type": "Creature", "subtype": "Dragon"}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Bitmap Heap Scan on cards  (cost=2044.35..28677.89 rows=179403 width=163) (actual time=96.083..777.979 rows=250022 loops=1)"&lt;/span&gt;
&lt;span class="s2"&gt;"  Recheck Cond: (attributes @&amp;gt; '{""type"": ""Creature"", ""subtype"": ""Dragon""}'::jsonb)"&lt;/span&gt;
&lt;span class="s2"&gt;"  Heap Blocks: exact=24391"&lt;/span&gt;
&lt;span class="s2"&gt;"  -&amp;gt;  Bitmap Index Scan on idx_cards_attributes  (cost=0.00..1999.50 rows=179403 width=0) (actual time=92.507..92.509 rows=250022 loops=1)"&lt;/span&gt;
&lt;span class="s2"&gt;"        Index Cond: (attributes @&amp;gt; '{""type"": ""Creature"", ""subtype"": ""Dragon""}'::jsonb)"&lt;/span&gt;
&lt;span class="s2"&gt;"Planning Time: 0.388 ms"&lt;/span&gt;
&lt;span class="s2"&gt;"Execution Time: 1197.012 ms"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora temos um Bitmap Heap Scan, que é muito mais eficiente do que o Seq Scan. Não temos mais o Rows Removed by Filter, pois o índice Gin já filtrou as linhas relevantes, resultando em uma execução muito mais rápida da consulta. A diferença no tempo de execução é significativa, mostrando a importância de usar índices adequados para otimizar consultas em campos JSONB. &lt;/p&gt;

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

&lt;p&gt;O uso do tipo JSONB em conjunto com o índice Gin pode melhorar significativamente o desempenho das consultas em campos JSONB no PostgreSQL. Ao criar um índice Gin, as consultas que filtram por atributos específicos dentro do JSONB podem ser executadas muito mais rapidamente, especialmente em tabelas com um grande volume de dados. Se você estiver trabalhando com dados semi-estruturados, considere usar JSONB e índices Gin para otimizar suas consultas e melhorar a performance do seu banco de dados.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>backend</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>O problema N+1</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Mon, 23 Feb 2026 18:04:11 +0000</pubDate>
      <link>https://forem.com/ewertoncodes/o-problema-n1-um-vilao-na-performance-do-backend-3co4</link>
      <guid>https://forem.com/ewertoncodes/o-problema-n1-um-vilao-na-performance-do-backend-3co4</guid>
      <description>&lt;p&gt;Performance é uma das minhas preocupações quando estou desenvolvendo uma aplicação. E um dos problemas mais conhecidos relacionado a performance é o problema N+1. Ele acontece quando temos uma consulta que retorna N registros, e para cada um desses registros, fazemos uma nova consulta para buscar informações relacionadas.&lt;/p&gt;

&lt;p&gt;Por exemplo, imagine que temos um sistema de blog, onde temos uma tabela de posts e uma tabela de comentários. Se quisermos buscar todos os posts e seus comentários, podemos fazer uma consulta para buscar os posts, e para cada post, fazer uma nova consulta para buscar os comentários relacionados. Isso pode resultar em N+1 consultas, onde N é o número de posts.&lt;/p&gt;

&lt;p&gt;Imagine que temos 100 posts, isso significa que teremos 1 consulta para buscar os posts e 100 consultas para buscar os comentários, totalizando 101 consultas. Isso pode ser um grande problema de performance, especialmente se o número de posts for muito grande.&lt;/p&gt;

&lt;p&gt;Exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- 1 consulta para buscar os posts&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- 1 consulta para cada post&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos resolver esse problema com o IN, fazendo uma única consulta para buscar os comentários relacionados a todos os posts de uma vez.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- 1 consulta para buscar os posts&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;-- 1 consulta para buscar os comentários relacionados a todos os posts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma, reduzimos o número de consultas de N+1 para apenas 2, melhorando significativamente a performance da aplicação.&lt;/p&gt;

&lt;p&gt;No Rails, por exemplo, podemos usar o método &lt;code&gt;includes&lt;/code&gt; para evitar o problema N+1. Ele faz um eager loading dos registros relacionados, evitando consultas adicionais para cada registro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que o include faz por debaixo dos panos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- 1 consulta para buscar os posts&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;--&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uma ferramenta que usso para indentificar o problema N+1 é o Bullet, uma gem para Rails que detecta consultas N+1 e outras consultas ineficientes, alertando o desenvolvedor para que ele possa corrigir o problema. &lt;/p&gt;

&lt;p&gt;Em resumo, o problema N+1 é um problema de performance no backend. Mas que pode ser evitado com boas práticas de desenvolvimento e ferramentas de detecção. &lt;/p&gt;

</description>
      <category>sql</category>
      <category>backend</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Entendendo o JSON Web Token (JWT)</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Wed, 24 Dec 2025 20:48:12 +0000</pubDate>
      <link>https://forem.com/ewertoncodes/entendendo-o-json-web-token-jwt-1b38</link>
      <guid>https://forem.com/ewertoncodes/entendendo-o-json-web-token-jwt-1b38</guid>
      <description>&lt;p&gt;Em algum momento, ao criar uma aplicação web, precisamos desenvolver uma solução de autenticação para o sistema. Existem várias estratégias para isso, como autenticação por senha,tokens, OAuth, entre outras.&lt;/p&gt;

&lt;p&gt;Nesse post, vou falar apenas sobre o JWT (JSON Web Token), uma abordagem bastante utilizada no desenvolvimento de APIs.&lt;/p&gt;

&lt;p&gt;O JWT é um padrão aberto usado para transmitir informações de forma compacta e segura entre partes usando JSON. Uma de suas características é ser stateless, ou seja, o servidor não precisa armazenar nenhuma informação sobre a sessão do usuário. Todas as informações nescessárias estão contidas no próprio token.&lt;/p&gt;

&lt;p&gt;Essa abordagem é especialmente útil em aplicações onde o backend e o frontend estão separados, como em aplicações mobile e SPAs (Single Page Applications).&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomia do JWT
&lt;/h2&gt;

&lt;p&gt;O JWT é composto por três partes, header, payload e assinatura separados por um ponto (.).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxxxx.yyyyy.zzzzz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Header
&lt;/h3&gt;

&lt;p&gt;O Header tem duas partes. O tipo do token, que é jwt e o algoritimo de assinatura utilizado. Tais como HMAC SHA256 ou RSA. &lt;/p&gt;

&lt;p&gt;Exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HS256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida esse Json é codificado para Base64Url para formar a primeira parte do JWT.&lt;/p&gt;

&lt;h3&gt;
  
  
  Payload
&lt;/h3&gt;

&lt;p&gt;A segunda parte do jwt é o payload, um objeto json com as informações da entidade tratada, geralmente é um user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1234567890"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Signature
&lt;/h3&gt;

&lt;p&gt;A terceira parte do jwt é a assinatura.  Ela é formada pelo header  mais o payload  encodados em Base64Url e um secret. A assinatura é a parte mais importante  do jwt pois é ela que garante  a integridade do nosso token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;HMACSHA256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;base64UrlEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="nf"&gt;base64UrlEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Colocando tudo junto o jwt ficaria assim:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Como validamos a Assinatura?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyghfroxzzcx2svxnjjlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyghfroxzzcx2svxnjjlh.png" alt=" " width="589" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando o servidor recebe o token, ele inicia um processo de verificação para garantir que aquelas informações são legítimas. Em vez de tentar "descriptografar" a assinatura, o servidor opta por &lt;strong&gt;reconstruí-la&lt;/strong&gt;. Ele separa o Header e o Payload enviados pelo usuário e, utilizando a sua própria &lt;strong&gt;Secret&lt;/strong&gt; (chave secreta) guardada no ambiente seguro do backend, aplica novamente o algoritmo de hash.&lt;/p&gt;

&lt;p&gt;O resultado desse cálculo gera uma nova assinatura que é então comparada com a assinatura que veio originalmente no token. Se ambas forem exatamente iguais, o servidor tem a prova matemática de que o token é íntegro e pode confiar nos dados contidos ali.&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;novaAssinatura&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;headerSent&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;payloadSent&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sua_secret_aqui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;novaAssinatura&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;signatureSent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// O token é íntegro e válido!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se uma pessoa mal-intencionada interceptar um token JWT e tentar alterar o role no payload — por exemplo, mudando de user para admin — qualquer modificação em um único caractere fará com que a assinatura original deixe de ser válida, e o token será rejeitado pelo servidor.&lt;/p&gt;

&lt;p&gt;Para que o servidor aceitasse essa alteração, o atacante precisaria gerar uma nova assinatura que batesse com o novo conteúdo. No entanto, como a assinatura depende obrigatoriamente da Secret para ser gerada, e essa chave só o servidor possui, o invasor não consegue concluir o ataque. Sem a chave secreta, qualquer tentativa de alteração resulta em uma assinatura inválida, e o sistema bloqueia o acesso imediatamente.&lt;/p&gt;

&lt;p&gt;O JWT é uma ferramenta poderosa para a autenticação , especialmente por ser stateless. Isso permite que sua aplicação escale facilmente, já que o servidor não precisa consultar um banco de dados de sessões a cada requisição.&lt;/p&gt;

&lt;p&gt;No entanto, lembre-se o JWT protege a integridade dos dados, mas não a sua privacidade (já que o payload é visível). Portanto, mantenha sua Secret bem guardada, nunca armazene informações sensíveis como senhas dentro do token, crie uma secret que não seja fácil de ser quebrada com brute force. Com esses cuidados, o JWT se torna uma solução robusta e eficiente para o controle de acesso da sua API.&lt;/p&gt;

</description>
      <category>jwt</category>
      <category>backend</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Blocos, Procs e Lambdas no Ruby</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Wed, 04 Jun 2025 21:45:42 +0000</pubDate>
      <link>https://forem.com/ewertoncodes/blocos-procs-e-lambdas-no-ruby-22n3</link>
      <guid>https://forem.com/ewertoncodes/blocos-procs-e-lambdas-no-ruby-22n3</guid>
      <description>&lt;p&gt;Ruby é famoso por sua sintaxe elegante e recursos poderosos, entre eles os &lt;strong&gt;Blocos&lt;/strong&gt;, &lt;strong&gt;Procs&lt;/strong&gt; e &lt;strong&gt;Lambdas&lt;/strong&gt;. Se você está começando com Ruby ou quer reforçar o entendimento, este post vai ajudar a esclarecer o que são esses recursos, como funcionam, e quando usá-las.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blocos
&lt;/h2&gt;

&lt;p&gt;Um &lt;strong&gt;bloco&lt;/strong&gt; é um pedaço de código que pode ser passado para um método. Um exemplo bastante comum é seu uso em iterações, como no método &lt;code&gt;each&lt;/code&gt;. Podemos usar blocos tanto inline, com os caracteres &lt;code&gt;{}&lt;/code&gt;, quanto em múltiplas linhas, com &lt;code&gt;do .. end&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Procs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Procs&lt;/strong&gt; são objetos que encapsulam blocos de código. Eles são flexíveis quanto à passagem de argumentos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Se passarmos mais argumentos do que o esperado, os extras são ignorados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se não passarmos o argumento esperado, a execução continua normalmente.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'my proc'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# ou proc {puts 'my proc'}&lt;/span&gt;
&lt;span class="n"&gt;my_proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;

&lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;


&lt;span class="n"&gt;other_proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"x is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;other_proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"x is 2"&lt;/span&gt;
&lt;span class="n"&gt;other_proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"x is "&lt;/span&gt;

&lt;span class="n"&gt;other_proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"x is 5"&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lambdas
&lt;/h2&gt;

&lt;p&gt;Se nenhum argumento for passado, um erro será exibido.&lt;br&gt;
&lt;strong&gt;Lambdas&lt;/strong&gt; são muito parecidas com Procs, mas são &lt;strong&gt;estritas&lt;/strong&gt; em relação aos argumentos. Se você não passar o número exato de argumentos, um erro será gerado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"x is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;my_lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

 &lt;span class="sb"&gt;`block in &amp;lt;top (required)&amp;gt;': wrong number of arguments (given 0, expected 1) (ArgumentError)`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Em resumo, blocos, procs e lambdas oferecem formas poderosas e flexíveis de lidar com trechos de código em Ruby. Os blocos são ideais para usos rápidos, como em iterações, enquanto procs permitem reutilizar lógica de forma mais solta, sem tanta preocupação com os argumentos. Já as lambdas se comportam de maneira mais próxima às funções tradicionais, garantindo que os parâmetros sejam respeitados com rigor.&lt;/p&gt;

&lt;p&gt;Entender essas diferenças ajuda não só a escrever um código mais limpo e expressivo, mas também a fazer escolhas mais conscientes em projetos reais. Com o tempo e a prática, você vai perceber que esses conceitos são fundamentais para aproveitar todo o potencial da linguagem Ruby.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>backend</category>
    </item>
    <item>
      <title>Como os Sites Evoluíram</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Wed, 05 Mar 2025 19:10:12 +0000</pubDate>
      <link>https://forem.com/ewertoncodes/como-os-sites-evoluiram-ajax-ssg-spa-e-ssr-a7</link>
      <guid>https://forem.com/ewertoncodes/como-os-sites-evoluiram-ajax-ssg-spa-e-ssr-a7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1wvmr8h29srm1v30prh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1wvmr8h29srm1v30prh.jpg" alt=" " width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este é o meu primeiro post neste blog, e para construí-lo estou usando o &lt;strong&gt;Jekyll&lt;/strong&gt;, um gerador de sites estáticos (SSG). Mas, afinal, o que significa um SSG? 🤔&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;SSG (Static Site Generator)&lt;/strong&gt; é uma abordagem onde todas as páginas do site são geradas de forma estática no momento da build, antes mesmo de um usuário acessá-las. Isso significa que, ao invés de processar cada requisição no servidor, o site já está pronto e é entregue como arquivos HTML estáticos. O resultado? Um carregamento muito mais rápido, menor consumo de recursos no servidor .&lt;/p&gt;

&lt;p&gt;Mas os sites sempre funcionaram dessa forma? Não! A forma como servimos conteúdo na web evoluiu bastante ao longo do tempo. Antes das abordagens modernas como SPA (Single Page Application) e SSR (Server-Side Rendering), os sites eram renderizados de maneira muito diferente.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Início da Web com  Sites Tradicionais e o Surgimento do AJAX
&lt;/h2&gt;

&lt;p&gt;No começo da web, a maioria dos sites funcionava com uma abordagem clássica: cada clique em um link ou envio de formulário resultava no carregamento de uma nova página pelo servidor. Isso era simples, mas tornava a navegação lenta e pouco interativa.&lt;/p&gt;

&lt;p&gt;A grande revolução veio com o &lt;strong&gt;&lt;em&gt;AJAX (Asynchronous JavaScript and XML)&lt;/em&gt;&lt;/strong&gt;. Com essa técnica, os sites puderam buscar e atualizar informações sem precisar recarregar a página inteira. Isso trouxe um nível de interatividade antes impensável.&lt;/p&gt;

&lt;p&gt;Um Exemplo famoso que popularizarou o AJAX foi o Gmail. Nele você conseguia visualizar e enviar emails sem precisar atualizar a página.&lt;/p&gt;

&lt;p&gt;O AJAX abriu caminho para uma experiência mais dinâmica, mas ainda exigia muitos cuidados no gerenciamento das requisições. Isso levou à evolução para algo ainda mais avançado: as Single Page Applications (SPAs).&lt;/p&gt;

&lt;h2&gt;
  
  
  O Próximo Passo na Evolução com SPAs
&lt;/h2&gt;

&lt;p&gt;As &lt;strong&gt;Single Page Applications (SPAs)&lt;/strong&gt; levaram a ideia do AJAX ainda mais longe. Em vez de carregar páginas inteiras, elas carregam apenas uma única página inicial e usam JavaScript para atualizar o conteúdo dinamicamente conforme o usuário navega.&lt;/p&gt;

&lt;p&gt;Isso tornou a experiência muito mais fluida e interativa, já que não há recarregamento completo da página. Frameworks como React, Vue e Angular popularizaram esse modelo, permitindo que desenvolvedores criassem aplicações altamente dinâmicas.&lt;/p&gt;

&lt;p&gt;OK. Mas como funciona uma SPA?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O usuário acessa a aplicação e o navegador baixa um único arquivo HTML junto com os scripts JavaScript e CSS.&lt;/li&gt;
&lt;li&gt;O JavaScript da página solicita dados do servidor via API (normalmente em JSON).&lt;/li&gt;
&lt;li&gt;A aplicação atualiza dinamicamente o conteúdo exibido, sem precisar recarregar a página inteira.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb3l268i2jy8oaxtmku9u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb3l268i2jy8oaxtmku9u.png" alt="image" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo real&lt;/strong&gt;: Quando você navega pelo Gmail, o conteúdo dos e-mails muda sem que a página toda precise ser recarregada. Isso acontece porque o frontend faz chamadas assíncronas para buscar apenas os dados necessários.&lt;/p&gt;

&lt;p&gt;Vantagens das SPAs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navegação rápida após o primeiro carregamento.&lt;/li&gt;
&lt;li&gt;Melhor experiência do usuário, sem recarregamentos constantes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Desvantagens das SPAs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SEO mais difícil, já que o conteúdo é carregado via JavaScript.&lt;/li&gt;
&lt;li&gt;Tempo de carregamento inicial pode ser maior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  O Retorno do SSR
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;Server-Side Rendering (SSR)&lt;/strong&gt; resolve algumas das limitações das SPAs ao renderizar as páginas no servidor antes de enviá-las ao navegador. Isso melhora o tempo de carregamento e, principalmente, o SEO, já que os motores de busca conseguem indexar melhor o conteúdo já renderizado.&lt;/p&gt;

&lt;p&gt;Frameworks modernos como Next.js trouxeram o melhor dos dois mundos, permitindo combinar SSR e SPA dentro do mesmo projeto.&lt;/p&gt;

&lt;p&gt;Diferente das SPAs, que carregam um HTML básico e preenchem o conteúdo via JavaScript, o Server-Side Rendering (SSR) gera a página no servidor antes de enviá-la ao navegador. Assim, o usuário recebe um HTML pronto, sem depender do carregamento do JavaScript para visualizar o conteúdo.&lt;/p&gt;

&lt;p&gt;Como funciona o SSR?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1me5cgt89uwyeqccrv8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1me5cgt89uwyeqccrv8z.png" alt="image" width="556" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;O usuário acessa a aplicação e o navegador faz uma requisição ao servidor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O servidor busca os dados (ex.: do banco de dados) e gera um HTML pronto.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Esse HTML é enviado ao navegador e exibido imediatamente.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Exemplo no Rails:&lt;/strong&gt; Em um app Rails tradicional com ERB Views, cada requisição a uma rota (/posts/1) faz o servidor buscar o post no banco e renderizar a view (show.html.erb) antes de enviá-la ao navegador. Isso garante que o HTML já chegue pronto ao usuário .&lt;/p&gt;

&lt;p&gt;Por que o SSR é útil? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SEO muito melhor, pois o conteúdo chega pronto para os motores de busca.&lt;/li&gt;
&lt;li&gt;Primeiro carregamento mais rápido.
Por outro lado, o SSR pode aumentar a carga no servidor e exigir um backend mais robusto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com o tempo, diferentes abordagens surgiram para melhorar a forma como servimos conteúdo na web. O AJAX trouxe interatividade, as SPAs transformaram a navegação, e o SSG e SSR equilibraram performance e SEO. Hoje, a escolha da abordagem ideal depende das necessidades de cada projeto e das prioridades do desenvolvedor.&lt;/p&gt;

</description>
      <category>jekyll</category>
      <category>ruby</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
