<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ewerton</title>
    <description>The latest articles on DEV Community by Ewerton (@ewertoncodes).</description>
    <link>https://dev.to/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>DEV Community: Ewerton</title>
      <link>https://dev.to/ewertoncodes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ewertoncodes"/>
    <language>en</language>
    <item>
      <title>O que é ACID?</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Sat, 09 May 2026 12:12:59 +0000</pubDate>
      <link>https://dev.to/ewertoncodes/o-que-e-acid-3e23</link>
      <guid>https://dev.to/ewertoncodes/o-que-e-acid-3e23</guid>
      <description>&lt;h1&gt;
  
  
  O que é ACID?
&lt;/h1&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%2F731gn6tokvcxt930lt6s.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%2F731gn6tokvcxt930lt6s.jpg" alt="alt text" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine um sistema de compra de ingressos, onde você precisa comprar um ingresso para um show. Você clica em "Comprar", o sistema verifica se tem ingressos disponíveis, reserva um para você, debita o valor do seu cartão de crédito e gera o ingresso. Agora imagine que, no meio desse processo, o sistema falha. O que acontece com o seu ingresso? E com o seu dinheiro?&lt;/p&gt;

&lt;p&gt;Para garantir que isso não aconteça, os bancos de dados relacionais implementam o ACID, que é um conjunto de propriedades que garantem que as transações sejam processadas de forma confiável.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomicidade
&lt;/h2&gt;

&lt;p&gt;Na &lt;strong&gt;Atomicidade&lt;/strong&gt; uma transação ou é executada por completo ou não é executada. Não existe meio termo. No nosso exemplo, se o sistema falhar no meio do processo, o dinheiro não será debitado do cartão e o ingresso não será gerado. A transação será revertida por completo.&lt;/p&gt;

&lt;p&gt;O exemplo clássico é uma transferência entre duas contas, onde o dinheiro sai de uma conta e entra na outra.&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="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;david&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withdrawal&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="n"&gt;maria&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deposit&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse exemplo só levará dinheiro de David e dará para Maria se nem withdrawal nem deposit levantarem uma exceção. As exceções forçarão um ROLLBACK que retorna o banco de dados ao estado anterior ao início da transação.&lt;/p&gt;

&lt;p&gt;Mas, se nem withdrawal nem deposit levantarem uma exceção, então a transação será concluída com sucesso. Ou seja, o dinheiro sairá da conta de David e entrará na conta de Maria.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistência
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Consistência&lt;/strong&gt; garante que a transação leve o banco de dados de um estado &lt;br&gt;
válido para outro estado válido. Ou seja, se uma transação não for concluída com sucesso, o banco de dados não será alterado.&lt;/p&gt;

&lt;p&gt;No exemplo dos ingressos, isso significa que não é possível comprar um ingresso com uma quantidade negativa ou com dados obrigatórios em branco. O banco rejeita qualquer operação que violaria suas regras.&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;ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;
&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="ss"&gt;:nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;# PG::NotNullViolation: ERROR:  null value in column "id" of relation "tickets" &lt;/span&gt;
&lt;span class="c1"&gt;# violates not-null constraint (ActiveRecord::NotNullViolation)&lt;/span&gt;
&lt;span class="c1"&gt;# DETAIL:  Failing row contains (null, 2026-04-29 06:01:26.693314, 173335, &lt;/span&gt;
&lt;span class="c1"&gt;# 2026-05-06 19:20:28.89082, 90, 5).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O banco recusa a operação e permanece exatamente como estava, nenhum estado inválido é persistido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Isolamento
&lt;/h2&gt;

