<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AlexCastroDev</title><link>https://alexandrocastro.dev.br/</link><description>Blog das minhas experiências de programação, desenvolvimento e tecnologia.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Thu, 25 Dec 2025 21:13:43 GMT</lastBuildDate><atom:link href="https://alexandrocastro.dev.br/index.xml" rel="self" type="application/rss+xml"/><item><title>Pequena otimização com índice GIN</title><link>https://alexandrocastro.dev.br/2025/12/25/database-indexes-gin/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2025/12/25/database-indexes-gin/</guid><pubDate>Thu, 25 Dec 2025 00:00:00 GMT</pubDate><description>&lt;h1>Introdução&lt;/h1>&lt;p>Em pleno feriado, nada para fazer, eu tinha em mente um relatório que recebi no fim de semana, de um dos meus serviços que deixo rodando no meu homelab.&lt;/p>
&lt;p>O report recebido era esse:&lt;/p>
&lt;p>&lt;img src="https://github.com/user-attachments/assets/ac95d993-2d7f-4a2e-a706-e4f4fd8f0a90" alt="image" loading="lazy" />&lt;/p>
&lt;p>Essa era a &amp;ldquo;pior&amp;rdquo; query, visto que era um serviço com poucos acessos, então outros endpoint estava em um ótimo tempo de resposta.&lt;/p>
&lt;p>Essa query, se fosse algum serviço maior e mais sério, não precisava gastar tanto tempo nisso, mas foi umas horas de aprendizado.&lt;/p></description><content:encoded><![CDATA[<h1>Introdução</h1><p>Em pleno feriado, nada para fazer, eu tinha em mente um relatório que recebi no fim de semana, de um dos meus serviços que deixo rodando no meu homelab.</p>
<p>O report recebido era esse:</p>
<p><img src="https://github.com/user-attachments/assets/ac95d993-2d7f-4a2e-a706-e4f4fd8f0a90" alt="image" loading="lazy" /></p>
<p>Essa era a &ldquo;pior&rdquo; query, visto que era um serviço com poucos acessos, então outros endpoint estava em um ótimo tempo de resposta.</p>
<p>Essa query, se fosse algum serviço maior e mais sério, não precisava gastar tanto tempo nisso, mas foi umas horas de aprendizado.</p>
<h1>Contexto</h1><p>Tenho uma API onde a autenticação é delegado ao Auth0, e ao criar um novo usuário na minha db, antes preciso verificar se esse email já foi criado ou não. A princípio, isso é uma coisa banal de se fazer, já que temos índices unique na maioria dos bancos de dados.</p>
<p>O &ldquo;problema&rdquo; é que um usuário, pode ter várias &ldquo;identidades&rdquo;, ou formas de se conectar. Para o Auth0, login via Google, é uma conta diferente de Login / Password, que também é diferente do Login com Facebook. Para vincular as contas, entra os &ldquo;link account&rdquo;.</p>
<p>Se sua regra de negócio não permite que o mesmo email seja contas diferentes, você precisa ter uma &ldquo;action&rdquo; que faz alguma ação antes de realizar o cadastro. E eu tenho uma API com chave (M2M) que diz se aquele email já existe em minha base, ou não.</p>
<p>Basicamente armazeno as contas do seguinte formato:</p>
<ul>
<li>id (PK)</li>
<li>auth0_id (qual identity é a principal, para controle de qual não pode ser desassociada, até a troca de outra principal)</li>
<li>auth0_infos</li>
</ul>
<p>Entenda auth0_infos como dados parciais da conta como se fosse um cache. por exemplo:</p>
<p><code>{ {&quot;identities&quot; =&gt; {&quot;google-oauth2|1234&quot; =&gt; {&quot;email&quot; =&gt; &quot;xx@x.com&quot;, &quot;connection&quot; =&gt; &quot;google-oauth2&quot;, &quot;email_verified&quot; =&gt; true } } )</code></p>
<h1>Problema</h1><p>O index que criei primeiramente, era para solucionar a busca rápida pelo auth0_id, que fazia algo do tipo:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">select</span><span class="w"> </span><span class="n">auth0_infos</span><span class="o">-&gt;</span><span class="s1">&#39;identities&#39;</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="s1">&#39;google-oauth2|1234&#39;</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">users</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>com o index:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="p">(</span><span class="n">auth0_infos</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s1">&#39;identities&#39;</span><span class="p">::</span><span class="nb">text</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>O explain analyze me retornou um bitmap, com menos de 1ms, estava feliz e pronto, vida que segue.</p>
<p>Porém quando surgiu a necessidade de existir a implementação dos identities, o que eu fiz foi algo do tipo:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="s2">&#34;users&#34;</span><span class="p">.</span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="s2">&#34;users&#34;</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="p">(</span><span class="k">EXISTS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">SELECT</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">jsonb_each</span><span class="p">(</span><span class="n">auth0_infos</span><span class="o">-&gt;</span><span class="s1">&#39;identities&#39;</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="k">identity</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="k">WHERE</span><span class="w"> </span><span class="k">identity</span><span class="p">.</span><span class="n">value</span><span class="o">-&gt;&gt;</span><span class="s1">&#39;email&#39;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;user_xpto@example.com&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">));</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Na minha cabeça, funcionava perfeito, como tinha poucos usuários, não me importei muito, então &ldquo;compilou, vendeu&rdquo;.</p>
<p>O resultado foi ter um <a href="https://en.wikipedia.org/wiki/Full_table_scan" target="_blank" rel="noopener">FULL SCAN Query</a>.</p>
<h1>Pesquisa</h1><p>Após ver o report, decidi melhorar meu entendimento sobre como isso realmente funcionava, e vou deixar uns artigos que me ajudou:</p>
<ul>
<li>
<p><a href="https://www.tigerdata.com/learn/optimizing-array-queries-with-gin-indexes-in-postgresql" target="_blank" rel="noopener">Optimizing Array Queries With GIN Indexes in PostgreSQL</a></p>
</li>
<li>
<p><a href="https://pganalyze.com/blog/gin-index" target="_blank" rel="noopener">Understanding Postgres GIN Indexes: The Good and the Bad</a></p>
</li>
<li>
<p><a href="https://www.cybertec-postgresql.com/en/gin-just-an-index-type/" target="_blank" rel="noopener">GIN - Just A Kind Of Index</a></p>
</li>
<li>
<p><a href="https://medium.com/@vedantthakkar1003/mastering-postgresql-gin-indexes-the-ultimate-guide-to-faster-jsonb-array-and-full-text-search-f1f8ec3e67af" target="_blank" rel="noopener">Mastering PostgreSQL GIN Indexes: The Ultimate Guide to Faster JSONB, Array, and Full-Text Search</a></p>
</li>
</ul>
<p>Um <a href="https://stackoverflow.com/questions/44326458/is-gin-index-on-postgres-jsonb-column-nested" target="_blank" rel="noopener">post do Stack Overflow</a> me chamou atenção aqui: &ldquo;For containment @&gt; it works with nested values. For other operators it works only for top-level keys or whatever level is used in expression index. Also, according to documentation, using expression index on level you want to query will be faster than simple index on whole column (makes sense as size is smaller).</p>
<p>If you are doing only containment search, consider using jsonb_path_ops while building your index. It is smaller and faster.&rdquo;</p>
<p>Então se juntarmos os posts, com o esse comentário, percebemos que o problema ta mesmo na query e não no index.</p>
<p>Mas até onde podemos melhorar?</p>
<h1>Solução</h1><p>Primeiro, Vamos trocar testar remover o jsonb_each e usar operador simples de concat. @&gt; que o jsonb_path_ops suporta:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>SELECT * FROM users WHERE auth0_infos -&gt; &#39;identities&#39; @&gt; &#39;[{&#34;auth0_id&#34;: &#34;auth0|52e3af8e7f5be863c4169abb&#34;}]&#39;::jsonb;
SELECT * FROM users WHERE auth0_infos -&gt; &#39;identities&#39; @&gt; &#39;[{&#34;email&#34;: &#34;user_100000_aa7daf85@example.com&#34;}]&#39;::jsonb;</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>No Rails:</p>
<p><img src="https://github.com/user-attachments/assets/33b9ef4e-33ae-4a4e-a927-96afa0a6b406" alt="changes" loading="lazy" /></p>
<p>Para aproveitar o melhor da indexação, mudamos a estrutura que armazenamos para:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;identities&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;auth0_id&#34;</span><span class="p">:</span> <span class="s2">&#34;auth0|1234&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;user@example.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;isSocial&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;email_verified&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;connection&#34;</span><span class="p">:</span> <span class="s2">&#34;Username-Password-Authentication&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Preparei uma DB com uma quantidade considerável de usuários ( 100 mil ), e o resultado:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Antes:
</span></span><span class="line"><span class="cl">Execution Time: 187.472 ms
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Depois: 
</span></span><span class="line"><span class="cl">Execution Time: 0.084 ms</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Se só estamos utilizando esse operador, e não precisamos de tanta flexibilidade (interseções, mais entradas indexadas), não precisamos ter tantas entries no nosso índice.</p>
<p>Atualmente temos este peso (índice não é grátis):</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">SELECT pg_size_pretty<span class="o">(</span>pg_relation_size<span class="o">(</span><span class="s1">&#39;index_users_on_auth0_infos_identities&#39;</span><span class="o">))</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="m">22</span> MB</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Agora quero ver qual a diferença que tenho, após criar apenas jsonb_path_ops:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">INDEX</span><span class="w"> </span><span class="n">idx_users_auth0_identities</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">users</span><span class="w"> </span><span class="k">USING</span><span class="w"> </span><span class="n">GIN</span><span class="w"> </span><span class="p">((</span><span class="n">auth0_infos</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s1">&#39;identities&#39;</span><span class="p">)</span><span class="w"> </span><span class="n">jsonb_path_ops</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">pg_size_pretty</span><span class="p">(</span><span class="n">pg_relation_size</span><span class="p">(</span><span class="s1">&#39;index_users_on_auth0_infos_identities&#39;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="mi">12</span><span class="w"> </span><span class="n">MB</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Bem menos, resolvendo o mesmo problema!</p>
<h1>Conclusão</h1><p>Ainda não é um assunto que domino 100%, mas entender a diferença de BTREE, GIN, GIST, Brin, Hash como índice, e sua estrutura de dados te faz pensar com mais clareza na solução.</p>
<p>Foi bom conhecer também os limites de escritas dos índices GIN, tanto em tamanho de pendentes, como em lentidão de escrita, que me faz pensar no como o não relacional resolve bem essa parte.</p>
<p>Obrigado por ler até aqui, um abraço.</p>
]]></content:encoded><category>database</category><category>postgres</category><category>indexes</category></item><item><title>Meu Framework de Estudo</title><link>https://alexandrocastro.dev.br/2024/10/21/meu-framework-de-estudo/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2024/10/21/meu-framework-de-estudo/</guid><pubDate>Mon, 21 Oct 2024 00:00:00 GMT</pubDate><description>&lt;h1>Introdução&lt;/h1>&lt;p>Este artigo vai ser bem breve, e o objetivo principal é mostrar como hoje faço meus estudos.&lt;/p>
&lt;h2>Leitura&lt;span class="hx-absolute -hx-mt-20" id="leitura">&lt;/span>
&lt;a href="#leitura" class="subheading-anchor" aria-label="Permalink for this section">&lt;/a>&lt;/h2>&lt;p>Eu iniciei minha carreira, lendo muitas apostila em PDF de PHP, e sofri pra aprender lendo.&lt;/p>
&lt;p>Ultimamente tenho lido muito conteúdo teórico da faculdade, e livros recomendados pelos meus professores, e livros que tenho muita curiosidade para aprender.&lt;/p>
&lt;p>Normalmente eu prefiro livros físicos, mas dependendo da leitura, eu também uso kindle, e (bem raramente) o iPad.&lt;/p></description><content:encoded><![CDATA[<h1>Introdução</h1><p>Este artigo vai ser bem breve, e o objetivo principal é mostrar como hoje faço meus estudos.</p>
<h2>Leitura<span class="hx-absolute -hx-mt-20" id="leitura"></span>
    <a href="#leitura" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu iniciei minha carreira, lendo muitas apostila em PDF de PHP, e sofri pra aprender lendo.</p>
<p>Ultimamente tenho lido muito conteúdo teórico da faculdade, e livros recomendados pelos meus professores, e livros que tenho muita curiosidade para aprender.</p>
<p>Normalmente eu prefiro livros físicos, mas dependendo da leitura, eu também uso kindle, e (bem raramente) o iPad.</p>
<p>Eu também faço notas nos livros que leio, e quando é um mais mão na massa, igual ao livro de Java, eu paro pra testar coisas diferentes, para validar se o que li, eu aprendi direito.</p>
<p>Quando eu gosto muito do livro que estou lendo de forma virtual, eu compro o livro físico, para fazer notas. ( mesmo que já tenha comprado na amazon ).</p>
<h2>Papers<span class="hx-absolute -hx-mt-20" id="papers"></span>
    <a href="#papers" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Essa modalidade é nova, mas ultimamente, com o aumento do meu interesse na área acadêmica, eu estou lendo papers acadêmicos relacionado a sistemas operacionais e sistemas de arquivos. É uma área que quero contribuir, então logo espero fazer algo por aí.</p>
<p>Papers são complexos, foram anos de estudo, e se você entender bem a proposta, poderá valer mais que centenas de vídeos.</p>
<h2>Engineering blog<span class="hx-absolute -hx-mt-20" id="engineering-blog"></span>
    <a href="#engineering-blog" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Existem muitos blogs bons, de cientistas e engenheiros de verdade. Netflix Medium, Uber, Shopify blog, etc.. Esquece Medium de pessoas randoms que querem fazer bait como &ldquo;stop doing …&rdquo;. Pelo amor de Deus, é uma perca de tempo.</p>
<p>Meu próprio blog, eu faço pra mim, e pensando em mim.</p>
<h2>Palestras Online<span class="hx-absolute -hx-mt-20" id="palestras-online"></span>
    <a href="#palestras-online" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu gosto de palestras gravadas, não de vídeos de influencers no Youtube. Também não gosto de cursos pagos. Faz muito tempo que não pago algum curso.</p>
<p>Os cursos na Udemy, e alguns específicos, foram bons no início da minha carreira. Depois acabei assistindo alguns com destaques, tipo Full Cycle e Balta. Esses tem conteúdo dedicado em um tema que eu não queria perder muito tempo, e acabei aprendendo bastante. São ambos que têm décadas de experiência.</p>
<p>Eu já não tenho paciência para esses cursos, são lentos, e eu consigo hoje facilmente na documentação, entender o objetivo, e aprender por mim mesmo.</p>
<p>Palestras normalmente são deep dive bem abrangente, e mostra muito o overview do problema que tal solução resolve.</p>
<h2>Palestras presenciais<span class="hx-absolute -hx-mt-20" id="palestras-presenciais"></span>
    <a href="#palestras-presenciais" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Além do network, palestras presenciais são muito boas, por que muitas das vezes, eu posso levantar a mão e perguntar algum ponto das palestras.</p>
<p>Nem todas vão valer a pena. Eu já assisti palestras onde o tema era nada interessante, mas ao conversar no final com algumas pessoas experientes, valeu muito mais e agregou muito no conhecimento limitado que tenho.</p>
<h2>Ler pull requests de Open source<span class="hx-absolute -hx-mt-20" id="ler-pull-requests-de-open-source"></span>
    <a href="#ler-pull-requests-de-open-source" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>É bem legal ler pull request de algum projeto em uma linguagem que você tem interesse. Por exemplo, eu costumo ver os PR e RFC do Swift Lang. Também costumo ver PRs do Ruby on Rails, Spring Boot, e ver o que estão fazendo e que forma implementam as coisas.</p>
<p>Ver também os comentários resolvidos do PR, são bem interessantes.</p>
<h2>Learning by doing<span class="hx-absolute -hx-mt-20" id="learning-by-doing"></span>
    <a href="#learning-by-doing" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quando estou cansado de conteúdos repetidos, eu costumo mexer com placas de ensaio e microcontroladores.</p>
<p>Também testo coisas como manter um servidor em um Raspberry, e monitorar o mesmo.</p>
<h1>Considerações</h1><p>Faça as coisas, leia documentação, leia livros, e tente evoluir. Sai desses videozinhos do youtube, que você não aprende nada.</p>
<p>Esses dias no Linkedin uma pessoa postou que viu o vídeo XPTO, e não concordava e perguntou o que outros achavam. Simplesmente queria tocar numa discussão de gosto pessoal. Pelo amor de Deus, vá estudar!</p>
<p>Se você discorda de algo, vá pro próximo tópico de estudo, ou vá você e crie um exemplo de que XYZ funciona em tal linguagem, ou framework, mas só caso você não tenha certeza. Se já tem, vá pra outra coisa.</p>
<p>É muito melhor ter uma boa base técnica, e boas fundações, do que um badge de &rsquo;top voice&rsquo; ou qualquer porcaria que recompensa por perder seu tempo.</p>
]]></content:encoded><category>aprendizado</category><category>estudos</category><category>carreira</category><category>desenvolvimento</category><category>livros</category><category>papers</category><category>open-source</category><category>palestras</category></item><item><title>Meu Passado, Presente e Futuro na Programação</title><link>https://alexandrocastro.dev.br/2024/10/12/meu-passado-presente-e-futuro-na-programacao/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2024/10/12/meu-passado-presente-e-futuro-na-programacao/</guid><pubDate>Sat, 12 Oct 2024 17:47:00 GMT</pubDate><description>&lt;h2>Introdução&lt;span class="hx-absolute -hx-mt-20" id="introdução">&lt;/span>
&lt;a href="#introdu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section">&lt;/a>&lt;/h2>&lt;p>Este artigo é minha reflexão sobre a minha carreira na programação. Serve como um lembrete para mim mesmo, uma forma de lembrar que tracei algumas metas e não desisti delas. Também gostaria de indicar quem me motiva e inspira.&lt;/p>
&lt;p>Com o tempo, vou esquecer de detalhes que hoje está bem vivo. Então espero que eu consiga ler este blog daqui muitos anos.&lt;/p>
&lt;h1>Quem eu era&lt;/h1>&lt;p>Eu hoje em dia, com 28 anos, tenho muito claro em minhas lembranças 2005, quando fiz minha primeira conta MSN, como relacionava no MySpace, e como era limitado o acesso a informação.&lt;/p></description><content:encoded><![CDATA[<h2>Introdução<span class="hx-absolute -hx-mt-20" id="introdução"></span>
    <a href="#introdu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Este artigo é minha reflexão sobre a minha carreira na programação. Serve como um lembrete para mim mesmo, uma forma de lembrar que tracei algumas metas e não desisti delas. Também gostaria de indicar quem me motiva e inspira.</p>
<p>Com o tempo, vou esquecer de detalhes que hoje está bem vivo. Então espero que eu consiga ler este blog daqui muitos anos.</p>
<h1>Quem eu era</h1><p>Eu hoje em dia, com 28 anos, tenho muito claro em minhas lembranças 2005, quando fiz minha primeira conta MSN, como relacionava no MySpace, e como era limitado o acesso a informação.</p>
<p>Alguns detalhes me trazem nostalgia como: Os horários limitados a internet como sábado após as 14h ( que na verdade nunca me perguntei o motivo desse horário ), e domingo o dia todo. Dia de semana era de meia noite as 06:00, mas eu só utilizava este horário para ficar conectado, por que &ldquo;ganhava&rdquo; pontos no provedor intelig que eu conseguia trocar por créditos de operadora para meu chip de celular.</p>
<p>Nesta mesma época eu comecei um curso de datilografia na associação de moradores do meu bairro. Era praticamente horas escrevendo páginas de livros, durante alguns meses. Eu lembro que faziamos algo mais, como gravar documento de texto em um disquete. Eu lembro que disquete não era tão caro, e vendia ao lado da mercearia onde minha vó era dona e trabalhava. Esses disquetes tinha de várias cores (inclusive eu tinha preto, vermelho e verde), mas não lembro exatamente o que eu fazia com eles.</p>
<p>Eu vou me referir a esta época como entre os anos de 2005 a 2008, por que é exatamente dos 09 aos 12 anos que foi o meu início de descobrimento do que é um computador.</p>
<p>Nesta época, tinhamos vários discadores de internet: Oi, intellig, IG, POP (que eu odiava), e terra. A internet era então 56kbps, então como a internet era &ldquo;discada&rdquo; ( literamente, era uma ligação para se comunicar na internet ), existia o risco da internet &ldquo;cair&rdquo;. O sentido de cair, era literamente perder a conexão, e ter que &ldquo;discar&rdquo; novamente para voltar a ter acesso.</p>
<p>O maior problema era ter que tentar fazer download de jogo, música, que demorava horas e horas e a internet cair, precisava fazer tudo de novo. Além de até o fator de pessoas te ligarem, afetar a internet e ela cair. Então eu utilizava formas de fazer download de música e clips como Emule, Kazaa. Mesmo se a internet caisse, eu conseguia continuar de onde parei o download.
Além disso, era possível utilizar o download accelerator, que fazia uma gestão desses pacotes e pulava o que já tinha feito o download. ( Não me lembro bem como funcionava, nem nunca tive essa curiosidade )</p>
<p>Além disso, uma forma de espalhar algum conteúdo era por meio de revistas. Eu lembro de comprar revistas como da LevelUp, Digerati, em bancas de jornais. Sempre vinha com algum CD, que tinha demo de algum jogo, algumas apostilas em PDF para ler e aprender algo. Isso era louco, ter que ir na banca de Jornal, para saber o que há de novo para aquele mês.</p>
<p>Entre 2009 a 2010 foi uma época que eu fui apaixonado por MMORPG, e Ragnarok Online era mágico para mim. E nesta época meu tio começou a fazer curso na Microlins de montagem e manutanção de micros e redes de computadores. E foi neste ponto, que minha curiosidade começou a aumentar sobre a computação.</p>
<p>2011 foi definitivamente o marco da minha vida, eu assistia Naruto e existia muito site de animes, então em algum papo dentro do Ragnarok, conheci um garoto que sabia criar sites, e ele me chamou pra criar um site de naruto que ele tava fazendo pelo Photoshop. Eu copiava o html, e css de alguns sites, e me lembro claramente a decepção que tive, quando eu fiquei por dias sem conseguir fazer um efeito de esconder conteudo e meu código tava igual a um tutorial, e no fim, era a falta de um import de javascript.</p>
<p>Eu não entendia nada mas era muito legal construir sites, e esse garoto na época chegou a abrir um perfil HiPix eu acho, que era para vender PSD (arquivo de photoshop) de Web Design. Então eu tinha 15 anos, minha mãe deixou eu fazer um curso de web design ( na época existia uma escola de desenvolvimento de jogos, que se chamava Seven, era uma ótima iniciativa, mas era muito caro, e não tinhamos dinheiro para investir num curso assim), e neste curso aprendi coisas como Macromedia flash, dreamweaver, fireworks ( Vulgo MX Studio ).</p>
<p>Meu tio tinha me ensinado como iniciar um emulador de Ragnarok, e então imagina que, com 15 anos, eu estava aprendendo a fazer site, comecei a entender como compilar um servidor ragnarok pelo Visual Studio, e iniciar ele, e entrar em um servidor onde eu era o &ldquo;game master&rdquo; e eu também podia criar uma &ldquo;rede virtual&rdquo; via Hamachi e 5 pessoas podiam jogar na mesma rede, era incrivelmente maravilhoso.</p>
<p>Importante comentar aqui, que eu comecei a ter internet discada (acho que acima de 56kbps), e todo dia disponivel, e então comecei a frequentar bastante fórum de discussão de programação, e de ragnarok (Cronus, eAthena, brAthena e Hercules)</p>
<p>Entre 16 e 17 anos (2012 e 2013), foi um contexto que já tinha internet de 1mbps (sem limitação de dias e horário), e eu comecei a fazer alguns sites para servidores de Ragnarok, e comecei a ganhar um dinheiro aqui e ali, por que eu já conhecia o Schema do banco de dados (MySQL) dos emuladores de Ragnarok, e conseguia saber qual Clan conquistou qual castelo, Ranking PvP, e comecei a fazer script para NPC.</p>
<p>Foi quando também comecei a ler muitas apostilas de PHP, e juntar conhecimento de PHP + MySQL, conhecer também como subir arquivo via sftp pelo filezilla. Isso me levou a procurar entender como funcionava o cPanel, e comecei a entender os servidores apache, XAMPP e Wamp.</p>
<p>Até os 17 anos (2013) eu jogava muito Ragnarok, então entre 2011 a 2013 comecei a vender sites (alguns muito inspirado no themeforest), instalar Fórums para servidores (tantos Invision IPboard), configurar layout de alguns tipo &ldquo;forumeiros&rdquo;.</p>
<p>Neste ponto, antes de terminar o ensino médio, eu já conhecia um pouquinho de C++ devido ao emulador de Ragnarok, PHP 4 e 5, como alguns sistemas de gestão como cPanel, Whm e ipboard funcionavam. Também conhecia como entrar numa VPS via SSH, fazer um servidor de ragnarok rodar, junto com Banco de dados, e que porta era necessário liberar. ( Login-server, Char-server e Map-server )</p>
<p>Eu ja conhecia um pouco de Linux, por causa do CentOS.</p>
<p>E meu último &ldquo;grande&rdquo; projeto foi construir um painel onde um cliente de uma plataforma de servidores, conseguia ver o status dos 3 server do jogo. E fazer operação como: Compilar servidor (um script que via SSH fazia um curl, depois executava a compilação do servidor), ligar o servidor (um script via SSH que fazia algo como ./login-server &amp;), desligar servidor, baixar todo o conteudo do servidor (um script que fazia zip e acessava o link publico diretamente do servidor via porta 80). E acreditem que esse painel, era o diferencial de todos os provedores de VPS, já que não eram dedicado para Ragnarok.</p>
<p>Cheguei a fazer um outro Rewamp em 2016, mas nunca foi pro ar ( já tinha acabado a era de ouro do Ragnarok ).</p>
<p>Após meus 18 anos ( a partir de 2014 ), que comecei a estudar para trabalhar na área de verdade. O mercado era cruel, pelo menos na minha visão, onde eu não era um completo idiota, mas não sabia das linguagens de mercado como Delphi e Java.</p>
<h1>Salto na história</h1><p>Demorou 5 anos, além dos outros 3 que estava aprendendo e ganhando dinheiro, para começar em uma empresa de verdade. De 2014 a 2019 foram muitos trabalhos freelances (alguns de poucos valor, outros com mais), e ter que trabalhar e estudar (começar uma faculdade, trancar por falta de tempo, dormir mal por passar noites estudando). Não tem nenhum valor em contar sobre esses anos.</p>
<p>De 2019 a 2024 foram anos de tabalhar em empresas, fazer duas faculdades, e estudos extracurriculares.</p>
<h1>O que sou hoje</h1><p>Hoje em dia, olho pra trás, e vejo o que construi com PHP, NodeJS, Ruby on Rails, JQuery, e os infinitos frameworks/biblioteca Frontend, e ainda estou construindo, agora um pouco mais voltado a Backend.</p>
<p>Também estou bastante focado em ler muitos livros, e ter bastante conhecimento, e conseguir compartilhar eles.</p>
<h1>O que serei</h1><p>A médio prazo, pretendo continuar estudando Java e C# para trabalhar com sistemas maiores, talvez ir pra Banco, ou empresas que trabalham com processo em escala.</p>
<p>Já se passaram 10 anos, que estou em TI, e pretendo até os 20 anos de carreira, acumular toda essa experiência, fazer meu Mestrado, seguir para um Doutorado, participar ativamente no campo de pesquisa e enfim, até os 30 anos de carreira, me tornar um professor universitário, e ajudar a próxima geração de programadores.</p>
<p>Tendo em conta que estamos numa era de Inteligência Artificial, então, continuar me adaptando para que eu continua relevante na área que é a minha paixão.</p>
<h1>Agradecimentos</h1><p>Sou primeiramente grato pela minha esposa, Karen Castro, que esteve do meu lado desde o dia 0, da minha vida profissional, e que me conheceu antes disso tudo, e que ajudou a chegar onde cheguei e sempre me apoiou.</p>
<p>Sou muito grato ao primeiro CTO - Ian Paletta - que me deu a minha primeira oportunidade.</p>
<p>Sou grato ao CTO que me inspirou em vários aspectos, como flexibilidade, bondade e foco. - Daniel Vieira</p>
<p>Sou grato ao Lucas Testa, que não consigo definir como CTO, Backend, Head, já que teve todos esses chapéus, mas merece um destaque, por que alem de um ótimo amigo, foi outro impulso na carreira, na vida, com suas soft skills.</p>
<p>Sou grato também ao CTO que hoje em dia, é mais que um chefe, mas é uma inspiração como pessoa, como pesquisador, como mentor, e que conseguiu dar o maior impulso de carreira que já tive. - João Ferreira Loff.</p>
<p>E por fim, mas não menos importante, a todos meus amigos que fiz durante esse percurso e aos que vão fazer.</p>
<p>Esses amigos que foram além de colegas de trabalho, mas sempre se ajudaram, que um deu a mão para o outro.</p>
<p>Amigos que passamos momentos das nossas vidas pessoais juntos, e que também aprendemos coisas juntos.</p>
]]></content:encoded><category>carreira</category><category>programacao</category><category>desenvolvimento</category><category>reflexao</category><category>tecnologia</category><category>php</category><category>nodejs</category><category>ruby-on-rails</category><category>ragnarok</category><category>web-development</category></item><item><title>A Importância da Base Sólida e Decisão Técnica</title><link>https://alexandrocastro.dev.br/2024/07/14/a-importancia-da-base-solida-e-decisao-tecnica/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2024/07/14/a-importancia-da-base-solida-e-decisao-tecnica/</guid><pubDate>Sun, 14 Jul 2024 10:00:00 GMT</pubDate><description>&lt;h2>Introdução&lt;span class="hx-absolute -hx-mt-20" id="introdução">&lt;/span>
&lt;a href="#introdu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section">&lt;/a>&lt;/h2>&lt;p>Existem algumas coisas que me deixam profundamente chateado no nosso contexto de desenvolvimento de software.&lt;/p>
&lt;p>Posso citar algumas como: decisão sem motivo técnico, ataque à decisão sem saber o contexto de implementação e falta de compromisso com seu próprio trabalho.&lt;/p>
&lt;p>Vou explorar esses três pontos e dar minha visão pessoal sobre eles.&lt;/p>
&lt;h3>Ataque à decisão técnica&lt;span class="hx-absolute -hx-mt-20" id="ataque-à-decisão-técnica">&lt;/span>
&lt;a href="#ataque-%c3%a0-decis%c3%a3o-t%c3%a9cnica" class="subheading-anchor" aria-label="Permalink for this section">&lt;/a>&lt;/h3>&lt;p>Não importa se você é Frontend, Backend ou DevOps. Se você já tem experiência, já deve ter implementado algo que hoje em dia não é muito comum.&lt;/p></description><content:encoded><![CDATA[<h2>Introdução<span class="hx-absolute -hx-mt-20" id="introdução"></span>
    <a href="#introdu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Existem algumas coisas que me deixam profundamente chateado no nosso contexto de desenvolvimento de software.</p>
<p>Posso citar algumas como: decisão sem motivo técnico, ataque à decisão sem saber o contexto de implementação e falta de compromisso com seu próprio trabalho.</p>
<p>Vou explorar esses três pontos e dar minha visão pessoal sobre eles.</p>
<h3>Ataque à decisão técnica<span class="hx-absolute -hx-mt-20" id="ataque-à-decisão-técnica"></span>
    <a href="#ataque-%c3%a0-decis%c3%a3o-t%c3%a9cnica" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Não importa se você é Frontend, Backend ou DevOps. Se você já tem experiência, já deve ter implementado algo que hoje em dia não é muito comum.</p>
<p>Assim como no Japão se usa fax ao invés de e-mail, ou startups que usam FTP ao invés de algum CI com Github, Gitlab, ou o que for, sempre haverá alguém que irá criticar a abordagem.</p>
<p>O que eu defendo não é o que está sendo usado e sim o contexto do todo. Vá até o Japão e grite para todo mundo que deveriam usar e-mails, e que sua opinião é super validada e maravilhosa. Boa sorte!</p>
<p>Um post muito &ldquo;interessante&rdquo; falando sobre não se deveria usar várias bibliotecas para resolver o suposto &ldquo;problema&rdquo;.</p>
<p>O autor não estava errado em dizer que não deveria haver falta de padronização, porém duas ferramentas podem coexistir pela identificação de um problema técnico.</p>
<p>Vou contar uma experiência pessoal, mas não leve tanto em conta a tecnologia usada, porque hoje ela está em alta, amanhã será uma totalmente diferente.</p>
<p>Eu mesmo, quando era Frontend Lead, tomei uma decisão onde escolhi uma biblioteca que era bastante usada, tinha &ldquo;battle-tested&rdquo; (termo usado para algo bem utilizado por anos), e resolvia 90% dos problemas.</p>
<p>Porém, a implementação no NextJS era ruim, mas só se perceberia isso com o tempo. Após um ano e meio da existência, foi necessário migrar, pois do contrário prejudicaria o uso da plataforma.</p>
<p>Uma nota importante aqui: o workaround não valia a pena. Era tampar o sol com a peneira.</p>
<p>A escolha da mudança deveria ser bem testada, cobrir a necessidade do uso atual e cobrir o caso de uso onde estava ocorrendo o problema.</p>
<p>Migrar tudo seria muito trabalhoso, então decidi criar uma dívida técnica e migrar os pontos onde estava começando o gargalo. E então, toda alteração na aplicação posterior que tocasse nessa biblioteca, era necessário mover para a nova implementação.</p>
<p>Pontos importantes:</p>
<ul>
<li>O ponto é usar a ferramenta correta no tempo correto.</li>
<li>Ter base técnica na escolha e na mudança.</li>
<li>Nem tudo é projeto recém-iniciado, onde você tem todas as escolhas certas.</li>
<li>Provavelmente, a ferramenta que você acha ideal nem existia quando a solução foi feita.</li>
</ul>
<h3>Decisão sem motivo técnico<span class="hx-absolute -hx-mt-20" id="decisão-sem-motivo-técnico"></span>
    <a href="#decis%c3%a3o-sem-motivo-t%c3%a9cnico" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Uma decisão feita por falta de contexto ou conhecimento, embora não seja comum num cargo de líder técnico, na minha opinião, dá para entender.</p>
<p>Ninguém tem que ficar a cada segundo procurando a última ferramenta do momento, embora as escolhas precisem ser baseadas no CASO DE USO para o problema que está sendo resolvido.</p>
<p>Mas não estou falando de overengineering. Não é basicamente escolher Kubernetes, Kafka, RabbitMQ, e outros exemplos que podem ser demais para atender poucos clientes.</p>
<p>Vou dar um exemplo baseado na experiência que tive um tempo atrás.</p>
<p>Existe um problema no Frontend que não é novidade. Acontece em todos os frameworks e foi resolvido com Tree-Shaking. Você pode depois pesquisar caso não conheça esses problemas de bundler. Você também pode ver uma pesquisa que eu fiz sobre <a href="https://alexandrocastro.dev.br/posts/1686297600322-code-splitting" target="_blank" rel="noopener">code splitting</a>.</p>
<p>Certa altura, quando apresentei esse problema em um dos comentários de um code review, a resposta que recebi foi: &ldquo;Entendo seu ponto. Mas siga da minha forma, que fica mais padronizado&rdquo;.</p>
<p>Onde a opinião pessoal foi mais forte que uma base técnica.</p>
<p>Eu realmente não me importo com isso, desde que não seja com um projeto sob minha responsabilidade. Isto é um sintoma de fraqueza, onde o ego é maior do que sua base técnica e suas bases fracas.</p>
<p>Eu compartilho de uma coisa que o Akita disse sobre DHH e o Ruby on Rails: <a href="https://www.akitaonrails.com/2019/08/21/akitando-59-a-historia-de-ruby-on-rails-por-que-deu-certo" target="_blank" rel="noopener">&ldquo;Certo ou errado, ele owna as decisões em vez de se esconder atrás de um comitê. Isso é integridade conceitual que todo projeto precisa: um ditador benevolente. Gostem ou odeiem, foi o que manteve o Rails intacto até hoje.&rdquo;</a></p>
<p>DHH, ou o criador do Rails, tem opiniões fortes porque suas bases são fortes.</p>
<p>Pontos importantes:</p>
<ul>
<li>O chef não conhece todas as comidas do mundo, mas ele tem um paladar treinado e sabe quando algo é mal feito.</li>
<li>Você não precisa saber tudo, mas precisa ter boas bases sólidas.</li>
<li>Com bases fracas, criam-se líderes fracos.</li>
</ul>
<h3>Falta de compromisso com seu próprio trabalho<span class="hx-absolute -hx-mt-20" id="falta-de-compromisso-com-seu-próprio-trabalho"></span>
    <a href="#falta-de-compromisso-com-seu-pr%c3%b3prio-trabalho" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Eu já falei minha opinião no último post sobre fazer testes unitários e de integração.</p>
<p>Se você ainda está aprendendo ou tem pouca experiência como programador, o que vou dizer não é para você. Mesmo que, na minha opinião, você já deveria estar explorando testes.</p>
<p>Mas eu já estou cansado de ver pessoas &ldquo;experientes&rdquo; dando desculpinhas sobre fazer testes. Pessoas com anos de experiência, com a falácia de &ldquo;ninguém faz testes, e se meu PR for aprovado, não vou fazer o teste. Só se for obrigatório&rdquo;. Ou até mesmo líderes que não se importam com testes, não têm métricas, e os poucos testes que fazem têm nível porco de validação.</p>
<p>Para mim, todos não têm compromisso com seu próprio trabalho, preferem estar correndo atrás do rabo em um ciclo sem fim, tentando corrigir bugs que nem deveriam existir, e bugs que já foram corrigidos várias vezes e que passam de mão em mão.</p>
<p>Pior que um líder medíocre é ter pessoas que não se importam se seu &ldquo;grande código à prova de falha&rdquo; quebrar em produção.</p>
<p>Se você ainda quer se salvar, leia este artigo sobre: <a href="https://www.akitaonrails.com/2022/10/25/akitando-130-rant-projetos-testes-e-estimativa-rated-r-5097af48-c72f-42b7-bec4-486e24a86cfc" target="_blank" rel="noopener">Rant: Projetos, TESTES e Estimativa???</a></p>
<p>Pontos importantes:</p>
<ul>
<li>Sua estimativa da tarefa deveria contar com a tarefa e os testes.</li>
<li>Se você tem a possibilidade de fazer testes e mesmo assim não faz, seu trabalho ainda é tão medíocre quanto você.</li>
<li>Falar que o projeto já está há meses ou até anos sem nenhum teste é o cúmulo da preguiça.</li>
</ul>
]]></content:encoded><category>desenvolvimento</category><category>lideranca-tecnica</category><category>decisoes-tecnicas</category><category>testes</category><category>experiencia</category><category>boas-praticas</category><category>engenharia-software</category><category>frontend</category><category>backend</category></item><item><title>Testes de Integração em Frontend</title><link>https://alexandrocastro.dev.br/2024/03/29/testes-de-integracao-em-frontend/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2024/03/29/testes-de-integracao-em-frontend/</guid><pubDate>Fri, 29 Mar 2024 00:00:00 GMT</pubDate><description>&lt;h2>Introdução&lt;span class="hx-absolute -hx-mt-20" id="introdução">&lt;/span>
&lt;a href="#introdu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section">&lt;/a>&lt;/h2>&lt;p>Sempre gostei de testes unitários, integração, e tive que aprofundar mais, quando fiz um trabalho pela minha empresa durante um ano em testes manuais e automatizado em um e-commerce escrito em React Native.&lt;/p>
&lt;p>Os problemas no fim das contas, são sempre os mesmos: Fluxos complexos, tempo de execução, dispositivos diferentes, sistemas operacionais diferentes, ambiente diferentes e problemas que surgem por causa de versão do dispositivo, do S.O, da linguagem nativa, da linguagem utilizada de alto nível, arquitetura, e etc&amp;hellip;&lt;/p></description><content:encoded><![CDATA[<h2>Introdução<span class="hx-absolute -hx-mt-20" id="introdução"></span>
    <a href="#introdu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sempre gostei de testes unitários, integração, e tive que aprofundar mais, quando fiz um trabalho pela minha empresa durante um ano em testes manuais e automatizado em um e-commerce escrito em React Native.</p>
<p>Os problemas no fim das contas, são sempre os mesmos: Fluxos complexos, tempo de execução, dispositivos diferentes, sistemas operacionais diferentes, ambiente diferentes e problemas que surgem por causa de versão do dispositivo, do S.O, da linguagem nativa, da linguagem utilizada de alto nível, arquitetura, e etc&hellip;</p>
<p>Eu não vou abordar todos os pontos, mas vou selecionar um específico.</p>
<h2>Testes unitários não é uma bala de prata<span class="hx-absolute -hx-mt-20" id="testes-unitários-não-é-uma-bala-de-prata"></span>
    <a href="#testes-unit%c3%a1rios-n%c3%a3o-%c3%a9-uma-bala-de-prata" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Houve um tempo que como líder técnico, eu decidi deixar o Jest num projeto NextJS com 90% de coverage para todo novo módulo.</p>
<p>Essa era uma das muitas vantagem de ter um Monorepo, se você tem um projeto em andamento, e ele tem 30, 40, 50% de coverage em todo o projeto, você pode trabalhar com módulos completos como um package, e exigir que seja um coverage alto. até mesmo se você achar que o módulo Y não precisa ter tanto testes, por ser algo interno, ou uma prova de conceito, você pode abaixar, ou até anular para aquele package, sem influenciar todo o projeto em volta que está sendo melhorado.</p>
<hr>
<p>Um exemplo desse bom funcionamento, é uma aplicação de delivery, onde cada parte do App era administrado por uma squad. Pelo menos no contexto do Android, o carrinho era um .jar com seus gerenciamento de estado, fluxos, e etc. Assim era mais fácil de gerir um módulo especialista ou até simplesmente descartar ele por completo, sem se preocupar com arquivos perdidos no resto da aplicação.</p>
<hr>
<p>Dessa forma, eu consegui com que diminuisse drásticamente a quantidade de issue aberta por causa de erros de renderização ou informações que não deveriam aparecer de tal forma.</p>
<p>Estes testes não cobrem coisas visuais, alinhamento, fontes, e outros erros no desenvolvimento de Frontend, para isso existe outras ferramentas, e não é disso que quero abordar hoje.</p>
<p>Um dos motivos de eu ter decidido parar de exigir um nível tão alto de coverage, foi ver que embora as issues referentes a quebras de componentes e módulos terem diminuido, não garantia a integração nas aplicações.</p>
<p>Como posso saber que ao alterar um módulo de verificação de disponibilidade de um produto vai funcionar no App X, e quebrar no App Y ? Todas as funcionalidades estão normais, a API não mudou, tenho 90% de coverage, e o meu Storybook mostra todas as definições.</p>
<p>A reposta é simples: O teste unitário não leva em conta o contexto.</p>
<p>Embora as ferramentas evoluam, e esteja mais próximo do comportamento real do user (como o Testing Library), ainda não é um fluxo integrado, e sim uma unidade, por isso, advinha advinha, teste UNITÁRIO.</p>
<p>Então, vamos avaliar os problemas:</p>
<h2>Problemas e Soluções<span class="hx-absolute -hx-mt-20" id="problemas-e-soluções"></span>
    <a href="#problemas-e-solu%c3%a7%c3%b5es" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Para cada desafio aqui, vai ser um pequeno tópico.</p>
<p>Nestes exemplos, não se preocupe com qual ferramenta eu vou mencionar, qualquer uma que resolve esses problemas, vai ser a melhor. Isso é atemporal.</p>
<h3>Login externo<span class="hx-absolute -hx-mt-20" id="login-externo"></span>
    <a href="#login-externo" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O fluxo era mais ou menos simples, eu entrava na aplicação, me redirecionava para a página do Auth0, eu validava o network do client, colocava login e senha (use variáveis de ambiente), era redirecionado e fazia o snapshot dos cookies.</p>
<p>Isso era feito no setup global do Playwright, é bem similar ao cypress. Eu conseguia entrar em todas páginas logado, com esse unico setup global.</p>
<h3>Reutilização<span class="hx-absolute -hx-mt-20" id="reutilização"></span>
    <a href="#reutiliza%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>É muito comum repetir fluxos durante vários testes, e os testes ficarem grande.</p>
<p>Pense em DRY (do not repeat yourself). Imagine que você precise de criar um produto, então você terá duas classes.</p>
<ul>
<li>BaseTest</li>
<li>ItemTest</li>
</ul>
<p>ItemTest herda de BaseTest, então no BaseTest você terá o browser headless, e poderá fazer qualquer coisa.</p>
<p>Se para criar o produto, você precisa: Navegar para inventário -&gt; clicar em criar -&gt; preencher X, Y e Z -&gt; Clicar em Salvar -&gt; Produto deve aparecer na lista de produtos.</p>
<p>Você não precisa ter tudo no arquivo spec, no BaseTest você tem o &ldquo;navegar para&rdquo; (vai ser igual para todos), e para cada &ldquo;preencher Y&rdquo;, &ldquo;preencher X&rdquo; é um método da classe ItemTest. Então seu teste ficaria simples:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">item</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ItemTest</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">Faker</span><span class="p">().</span><span class="nx">name</span> <span class="c1">// Use aqui para verificar se está na tabela 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">item</span><span class="p">.</span><span class="nx">fillTitle</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="c1">// se quiser pode ter internamente um Faker::name
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">item</span><span class="p">.</span><span class="nx">fillDescription</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">waitForSelector</span><span class="p">(</span><span class="sb">`tr &gt;&gt; text=</span><span class="si">${</span><span class="nx">nameOfItem</span><span class="si">}</span><span class="sb">`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">findItemInTable</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">$</span><span class="p">(</span><span class="sb">`text=</span><span class="si">${</span><span class="nx">nameOfItem</span><span class="si">}</span><span class="sb">`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Valide
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">expect</span><span class="p">(</span><span class="nx">findItemInTable</span><span class="p">).</span><span class="nx">toBeTruthy</span><span class="p">()</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Deste jeito, se você precisar mudar algo do fluxo, você concentra os selector e ação em um único lugar.</p>
<p>Utilize boas práticas da sua ferramenta de teste, mas tente atender esse problema, por que quando você tiver 700 testes de integração, como hoje no backend temos, será horrível ter que atualizar todos testes que ficaram outdated.</p>
<p>Mitigue esse problema o máximo possível.</p>
<h3>Reutilização de HTTP<span class="hx-absolute -hx-mt-20" id="reutilização-de-http"></span>
    <a href="#reutiliza%c3%a7%c3%a3o-de-http" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>No Ruby on Rails, utilizamos VCR, uma ferramenta nascida em 2010 e que funciona perfeitamente até hoje. O nome no Playwright se chama HAR ( HTTP Archive ).</p>
<p>Você não precisa SEMPRE chamar o backend, você precisa que com a resposta do Backend, a sua funcionalidade funcione sempre, mesmo que modifique o componente. É isso, não inventa.</p>
<p>Se vai mudar algo no Backend, por exemplo, na criação de produto, agora existe uma nova validação, onde o produto tem pode ou não aparecer no Marketplace, então sim REGRAVE os HAR.</p>
<p>Lembre que o importante é fazer com que a integração do Frontend funcione.</p>
<p>Não utilizar HAR, gera pode gerar vários problemas como: Rate limit, um teste pode corromper outro (concorrência ou ordem de execução pode excluir ou inativar um produto que no próximo teste irá precisar) e longo tempo de execução ( Tempo da tarefa + Resposta das requisições )</p>
<h3>Começar pelo meio, não pelo começo<span class="hx-absolute -hx-mt-20" id="começar-pelo-meio-não-pelo-começo"></span>
    <a href="#come%c3%a7ar-pelo-meio-n%c3%a3o-pelo-come%c3%a7o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Em certa altura, você pode precisar ter um produto, reservado para um cliente, para os próximos dois dias, e pago.</p>
<p>Só que para isso, você precisa ter um item novo (para não ter erro de ordem de execução ou concorrência), criar a ordem, adicionar o produto, a data, o cliente e mover para estado de reservado. Isso pode gerar um tempo desnecessário de execução, por que você pode ter 20 testes que valida a partir deste ponto.</p>
<p>Então é hora de começar a usar helpers (fixtures/support), e criar classes ou funções que utilizam os serviços que você já usa no frontend (Redux, axios, fetch, tanstack, ou qualquer outra ferramenta), para deixar um ambiente pronto para começar a partir daquele ponto. Talvez você precise fazer umas 2 ou 3 request: Criar produto, Criar ordem já com o produto, data, cliente, e outra para trocar o estado da reserva.</p>
<p>Agora você tem o que é necessário para iniciar o teste, e validar o que for necessário validar.</p>
<p>Existe formas mais fáceis, caso o backend fosse mais perto do frontend, como criar service container no github actions e criar usuários específicos para cada situação, mas nem sempre é assim. O backend vai ser em Java, C#, PHP, Ruby, então prefiro que os testes sejam sempre independente do Backend.</p>
<h3>Multiplos frontend web com testes integrados<span class="hx-absolute -hx-mt-20" id="multiplos-frontend-web-com-testes-integrados"></span>
    <a href="#multiplos-frontend-web-com-testes-integrados" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Este deixei por ultimo, por que precisa entender os problemas anteriores.</p>
<p>Talvez seja necessário inativar um cliente, e todos produtos dele no marketplace não apareçam mais. Então é necessário navegar para outra página. Acredito que todas ferramentas populares, como Playwright, Cypress, Selenium atenda esse requisito, é basicamente alterar o endereço. Porém o bom uso do DRY, como eu disse anteriormente vai ajudar a não ter que perder fluxo que você já criou.</p>
<p>Se você já consegue achar um dono de produto, ou achar um produto pelo dono dele, nos testes do seu e-commerce / Marketplace, você pode reutilizar esses teste e esperar que eles falhem.</p>
<hr>
<p>A gente se vê, até mais!</p>
]]></content:encoded><category>frontend</category><category>testing</category><category>integration-tests</category><category>javascript</category><category>typescript</category><category>playwright</category><category>cypress</category><category>react</category><category>nextjs</category><category>quality-assurance</category></item><item><title>Ninguém Faz Testes</title><link>https://alexandrocastro.dev.br/2024/02/18/ninguem-faz-testes/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2024/02/18/ninguem-faz-testes/</guid><pubDate>Sun, 18 Feb 2024 17:47:00 GMT</pubDate><description>&lt;p>Este problema que abordo nesse post se encaixa maior parte das vezes com desenvolvedores júniors e pleno (mid level), por que sêniors e líderes só evitam testes se quiserem, já que tem grande influência sobre o que está fazendo.
Mas vou incluir alguns, que trabalham em grandes empresas e que realmente, seja muito difícil mudar algo internamente. (Tenho dificuldade em acreditar que essas empresas realmente não implementam testes)&lt;/p>
&lt;p>Mas vamos ao ponto principal, e não espere uma solução mágica vindo deste post, por que o limite dele, é meu conhecimento.&lt;/p></description><content:encoded><![CDATA[<p>Este problema que abordo nesse post se encaixa maior parte das vezes com desenvolvedores júniors e pleno (mid level), por que sêniors e líderes só evitam testes se quiserem, já que tem grande influência sobre o que está fazendo.
Mas vou incluir alguns, que trabalham em grandes empresas e que realmente, seja muito difícil mudar algo internamente. (Tenho dificuldade em acreditar que essas empresas realmente não implementam testes)</p>
<p>Mas vamos ao ponto principal, e não espere uma solução mágica vindo deste post, por que o limite dele, é meu conhecimento.</p>
<h1>Minha empresa não faz testes, o que fazer?</h1><p>Vários fatores cria esse ambiente, falta de prioridade, produto interno que não tem grande prioridade, falta de senioridade do líder (existe líderes junior, acreditem), entre outros&hellip;</p>
<p>Todos esses fatores não justificam que o pedaço que você está construindo, seja feito de qualquer forma, igual aos outros membros.</p>
<h3>Lugares &ldquo;flexíveis&rdquo;<span class="hx-absolute -hx-mt-20" id="lugares-flexíveis"></span>
    <a href="#lugares-flex%c3%adveis" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Em alguns casos, onde não se é proibido (sim, existe esse local) criar testes no projeto e for algo totalmente opcional, você pode importar apenas seu trecho, e validar a função ou a classe que criou.</p>
<p>Nestes casos, vai ser mais fácil para Mid-level, já que eles fizeram testes, ou tem uma facilidade em ler uma documentação.
Sinto de dizer que para muito juniors, vai ser uma experiência ruim, já que vai ter que fazer sozinho (caso realmente ninguém se importe com testes), e quando falhar, vai ser um pouco decepcionante, caso for outra pessoa que quebrou e não validou.</p>
<p>Pode também ser considerado uma pessoa mais lenta para fazer funcionalidades. Mas considere um seguinte ponto, é melhor ser conhecido por fazer um pouco mais lento que outros, e fazer apenas uma vez, do que fazer rápido e estar sempre voltando por causa de problemas.</p>
<p>No final, eu sempre vou aconselhar seguir com testes, sempre foi minha opinião, e nunca me impediram isso, mas tenho amigos que já bloquearam ele e poderia custar o emprego. Sinceramente, segure seu emprego e aprenda coisas por fora, até encontrar um ambiente melhor.</p>
<h3>Lugares não flexíveis<span class="hx-absolute -hx-mt-20" id="lugares-não-flexíveis"></span>
    <a href="#lugares-n%c3%a3o-flex%c3%adveis" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Como eu disse no texto anterior, existem lugares onde realmente não querem que você perca tempo criando testes, porém, vão te cobrar se não funcionar corretamente, exigindo um teste manual.</p>
<p>Neste caso, no Backend (na minha opinião), será mais fácil resolver, por que você pode usar localmente um modelo Behaviour Driven Development, onde você precisa trabalhar com API&rsquo;s, e então seus testes locais vão fazer requisições, e você pode no final validar as resposta 200, 400, 422, etc&hellip;</p>
<p>O Frontend é pra mim, muito mais difícil fazer esse isolamento. Vou dar um exemplo de uma parte do fluxo da empresa onde eu trabalho.</p>
<p>Se eu quiser testar a disponibilidade de um produto, dentro de uma reserva, eu preciso: Ter um produto criado (com preço, configuração de estoque, fotos, descrição), ter uma reserva (com cliente, data), o cliente precisa ter parametros cadastrados, e enfim adicionar tudo a reserva e então validar com testes de end-to-end. E tem o risco de alguem alterar parte do fluxo, e quebrar seu teste.</p>
<p>Claro que não nos encaixamos neste cenário, mas como eu já disse, tenho amigos que passaram por isso.</p>
<h1>Falta de senioridade</h1><p>Esta talvez seja a mais desafiadora no começo, quando você nunca teve uma experiência com testes, quer implementar, mas nem você e nem seus colegas tem conhecimento.
(Aqui, eu só conheço 1 pessoa, onde ele é o lider, e tem pouco tempo de experiência, e tem apenas 1 desenvolvedor com ele.)</p>
<p>Neste caso, tente você ler sobre testes, divide seu tempo com vídeos e artigos que ensinam como fazer no ambiente próximo ao seus, e no final puxa um workshop para que todos consigam aprender um pouco contigo. Não espere que outros façam, vai e faz.</p>
<p>Tente pedir ajuda de alguém experiente em colocar verificação de testes na pipeline, caso você não souber.</p>
<p>Não tenho muito o que dizer além disso, é sentar na cadeira de noite, e estudar para resolver o problema.</p>
<h1>Afinal de contas, Então o que fazer ?</h1><p>Não tem o que fazer para mudar o agora, mas normalmente esses tipo de lugares, muito das vezes, quebra fluxo quase o tempo todo. Aí é sua hora de brilhar, na reunião fala que é possível resolver com testes unitários, end-to-end, de integração. Mostra seu projeto pessoal como você fez isso.</p>
<p>Óbvio, não é sempre que vão te dar a medalha pela brilhante idéia, mas insiste, em outras reuniões, que certamente vai ter fluxo quebrando, diz que é possível resolver.</p>
<p>Tenha cuidado ao dizer, e quando dizer. Imagina que o fluxo quebrou em um cliente importante, perderam uma oportunidade muito boa, ou uma considerável, e ele recebeu reclamação, e então vai repassar isso pro Sênior ou Lead. Ai você, um bom menino vai falar: &ldquo;Olha, testes resolveria esse caso.&rdquo;.</p>
<p>Talvez seja uma experiência que você nunca vai ter, mas não tira a possibilidade de você mostrar para seu Lead ou Sênior a importância.</p>
<p>Outra coisa que você pode fazer ( mesmo sendo junior ), é pedir para criar uma meeting de 15 a 20 minutos, sobre testes, e como você faz. Você não precisa ser o melhor testador de software do planeta, sua soft skill de melhorar a qualidade da sua entrega, vai ser compensada em ajuda de desenvolvedores mais experientes.</p>
<h1>Considerações finais</h1><p>Este artigo não é um paper ciêntifico, então, não tem referências. Assim como a maioria dos livros, é apenas minha experiência pessoal.</p>
<p>Não espere que seus esforços para mudar as coisas, vão acontecer. Mas sempre espere que seu conhecimento adquirido em criar algo com qualidade, seja um fruto de emprego, salário e considições melhores.</p>
<p>Não pense que foi em vão, todo seu esforço. Em uma entrevista, mostrar que você viu algo errado, e tentou melhorar, é um ótimo ponto.</p>
<p>Uma recomendação não técnica, é ler o livro do Pete Goodlife: Como ser um Programador Melhor: um Manual Para Programadores que se Importam com código.</p>
]]></content:encoded><category>testes</category><category>testing</category><category>desenvolvimento</category><category>qualidade</category><category>backend</category><category>frontend</category><category>bdd</category><category>unit-tests</category><category>integration-tests</category></item><item><title>Alta Disponibilidade com Background Jobs</title><link>https://alexandrocastro.dev.br/2024/01/23/alta-disponibilidade-com-background-jobs/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2024/01/23/alta-disponibilidade-com-background-jobs/</guid><pubDate>Tue, 23 Jan 2024 17:47:00 GMT</pubDate><description>&lt;p>Tráfego na rede, requisições lentas com um parceiro de pagamentos, ou tempo processando arquivo pode fazer sua aplicação ficar mais lenta, ou parar de responder.&lt;/p>
&lt;p>Instabilidade gera milhões em prejuízo, e nós como desenvolvedores precisamos saber como mitigar esse tipo de problema. Esse assunto acaba indo para algumas tangentes que leva desde a experiência do usuário, observabilidade, e escalabilidade horizontal com orquestração de containers.&lt;/p>
&lt;p>Mas um assunto muito básico e útil, é o uso de Background Jobs.&lt;/p></description><content:encoded><![CDATA[<p>Tráfego na rede, requisições lentas com um parceiro de pagamentos, ou tempo processando arquivo pode fazer sua aplicação ficar mais lenta, ou parar de responder.</p>
<p>Instabilidade gera milhões em prejuízo, e nós como desenvolvedores precisamos saber como mitigar esse tipo de problema. Esse assunto acaba indo para algumas tangentes que leva desde a experiência do usuário, observabilidade, e escalabilidade horizontal com orquestração de containers.</p>
<p>Mas um assunto muito básico e útil, é o uso de Background Jobs.</p>
<h2>Entendendo o problema<span class="hx-absolute -hx-mt-20" id="entendendo-o-problema"></span>
    <a href="#entendendo-o-problema" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu fiz uma experiência recentemente com <a href="https://github.com/castro-research/http-node-event-loop" target="_blank" rel="noopener">Node HTTP</a>, e mesmo que não deixamos de receber requisições no Node, por utilizar o Event loop pattern e o Event Emitter, cada processo síncrono precisa ser processado um de cada vez. Então se eu tenho um processo que exige mais CPU, e pare o processo de resposta, outras chamadas vão dar timeout ou simplesmente, crashar. ( Veja a referência 4 )</p>
<p>Essas tarefas podem ser:</p>
<ul>
<li>
<p>enviar e-mails</p>
</li>
<li>
<p>processar imagens e vídeos</p>
</li>
<li>
<p>Acionar webhooks ou fazer solicitações a terceiros</p>
</li>
<li>
<p>Reconstruir índices de busca</p>
</li>
<li>
<p>Importar grandes conjuntos de dados</p>
</li>
<li>
<p>Limpar dados obsoletos</p>
</li>
</ul>
<h1>Por que usamos Background Jobs?</h1><p>Background Jobs são usados para diminuir o trabalho excessivo da sua aplicação principal. Independente da linguagem que você esteja utilizando, o processo feito será fora do ciclo de vida da sua aplicação.</p>
<p>Hoje em dia uso Ruby on Rails e NestJS, tanto um como o outro podem delegar uma tarefa para ser executada, por exemplo processar alguma imagem na Azure, essa tarefa é armazenada um UUID no Redis, e um Worker &ndash; ou seja, um novo processo separado &ndash; irá processar (na mesma ou em outra máquina), e depois preencher o resultado e emitir que foi concluido para aplicação principal. Então a aplicação principal poderá enviar um email de sucesso, mudar um campo no banco de dados, ou enviar uma mensagem via websocket. A implementação pode mudar, também como o uso da tecnologia também pode, por exemplo como usar banco relacional para guardar os jobs ( veja a referência 6). Mas o importante aqui, é o uso dessa implementação, e não da tecnologia utilizada.</p>
<h2>Implementações<span class="hx-absolute -hx-mt-20" id="implementações"></span>
    <a href="#implementa%c3%a7%c3%b5es" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O conceito de multi-tarefa vem evoluindo desde 1950, então com certeza hoje temos soluções buil-in nos frameworks Backend.</p>
<p>No Rails podemos usar o Sidekiq, ou o mais novo ActiveJobs ( referência 9 )</p>
<p>O NestJS, por ser mais um wrapper, ele abstrai o package (BullMQ)[https://github.com/taskforcesh/bullmq]</p>
<p>Ambos são fáceis de usar, sabendo do problema que isto resolve, e o modo Rails e Nest de resolver sua estrutura.</p>
<hr>
<p>Espero ter ajudado, e fique a vontade para ler os links de referências.</p>
<h1>References</h1><p>1 - <a href="https://shopify.engineering/high-availability-background-jobs" target="_blank" rel="noopener">https://shopify.engineering/high-availability-background-jobs</a></p>
<p>2 - <a href="https://www.servertribe.com/kubernetes-alternatives/" target="_blank" rel="noopener">https://www.servertribe.com/kubernetes-alternatives/</a></p>
<p>3 - <a href="https://nodejs.org/en/guides/dont-block-the-event-loop" target="_blank" rel="noopener">https://nodejs.org/en/guides/dont-block-the-event-loop</a></p>
<p>4 - <a href="https://blog.platformatic.dev/the-nodejs-event-loop" target="_blank" rel="noopener">https://blog.platformatic.dev/the-nodejs-event-loop</a></p>
<p>5 - <a href="https://docs.abp.io/en/abp/latest/Background-Jobs" target="_blank" rel="noopener">https://docs.abp.io/en/abp/latest/Background-Jobs</a></p>
<p>6 - <a href="https://planetscale.com/blog/distributed-caching-systems-and-mysql" target="_blank" rel="noopener">https://planetscale.com/blog/distributed-caching-systems-and-mysql</a></p>
<p>7 - <a href="https://docs.nestjs.com/techniques/queues" target="_blank" rel="noopener">https://docs.nestjs.com/techniques/queues</a></p>
<p>8 - <a href="https://learn.microsoft.com/en-us/azure/well-architected/reliability/background-jobs" target="_blank" rel="noopener">https://learn.microsoft.com/en-us/azure/well-architected/reliability/background-jobs</a></p>
<p>9 - <a href="https://edgeguides.rubyonrails.org/active_job_basics.html" target="_blank" rel="noopener">https://edgeguides.rubyonrails.org/active_job_basics.html</a></p>
]]></content:encoded><category>background-jobs</category><category>nodejs</category><category>ruby-on-rails</category><category>redis</category><category>performance</category><category>scalability</category><category>web-development</category><category>backend</category><category>sidekiq</category><category>bullmq</category></item><item><title>AdonisJS e Produtividade no Desenvolvimento</title><link>https://alexandrocastro.dev.br/2024/01/21/adonis-js-and-productivity/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2024/01/21/adonis-js-and-productivity/</guid><pubDate>Sun, 21 Jan 2024 17:47:00 GMT</pubDate><description>&lt;p>TLDR: Este artigo gira mais em volta de produtividade, do que falar de framework em si.&lt;/p>
&lt;p>Já faz uns meses que eu não tenho escrito nada, e nem feito twitch ou lives no Youtube. Isso tem me chateado um pouco, por que é algo visível da minha evolução de explicar algumas coisas que tenho curiosidade. Exclusivamente para isso, pois nunca olhei números de views de meus vídeos, e nem tenho atualmente analytics no meu blog.&lt;/p></description><content:encoded><![CDATA[<p>TLDR: Este artigo gira mais em volta de produtividade, do que falar de framework em si.</p>
<p>Já faz uns meses que eu não tenho escrito nada, e nem feito twitch ou lives no Youtube. Isso tem me chateado um pouco, por que é algo visível da minha evolução de explicar algumas coisas que tenho curiosidade. Exclusivamente para isso, pois nunca olhei números de views de meus vídeos, e nem tenho atualmente analytics no meu blog.</p>
<p>Este artigo vai documentar um pensamento, e espero que ajude a ver as coisas desse modo, concordando ou não.</p>
<h2>Frameworks<span class="hx-absolute -hx-mt-20" id="frameworks"></span>
    <a href="#frameworks" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Hoje todos nós temos um leque de frameworks como o <a href="https://nestjs.com/" target="_blank" rel="noopener">NestJS</a>, <a href="https://learn.adonisjs.com/" target="_blank" rel="noopener">Adonis</a>, <a href="https://expressjs.com/" target="_blank" rel="noopener">Express</a>, <a href="https://fastify.dev/" target="_blank" rel="noopener">Fastify</a>, Koa, Hapi, etc&hellip;</p>
<p>Fora os ORM (TypeORM, Prisma, Knex, etc&hellip;), Testing library, etc&hellip;</p>
<p>No mundo Javascript, isso é bem normal, né ? &ldquo;Não gosto da biblioteca X, vou construir uma totalmente nova e diferente, por que do meu jeito é melhor&rdquo;. Daí percebemos uma divisão na comunidade.</p>
<h2>Background<span class="hx-absolute -hx-mt-20" id="background"></span>
    <a href="#background" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Normalmente quando eu penso em Java, penso Spring e Hibernates, quando penso C#: .NET MVC e Entity Framework, Ruby: penso em Rails e PHP penso Laravel e Eloquent.</p>
<p>Essas ferramentas (entenda que são ferramentas) não são bala de prata, mas padronizam os projetos.</p>
<p>Veja por exemplo o caso do Ruby on Rails, e da própria comunidade Rails. A mentalidade é completamente diferente, as coisas já foram resolvidadas a tanto tempo, que não é necessário ficar recriando as coisas.</p>
<p>&ldquo;Ah, e se eu quiser escalar&rdquo;, Rails escala mesmo com arquitetura monolito. (Veja o caso Spotify com Rails Engine)[https://shopify.engineering/shopify-monolith]</p>
<p>Não é necessário recriar ORM, se existe algum problema no ORM Active Record, bora lá abrir uma issue, abrir um PR, e resolver o problema. Sinceramente, isso mudou meu pensamento. ( olha que eu amo criar Open Source )</p>
<p>Realmente, tem coisas que não precisa ser criadas, e um PR resolveria.</p>
<h2>O Tempo<span class="hx-absolute -hx-mt-20" id="o-tempo"></span>
    <a href="#o-tempo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O ponto alto da produtividade, é usar ferramentas que existe há um tempo, que já resolve o mesmo problema há tempo.</p>
<p>O melhor Framework, ORM, Biblioteca de testes em pleno 2024 não deveria ser a pergunta para iniciar um projeto. e na verdade, convention over configuration já existe desde antes de 2005.</p>
<p>O AdonisJS traz isso ao Backend NodeJS desde 2015. Não estou dizendo que vai resolver todos seus problemas, mas repito que essas decisões não deveria existir no começo da construção de software.</p>
<p>Ferramentas novas, ainda não sofreu suficiente no mundo real, para se por a prova. Você não vai mudar tudo de Node para Bun, Denos, &ldquo;por que sim&rdquo;. Muito menos mudar de TypeORM, Sequelize, Lucid que já existe há anos para Prisma &ldquo;por que sim&rdquo;.</p>
<p>Se você se pergunta, &ldquo;será que devo&hellip;?&rdquo; Não, primeiro resolve seu problema com algo que já existe, quando &ldquo;bater na parede&rdquo;, você pensa em mudar.</p>
<h2>Arquitetura de pastas?<span class="hx-absolute -hx-mt-20" id="arquitetura-de-pastas"></span>
    <a href="#arquitetura-de-pastas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Por que não existe um consenso? você vai para uma empresa, utilizam DDD, sem convenção, e ás vezes você se pergunta se os devs implementaram eram Domain Driven Design ou Directory Driven Design. Outras vão usar Clean Architecture, com seus use cases, etc&hellip; Só que Clean Architecture na empresa A, não é igual na empresa B.</p>
<p>Você perde tempo, perde produtividade, e as vezes você trabalha debaixo de uma arquitetura de como o líder acredita ser a correta.</p>
<p>então novamente, convention over configuration.</p>
<h2>Performance<span class="hx-absolute -hx-mt-20" id="performance"></span>
    <a href="#performance" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O desempenho da sua aplicação, depende muito mais de você e da sua infraestrutura, do que do seu código. O seu conhecimento sobre SQL e banco de dados, deveria ser superior ao qual é o ORM de qualquer framework do momento.</p>
<p>Tenha um pensamento crítico, por exemplo: Deveria usar um framework MVC na Azure Functions? (ou Google Functions, AWS lambda, etc.. ?) Claro que não, Serveless não é pra isso.</p>
<p>Pensa em iniciar com performance, se você está num contexto onde já existe um negócio, com milhares de usuários, com problemas acontecendo a cada X tempos, e essa aplicação é pra tirar o gargalo de outros serviços.</p>
<h2>Trabalho em equipe<span class="hx-absolute -hx-mt-20" id="trabalho-em-equipe"></span>
    <a href="#trabalho-em-equipe" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A melhor coisa de convention over configuration, é trabalhar em equipe.</p>
<p>Você consegue trocar de contexto entre projetos, de forma uniforme e com foco na entrega de valor.</p>
<h2>Entrega de valor<span class="hx-absolute -hx-mt-20" id="entrega-de-valor"></span>
    <a href="#entrega-de-valor" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu simplesmente amo essa parte.</p>
<p>Você faz o start do seu projeto, e já ataca o negócio / solução.</p>
<p>Esquece qual é a melhor tecnologia para X, Y, Z. ( pense no que eu disse sobre performance )</p>
<p>Isso não se aplica somente a framework e bibliotecas.</p>
<p>Olha esse seguinte caso:</p>
<h3>Caso: Processando dados em massa<span class="hx-absolute -hx-mt-20" id="caso-processando-dados-em-massa"></span>
    <a href="#caso-processando-dados-em-massa" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Tenho um monolito, onde tudo está correndo tudo bem.</p>
<p>Recebo uma demanda para trabalhar com arquivos Word, Excel com validações, etc&hellip; Podemos trabalhar com Node Streams para resolver isso. A limitação não seria a linguagem.</p>
<p>Mas como andam as bibliotecas que resolvem isso ?</p>
<p>Se isso resolvesse rápido com C# ? Bibliotecas já implementadas, todas mantidas pela Microsoft.</p>
<p>Somos pagos para resolver problemas com as ferramentas certas, de forma produtiva.</p>
<h1>Conclusão</h1><p>Não tem uma conclusão, Conhecer arquiteturas não é o mal.</p>
<p>Os pontos foram focados em eficiência na entrega de valor.</p>
<p><img src="https://github.com/AlexcastroDev/blog-alexandrocastro-dev/assets/10711649/75f0c198-556f-451b-a2e4-afed9b824b8d" alt="image" loading="lazy" /></p>
<h1>Referências</h1><p><a href="https://www.mindtheproduct.com/overengineering-can-kill-your-product/" target="_blank" rel="noopener">https://www.mindtheproduct.com/overengineering-can-kill-your-product/</a></p>
<p><a href="https://rubyonrails.org/doctrine" target="_blank" rel="noopener">https://rubyonrails.org/doctrine</a></p>
]]></content:encoded><category>adonisjs</category><category>nodejs</category><category>javascript</category><category>typescript</category><category>web-development</category><category>productivity</category><category>frameworks</category><category>backend</category></item><item><title>Como os Estilos Funcionam</title><link>https://alexandrocastro.dev.br/2023/09/03/how-styles-works/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2023/09/03/how-styles-works/</guid><pubDate>Sun, 03 Sep 2023 17:47:00 GMT</pubDate><description>&lt;p>Vamos aprofundar-nos nos meandros da estilização web, na renderização do lado do servidor (SSR) e nos desafios que surgem ao usar soluções modernas de estilização como o styled-components.&lt;/p>
&lt;p>Seja um desenvolvedor experiente buscando solidificar seu entendimento ou um novato tentando compreender os fundamentos, este repositório tem como objetivo fornecer insights que desmistificam as complexidades da estilização no desenvolvimento web.&lt;/p>
&lt;p>Começaremos explorando os conceitos fundamentais que sustentam como os navegadores renderizam o conteúdo e aplicam estilos. Este conhecimento servirá como um bloco de construção crucial para entender tópicos mais avançados, como SSR, e as compensações ao usar abordagens de estilização específicas.&lt;/p></description><content:encoded><![CDATA[<p>Vamos aprofundar-nos nos meandros da estilização web, na renderização do lado do servidor (SSR) e nos desafios que surgem ao usar soluções modernas de estilização como o styled-components.</p>
<p>Seja um desenvolvedor experiente buscando solidificar seu entendimento ou um novato tentando compreender os fundamentos, este repositório tem como objetivo fornecer insights que desmistificam as complexidades da estilização no desenvolvimento web.</p>
<p>Começaremos explorando os conceitos fundamentais que sustentam como os navegadores renderizam o conteúdo e aplicam estilos. Este conhecimento servirá como um bloco de construção crucial para entender tópicos mais avançados, como SSR, e as compensações ao usar abordagens de estilização específicas.</p>
<p>À medida que avançamos, percorreremos diferentes cenários e exemplos que esclarecerão o comportamento dos navegadores, o papel do JavaScript na renderização e as implicações do uso de soluções CSS-in-JS, como o styled-components. Também discutiremos os desafios de implementar SSR com essas ferramentas e forneceremos insights sobre alternativas mais adequadas para estilos renderizados no servidor.</p>
<p>Ao final desta jornada, você terá adquirido uma compreensão abrangente dos mecanismos envolvidos na renderização de conteúdo e aplicação de estilos na web. Se você escolher adotar metodologias tradicionais de CSS, explorar módulos CSS ou trabalhar com bibliotecas modernas como o styled-components, estará equipado com o conhecimento necessário para tomar decisões informadas que atendam aos requisitos de seus projetos.</p>
<p>Vamos embarcar nesta exploração da estilização e renderização no mundo do desenvolvimento web, desvendando a magia nos bastidores e compreendendo as opções disponíveis para nós como desenvolvedores.</p>
<h3>Repositório<span class="hx-absolute -hx-mt-20" id="repositório"></span>
    <a href="#reposit%c3%b3rio" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Aqui eu deixo bem mais explicado meu deep-dive sobre estilização inline, em arquivos CSS e em bibliotecas como o styled-components, inclusive utilizando desde vanilla, até os frameworks mais populares como o Next, Remix, etc&hellip;</p>
<p>Link para o repositório: <a href="https://github.com/castro-research/research-styled-components-behaviours" target="_blank" rel="noopener">https://github.com/castro-research/research-styled-components-behaviours</a></p>
]]></content:encoded><category>css</category><category>javascript</category><category>react</category><category>styled-components</category><category>ssr</category><category>css-in-js</category><category>web-development</category></item><item><title>Code Spliting com NextJS</title><link>https://alexandrocastro.dev.br/2023/06/19/code-spliting-com-nextjs/</link><guid isPermaLink="true">https://alexandrocastro.dev.br/2023/06/19/code-spliting-com-nextjs/</guid><pubDate>Mon, 19 Jun 2023 17:47:00 GMT</pubDate><description>&lt;h1>O Problema em desenvolvimento&lt;/h1>&lt;h2>O Problema 1&lt;span class="hx-absolute -hx-mt-20" id="o-problema-1">&lt;/span>
&lt;a href="#o-problema-1" class="subheading-anchor" aria-label="Permalink for this section">&lt;/a>&lt;/h2>&lt;p>Em desenvolvimento, quando se importa um componente de um index (por exemplo no diretório &lt;code>components/index2.ts&lt;/code>) com outras exportações, o webpack gera o bundle com todos os componentes exportados no index.&lt;/p>
&lt;p>No nosso screens/Home_1.tsx, temos um exemplo, onde só está sendo usado o componente &lt;code>Modal&lt;/code> e em development, o bundle gerado é o seguinte:&lt;/p>
&lt;p>&lt;img
src="https://raw.githubusercontent.com/AlexcastroDev/dynamic-import-poc/main/.github//1.webp"
width="800"
/>&lt;/p>
&lt;p>O Dialog pesa 1mb, e o Modal uns 3kb, mas o bundle gerado tem 1.03mb, pois o webpack gera o bundle com todos os componentes exportados no index.&lt;/p></description><content:encoded><![CDATA[<h1>O Problema em desenvolvimento</h1><h2>O Problema 1<span class="hx-absolute -hx-mt-20" id="o-problema-1"></span>
    <a href="#o-problema-1" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Em desenvolvimento, quando se importa um componente de um index (por exemplo no diretório <code>components/index2.ts</code>) com outras exportações, o webpack gera o bundle com todos os componentes exportados no index.</p>
<p>No nosso screens/Home_1.tsx, temos um exemplo, onde só está sendo usado o componente <code>Modal</code> e em development, o bundle gerado é o seguinte:</p>
<p><img
src="https://raw.githubusercontent.com/AlexcastroDev/dynamic-import-poc/main/.github//1.webp"
width="800"
/></p>
<p>O Dialog pesa 1mb, e o Modal uns 3kb, mas o bundle gerado tem 1.03mb, pois o webpack gera o bundle com todos os componentes exportados no index.</p>
<p>Imagina uma página com um Design System inteiro importado, vai ficar <code>super pesado e lento</code>.</p>
<h2>O Problema 2<span class="hx-absolute -hx-mt-20" id="o-problema-2"></span>
    <a href="#o-problema-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você fizer o uso do Dialog, ao invés do Modal, no NextJS, o browser vai tentar renderizar os 1mb do Dialog via Server Side Render, e na hidratação, irá carregar de novo os 1mb do Dialog.</p>
<p><img
src="https://raw.githubusercontent.com/AlexcastroDev/dynamic-import-poc/main/.github//2.webp"
width="800"
/></p>
<h1>O Problema em produção</h1><h2>Introdução<span class="hx-absolute -hx-mt-20" id="introdução"></span>
    <a href="#introdu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Em produção, quando se importa um componente de um index com outras exportações, o webpack gera o bundle apenas com o componente importado.</p>
<p>Porém o <code>Problema 2</code> do ambiente de desenvolvimento, continua em produção.</p>
<h1>A Solução do Problema 1</h1><p>Este problema vai te atrapalhar mais em desenvolvimento, pois em produção, o webpack gera o bundle apenas com o componente importado.</p>
<p>Então, se você importar apenas o componente que você vai usar, o bundle gerado será apenas com o componente que você importou.</p>
<p>por exemplo, ao invés de importar:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>import { Modal } from &#39;@/components&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Seria melhor importar:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>import { Modal } from &#39;@/components/Modal&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Porém, se você está criando package local, ou alguma pasta global, onde você não quer ficar importando todos os componentes, você pode usar o import dynamic do NextJS, citado na solução do <code>Problema 2</code>.</p>
<p>ou você pode utilizar o React Lazy, que também vai resolver o problema.</p>
<p>O Resultado vai ser esse:</p>
<p><img
src="https://raw.githubusercontent.com/AlexcastroDev/dynamic-import-poc/main/.github//x2.webp"
width="800"
/></p>
<p>Repara também que o App foi carregado mais rápido e depois foi feito o carregamento do Dialog, que é o componente que foi importado.</p>
<p><img
src="https://raw.githubusercontent.com/AlexcastroDev/dynamic-import-poc/main/.github//x3.webp"
width="800"
/></p>
<h1>A Solução do Problema 2</h1><p>Existe uma solução bem simples que resolve o problema 2, que é o uso do <code>dynamic import</code> do NextJS.</p>
<p>O dynamic import, faz com que o componente seja carregado apenas no client side, e não no server side.</p>
<p>Isso então vai evitar que o Dialog seja renderizado no server side, e na hidratação, o Dialog não será carregado de novo.</p>
<p>você pode encontrar a implementação no arquivo <code>screens/Home_1.tsx</code></p>
<p>O Resultado vai ser esse:</p>
<p><img
src="https://raw.githubusercontent.com/AlexcastroDev/dynamic-import-poc/main/.github//x1.webp"
width="800"
/></p>
<h1>Fallback</h1><p>O fallback é uma propriedade do dynamic import, que pode ser usada para renderizar um componente de loading enquanto o componente é carregado.</p>
<p>Já que o dynamic não usa mais o você pode usar a propriedade loading, e renderizar via server side render, um componente de <code>loading</code> ou um <code>skeleton</code>.</p>
<p>Exemplo:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>import dynamic from &#39;next/dynamic&#39;

const Modal = dynamic(() =&gt; import(&#39;@/components/Dialog&#39;), {
  loading: () =&gt; &lt;div&gt;Carregando...&lt;/div&gt;
})</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<h1>Disclaimer</h1><p>O <code>then</code> usado no dynamic em <code>screens/Home_1.tsx</code> é apenas por que:</p>
<p>1 - Todos imports de arquivos são assincronos
2 - O <code>@/components</code> exporta componentes individuais, ao invés de <code>export default { ... }</code></p>
<p>Como está sendo usado:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>const Dialog = dynamic(() =&gt; import(&#39;@/components&#39;).then((components) =&gt; components.Dialog()), {
  ssr: false,
  loading: () =&gt; &lt;div&gt;loading...&lt;/div&gt;
})</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p><img
src="https://raw.githubusercontent.com/AlexcastroDev/dynamic-import-poc/main/.github//fallback.webp"
width="800"
/></p>
<p>Se por acaso você usar com <code>export default { ... }</code></p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>export default {
    Modal: () =&gt; import(&#39;./Modal&#39;),
    Dialog: () =&gt; import(&#39;./Dialog&#39;),
}</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>Exemplo em <code>components/index3.ts</code></p>
<p>Você pode usar o dynamic assim:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>const Dialog = dynamic(() =&gt; import(&#39;@/components&#39;).then((components) =&gt; components.default.Dialog()), {
  ssr: false,
  loading: () =&gt; &lt;div&gt;loading...&lt;/div&gt;
})</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<hr>
<p>Observação: Mudou de 1mb para 500kb por que? Após passar o minified code, o Dialog ficou com 500kb.</p>
<p><img
src="https://raw.githubusercontent.com/AlexcastroDev/dynamic-import-poc/main/.github//minified.webp"
width="800"
/></p>
<hr>
<p>Por que? Todo export default é retornado como <code>default</code>, então você precisa acessar o default para acessar o componente.</p>
<p>Se você fizer um console, vai ver algo assim:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>{
    __esModule: true,
    default: {
        Modal: () =&gt; import(&#39;./Modal&#39;),
        Dialog: () =&gt; import(&#39;./Dialog&#39;),
    }
}</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<p>e caso você manter os <code>export const</code>, você terá:</p>
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">

<div><pre><code>{
    __esModule: true,
    default: {
        Modal: () =&gt; import(&#39;./Modal&#39;),
        Dialog: () =&gt; import(&#39;./Dialog&#39;),
    },
    Modal: () =&gt; import(&#39;./Modal&#39;),
    Dialog: () =&gt; import(&#39;./Dialog&#39;),
}</code></pre></div><div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0">
  <button
    class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
    title="Copy code"
  >
    <div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"></div>
    <div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"></div>
  </button>
</div>
</div>
<h1>Conclusão</h1><p>O problema 1, pode ser resolvido apenas importando o componente que você vai usar, ou usando o dynamic import.</p>
<p>O problema 2, pode ser resolvido apenas usando o dynamic import.</p>
<p>Sugiro também que veja uma solução melhor que vá ter menos problemas, que é o uso do babel-plugin-transform-imports, que vai fazer o uso do dynamic import automaticamente.</p>
<p><a href="https://www.npmjs.com/package/babel-plugin-transform-imports" target="_blank" rel="noopener">https://www.npmjs.com/package/babel-plugin-transform-imports</a></p>
<h1>Referências</h1><p><a href="https://nextjs.org/docs/advanced-features/dynamic-import" target="_blank" rel="noopener">https://nextjs.org/docs/advanced-features/dynamic-import</a></p>
<p><a href="https://www.freecodecamp.org/news/code-splitting-in-react-loadable-components/" target="_blank" rel="noopener">https://www.freecodecamp.org/news/code-splitting-in-react-loadable-components/</a></p>
<p><a href="https://webpack.js.org/guides/code-splitting/" target="_blank" rel="noopener">https://webpack.js.org/guides/code-splitting/</a></p>
<p><a href="https://developer.mozilla.org/en-US/docs/Glossary/Code_splitting" target="_blank" rel="noopener">https://developer.mozilla.org/en-US/docs/Glossary/Code_splitting</a></p>
<p><a href="https://nextjs.org/learn/foundations/how-nextjs-works/code-splitting" target="_blank" rel="noopener">https://nextjs.org/learn/foundations/how-nextjs-works/code-splitting</a></p>
<p><a href="https://nextjs.org/learn/foundations/how-nextjs-works/client-and-server" target="_blank" rel="noopener">https://nextjs.org/learn/foundations/how-nextjs-works/client-and-server</a></p>
]]></content:encoded><category>nextjs</category><category>javascript</category><category>react</category><category>dynamic-import</category><category>code-splitting</category><category>import-dynamic</category><category>import-dynamic-nextjs</category></item></channel></rss>