&lt;p&gt;No &lt;strong&gt;Isolamento&lt;/strong&gt; é garantido que transações não interfiram umas nas outras. Vamos voltar ao exemplo dos ingressos. Maria e João estão comprando o último ingresso disponível.&lt;br&gt;
Se o isolamento não estiver ativo, João pode ver que há um ingresso disponível e iniciar a compra também. Nesse caso, ambos podem comprar o ingresso, o que não deveria acontecer. Para evitar isso, o isolamento garante que as transações não interfiram umas nas outras. A compra de Maria deve ser concluída antes que a de João possa ser iniciada.&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;# app/services/ticket_purchase_service.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketPurchaseService&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketUnavailableError&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;StandardError&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;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;purchase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;buyer_name&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
    &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;isolation: :serializable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="c1"&gt;# WITH LOCK garante que apenas uma transação por vez acesse esse registro&lt;/span&gt;
      &lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"FOR UPDATE"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;TicketUnavailableError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Ingresso não disponível!"&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;available?&lt;/span&gt;

      &lt;span class="c1"&gt;# Simula o tempo de processamento (onde a corrida aconteceria sem isolamento)&lt;/span&gt;
      &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;available: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;owner_name: &lt;/span&gt;&lt;span class="n"&gt;buyer_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"[&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;buyer_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] ✅ Compra realizada com sucesso!"&lt;/span&gt;
      &lt;span class="n"&gt;ticket&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;TicketUnavailableError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"[&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;buyer_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] ❌ &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="kp"&gt;nil&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;Demonstração do problema SEM isolamento (race condition)&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;def&lt;/span&gt; &lt;span class="nf"&gt;demo_sem_isolamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;=== SEM ISOLAMENTO ==="&lt;/span&gt;

  &lt;span class="c1"&gt;# Maria e João leem ao mesmo tempo que o ingresso está disponível&lt;/span&gt;
  &lt;span class="n"&gt;thread_maria&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# simula processamento&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;available?&lt;/span&gt;
      &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;available: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;owner_name: &lt;/span&gt;&lt;span class="s2"&gt;"Maria"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"[Maria] ✅ Compra realizada! (mas João também pode comprar)"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;thread_joao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# lê o mesmo estado "disponível"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;available?&lt;/span&gt;
      &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;available: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;owner_name: &lt;/span&gt;&lt;span class="s2"&gt;"João"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"[João] ✅ Compra realizada! (ingresso duplicado 💥)"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;thread_maria&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread_joao&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;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:join&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isolamento via FOR UPDATE + transaction serializable&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;def&lt;/span&gt; &lt;span class="nf"&gt;demo_com_isolamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;=== COM ISOLAMENTO ==="&lt;/span&gt;

  &lt;span class="n"&gt;thread_maria&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;TicketPurchaseService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;purchase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;ticket_id: &lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;buyer_name: &lt;/span&gt;&lt;span class="s2"&gt;"Maria"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;thread_joao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;TicketPurchaseService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;purchase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;ticket_id: &lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;buyer_name: &lt;/span&gt;&lt;span class="s2"&gt;"João"&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="n"&gt;thread_maria&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread_joao&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;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:join&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Resultado esperado com isolamento:&lt;/span&gt;
&lt;span class="c1"&gt;# [Maria] ✅ Compra realizada com sucesso!&lt;/span&gt;
&lt;span class="c1"&gt;# [João]  ❌ Ingresso não disponível!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Durabilidade
&lt;/h2&gt;

&lt;p&gt;Na &lt;strong&gt;Durabilidade&lt;/strong&gt; é garantido que uma vez que uma transação seja concluída com sucesso, ela não será desfeita, mesmo em caso de falha do sistema. No exemplo dos ingressos, uma vez que Maria compra o ingresso, ele não pode ser vendido novamente.&lt;/p&gt;

&lt;p&gt;Isso significa que mesmo que o servidor reinicie logo após a compra, o registro da transação de Maria já está gravado permanentemente no banco.&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="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;available: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;owner_name: &lt;/span&gt;&lt;span class="s2"&gt;"Maria"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Mesmo que o servidor caia aqui, a compra de Maria está salva.&lt;/span&gt;
&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;owner_name&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; "Maria"&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;available&lt;/span&gt;   &lt;span class="c1"&gt;# =&amp;gt; false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Voltando ao cenário inicial: você clica em "Comprar", o sistema processa tudo, mas no meio do caminho algo falha. Graças ao ACID, você não perde dinheiro sem &lt;br&gt;
receber o ingresso (Atomicidade), o banco não aceita dadosinválidos no processo (Consistência), Maria e João não compram o mesmo ingresso ao mesmo tempo (Isolamento), e uma vez confirmada a compra, ela não some (Durabilidade). As quatro propriedades juntas são o que torna um banco de dados confiável para &lt;br&gt;
transações do mundo real.&lt;/p&gt;

</description>
      <category>acid</category>
      <category>database</category>
      <category>transactions</category>
    </item>
    <item>
      <title>Teste Dev To 1</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Thu, 07 May 2026 17:48:36 +0000</pubDate>
      <link>https://dev.to/ewertoncodes/teste-dev-to-1-547c</link>
      <guid>https://dev.to/ewertoncodes/teste-dev-to-1-547c</guid>
      <description>&lt;h2&gt;
  
  
  Teste
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Teste 2
&lt;/h2&gt;

</description>
    </item>
    <item>
      <title>Size, Length e Count: Qual a diferença?</title>
      <dc:creator>Ewerton</dc:creator>
      <pubDate>Tue, 05 May 2026 00:48:16 +0000</pubDate>
      <link>https://dev.to/ewertoncodes/size-length-e-count-qual-a-diferenca-5g54</link>
      <guid>https://dev.to/ewertoncodes/size-length-e-count-qual-a-diferenca-5g54</guid>
      <description>&lt;p&gt;Ruby é uma linguagem muito expressiva e que nos dá a liberdade de escrever código de várias formas. Por exemplo, se eu quiser contar quantos elementos tem numa lista, eu posso usar pelo menos 3 métodos diferentes para isso.&lt;/p&gt;

&lt;h1&gt;
  
  
  No Ruby
&lt;/h1&gt;

&lt;p&gt;O &lt;code&gt;length&lt;/code&gt;, que é um método usado em arrays, strings e hashes, retorna o número de elementos que o objeto tem.&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="mi"&gt;4&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="nb"&gt;puts&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;length&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 5&lt;/span&gt;

  &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, World!"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 13&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
ruby&lt;/p&gt;

&lt;p&gt;O método &lt;code&gt;size&lt;/code&gt; é basicamente a mesma coisa que o &lt;code&gt;length&lt;/code&gt;. Ele é um alias do método &lt;code&gt;length&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="mi"&gt;4&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="nb"&gt;puts&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;size&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 5&lt;/span&gt;

  &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, World!"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 13&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;count&lt;/code&gt; já é um pouco diferente. Além de contar o total, você pode passar um argumento ou um bloco para filtrar o que quer contar.&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;numeros&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="mi"&gt;4&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;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# Quantos são pares?&lt;/span&gt;
  &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:even?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 3&lt;/span&gt;

  &lt;span class="c1"&gt;# Quantas vezes aparece o número 2?&lt;/span&gt;
  &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&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="c1"&gt;# =&amp;gt; 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  No Rails
&lt;/h1&gt;

&lt;p&gt;E como funciona no ActiveRecord? Quando estamos trabalhando com ActiveRecord, a escolha entre esses métodos impacta diretamente a performance, já que cada um fala com o banco de dados de um jeito diferente.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;count&lt;/code&gt; quando você quer garantir que a contagem será feita diretamente no banco de dados.&lt;br&gt;
Sempre que ele for chamado ele vai executar uma consulta SQL para contar os registros.&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="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Logger&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="no"&gt;STDOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&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;all&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="c1"&gt;# SELECT COUNT(*) FROM users =&amp;gt; 1000&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="c1"&gt;# SELECT COUNT(*) FROM users =&amp;gt; 1000&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;length&lt;/code&gt; quando é chamado pela primeira vez vai executar uma query no banco de dados para contar os registros, e nas chamadas seguintes ele vai usar o valor que foi armazenado na memória.&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="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Logger&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="no"&gt;STDOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&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;all&lt;/span&gt;
&lt;span class="c1"&gt;# O length carrega todos os registros para a memória&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="c1"&gt;# SELECT "users".* FROM "users" =&amp;gt; 1000 registros transformados em objetos&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt; &lt;span class="c1"&gt;# 1000 (agora usa o que já está na memória)&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;Quando usamos o &lt;code&gt;size&lt;/code&gt; ele consegue saber alternar entre o &lt;code&gt;count&lt;/code&gt; e o &lt;code&gt;length&lt;/code&gt;. Ele verifica se os registros foram carregados previamente, se sim ele usa o length, se não ele usa o count.&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;users&lt;/span&gt; &lt;span class="o"&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;all&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="c1"&gt;# SELECT COUNT(*) FROM "users" (Ele viu que não estava carregado e foi direto pro banco)&lt;/span&gt;

&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt; &lt;span class="c1"&gt;# Forçamos o carregamento dos registros&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="c1"&gt;# 1000 (Ele percebeu que já carregou e contou direto da memória)&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;Entender o comportamento real desses métodos é fundamental para evitar desperdício de recursos. Escolher o método certo para cada cenário é o que garante uma aplicação funcione de forma correta. Nos próximos posts pretendo mostrar outros métodos do Rails que causam confusão mas que são muito importantes para o dia a dia do desenvolvedor Rails.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <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://dev.to/ewertoncodes/como-eu-penso-e-escrevo-meus-testes-4j26</link>
      <guid>https://dev.to/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://dev.to/ewertoncodes/compartilhando-comportamentos-usando-heranca-no-ruby-3blf</link>
      <guid>https://dev.to/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://dev.to/ewertoncodes/jsonb-e-gin-index-otimizando-consultas-no-postgresql-3n0p</link>
      <guid>https://dev.to/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://dev.to/ewertoncodes/o-problema-n1-um-vilao-na-performance-do-backend-3co4</link>
      <guid>https://dev.to/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://dev.to/ewertoncodes/entendendo-o-json-web-token-jwt-1b38</link>
      <guid>https://dev.to/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://dev.to/ewertoncodes/blocos-procs-e-lambdas-no-ruby-22n3</link>
      <guid>https://dev.to/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://dev.to/ewertoncodes/como-os-sites-evoluiram-ajax-ssg-spa-e-ssr-a7</link>
      <guid>https://dev.to/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="448"&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>
