<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>carlos schults / blog</title>
    <description>Artigos sobre desenvolvimento de software e tecnologia.</description>
    <link>https://carlosschults.net/</link>
    <atom:link href="https://carlosschults.net/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 12 Aug 2026 11:07:58 +0000</pubDate>
    <lastBuildDate>Wed, 12 Aug 2026 11:07:58 +0000</lastBuildDate>
    <generator>Jekyll v4.3.1</generator>
    
    
      <item>
        <title>Elaborando Ótimas Mensagens de Commit na Era da IA</title>
        <description>&lt;p&gt;Um tempo atrás, expliquei que &lt;a href=&quot;/pt/suas-mensagens-de-commit-sao-um-lixo&quot;&gt;as suas mensagens de commit são uma porcaria e o que fazer a respeito&lt;/a&gt;. Naquele post, falei rapidinho sobre IA, afirmando que não acho que o uso de LLMs (&lt;em&gt;Large Language Models&lt;/em&gt;, ou Grandes Modelos de Linguagem) mude fundamentalmente nenhum dos pontos que levantei no post.&lt;/p&gt;

&lt;p&gt;Mas o tema das mensagens de commit geradas por LLM é relevante o suficiente para merecer um post próprio, especialmente agora que cada vez mais pessoas estão usando agentes para gerar código.&lt;/p&gt;

&lt;p&gt;É sobre isso que este post trata. Vou basicamente compartilhar minhas experiências sobre o que funciona e o que não funciona na hora de criar boas mensagens de commit.&lt;/p&gt;

&lt;h2 id=&quot;por-que-llms-não-são-automaticamente-boas-em-criar-boas-mensagens-de-commit&quot;&gt;Por Que LLMs Não São Automaticamente Boas em Criar Boas Mensagens de Commit&lt;/h2&gt;
&lt;p&gt;Quando se trata de escrever mensagens de commit, há uma área em que as IAs são muito boas: olhar para um diff e gerar um resumo.&lt;/p&gt;

&lt;p&gt;Em outras palavras, elas se destacam em descrever o que você fez em detalhes… o que, se você leu meu outro post, sabe que é exatamente o que não é pra você fazer!&lt;/p&gt;

&lt;p&gt;O que os LLMs não fazem bem é entender o contexto. Eles conseguem olhar para um diff e dizer algo como “Ok, o usuário desabilitou a cláusula OUTPUT do SQL Server na configuração do EF Core” e então escrever uma mensagem de commit detalhada descrevendo essas mudanças. O que é inútil, porque o diff do commit já mostra as mudanças.&lt;/p&gt;

&lt;p&gt;O que o LLM &lt;em&gt;não consegue&lt;/em&gt; fazer é descobrir que eu fiz a mudança porque tínhamos introduzido triggers em algumas tabelas e o EF Core começou a falhar porque a cláusula OUTPUT conflita com triggers, então tivemos que desabilitá-la.&lt;/p&gt;

&lt;p&gt;Existe toda uma história por trás de uma mudança, e a AI não vai conseguir adivinhar essa história se ninguém contar pra ela.&lt;/p&gt;

&lt;h2 id=&quot;a-ia-não-lê-sua-mente&quot;&gt;A IA Não Lê Sua Mente&lt;/h2&gt;
&lt;p&gt;Vejo que muitas pessoas ficam frustradas com código gerado por IA, e é um padrão comum. As pessoas fazem um pedido vago pra caramba, depois recebem algo em troca, e então ficam frustradas porque não era o que tinham em mente. Bom, se você tem algo específico em mente que a IA deveria levar em conta, garanta que isso saia da sua cabeça e chegue até a IA!&lt;/p&gt;

&lt;p&gt;Repitam comigo: &lt;strong&gt;a IA não lê mentes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Além disso, a IA é incrivelmente confiante. Ela sempre vai te dar &lt;em&gt;alguma coisa&lt;/em&gt; de volta. O que pode ser o que você quer, mais ou menos, mas também pode não ser, já que ela será tendenciosa em relação às abordagens que o LLM mais viu em seus dados de treinamento.&lt;/p&gt;

&lt;p&gt;Por exemplo, se você pedir uma mensagem de commit para um diff, sem instruções adicionais, é bem provável que ela cuspa algo usando &lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/&quot;&gt;conventional commits&lt;/a&gt;, simplesmente porque muita gente usa esse padrão. Pessoalmente, não gosto desse padrão e não quero usá-lo, mas é claro que o Claude não sabe disso sobre mim a menos que eu diga.&lt;/p&gt;

&lt;h2 id=&quot;o-que-fazer-então&quot;&gt;O Que Fazer Então?&lt;/h2&gt;
&lt;p&gt;No outro post, compartilhei o prompt que eu estava usando com o Claude na época:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Write a concise, well-crafted commit message for the diff I&apos;m going to give you.
Make it more high-level, focusing on the why rather than listing all changes in great detail.
Follow these rules:
- Summary
	- Brief description of what was done
	- 50 chars at the most
	- Use imperative mood
	- Do not use conventional commits
- Body
	- Brief description of the &quot;how&quot;, but focus more on the reason for the changes
	- Use prose rather than bullet points.
	- Use past tense
	- Lines no longer than 72 chars
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Eu não estava totalmente satisfeito com os resultados que estava obtendo com esse prompt, então continuei iterando sobre ele. Uma coisa que adicionei em algum momento foi que o Claude deveria me perguntar sobre o contexto quando não tivesse certeza. Isso funcionou, mas de forma um tanto inconsistente.&lt;/p&gt;

&lt;p&gt;Então, não me lembro exatamente quando, outra coisa aconteceu. Mas antes de entrar nisso, preciso fazer uma pequena digressão e explicar por que não uso Conventional Commits.&lt;/p&gt;

&lt;h2 id=&quot;conventional-commits-não-é-um-bom-padrão&quot;&gt;Conventional Commits Não É um Bom Padrão&lt;/h2&gt;
&lt;p&gt;Não gosto nem uso Conventional Commits. No passado, eu usava, mas comecei a mudar de ideia depois de um tempo.&lt;/p&gt;

&lt;p&gt;Por um bom tempo, não conseguia articular direito por que não gostava desse padrão, até ler &lt;a href=&quot;https://sumnerevans.com/posts/software-engineering/stop-using-conventional-commits/&quot;&gt;este post&lt;/a&gt; de Sumner Evans.&lt;/p&gt;

&lt;p&gt;A essência do motivo pelo qual Evans não gosta do Conventional Commits é que ele foca nas coisas erradas, tornando o tipo do commit (“feat”, “fix”, etc.) a informação mais importante, em vez do escopo. Ou seja, quais áreas ou partes do sistema o commit modifica.&lt;/p&gt;

&lt;p&gt;O Conventional Commits costuma ser combinado com ferramentas que geram changelogs automaticamente e incrementam números de versão com base nas mensagens. Evans argumenta, e eu concordo, que isso é uma ideia fundamentalmente ruim.&lt;/p&gt;

&lt;p&gt;Há mais motivos pelos quais esse padrão tão difundido não é tão bom quanto parece, mas vá ler o post do Evans para saber mais.&lt;/p&gt;

&lt;p&gt;A pergunta então se torna: o que usar no lugar?&lt;/p&gt;

&lt;h2 id=&quot;chegam-os-scoped-commits&quot;&gt;Chegam os Scoped Commits&lt;/h2&gt;
&lt;p&gt;Em seu post, depois de construir um argumento convincente contra o Conventional Commits, Evans oferece &lt;a href=&quot;https://sumnerevans.com/posts/software-engineering/stop-using-conventional-commits/#a-better-way&quot;&gt;uma alternativa diferente&lt;/a&gt;. Baseado nos padrões usados por projetos open-source de sucesso, como Git, o kernel do Linux, Go, entre outros, ele propõe um novo padrão que chamou de &lt;a href=&quot;https://scopedcommits.com/&quot;&gt;Scoped Commits&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O básico desse padrão é incrivelmente simples. Você para de usar o tipo da mudança como prefixo da sua mensagem e passa a usar um escopo, que se relaciona à área, subsistema ou parte da sua aplicação que o commit afeta.&lt;/p&gt;

&lt;p&gt;Este é um exemplo:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;auth: Add SSO login controller

The login page previously relied on a legacy form-based flow that
was being decommissioned. Introduced a new controller and service
layer to handle SSO natively, preserving existing session logic
while decoupling it from the legacy system.

Closes: AB998
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;chega-a-skill-do-claude&quot;&gt;Chega a Skill do Claude&lt;/h2&gt;
&lt;p&gt;Foi mais ou menos nessa época que comecei a experimentar com skills do Claude, porque estava cansado de repetir as mesmas instruções sempre. Decidi tentar encapsular todas essas preferências em uma skill que eu pudesse usar. Depois de bastante tentativa e erro e reescritas, cheguei a algo que acho útil.&lt;/p&gt;

&lt;p&gt;As partes mais importantes da skill, para mim, são as seguintes:&lt;/p&gt;

&lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; Read the full diff carefully before writing anything
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; If the scope isn&apos;t clear from the diff, ask one focused question
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;gs&quot;&gt;**If the diff shows *what* changed but not *why**&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*&lt;/span&gt; — the underlying
  problem, bug, or motivation isn&apos;t inferable from the code itself — ask
  one focused question about the reason for the change before writing the
  body. A body written without knowing the &quot;why&quot; tends to just restate the
  diff in prose, which isn&apos;t useful. It&apos;s fine to write the summary line
  in the meantime, but hold off on the body until you know the reason, or
  proceed with summary-only (ticket in parentheses) if the user doesn&apos;t
  have more context to give.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Elas me ajudam a garantir que o Claude receba o contexto certo para a mudança. Caso contrário, ele vai apenas fornecer uma lista detalhada de mudanças, que não é o que estou buscando.&lt;/p&gt;

&lt;p&gt;Se tiver interesse, veja a skill completa &lt;a href=&quot;https://github.com/carlosschults/claude-config/blob/main/skills/commit-message/SKILL.md&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;meu-veredito&quot;&gt;Meu Veredito?&lt;/h2&gt;
&lt;p&gt;Estou razoavelmente satisfeito com os resultados que consigo com a skill até agora. Não é perfeita, porém.&lt;/p&gt;

&lt;p&gt;Um problema que tenho com frequência é que o Claude às vezes “esquece” de usar a skill. Ele simplesmente segue em frente e escreve qualquer coisa como mensagem de commit, e aí eu tenho que dar uma bronca nele. Na maioria das vezes, ele usa a skill, então isso não chega a ser um grande problema.&lt;/p&gt;

&lt;p&gt;Outro problema é que às vezes ele não respeita a regra do 50/72 para o comprimento máximo das linhas. As linhas no corpo da mensagem costumam chegar a 75 ou 76 caracteres. Às vezes, são necessárias duas ou três tentativas até ele acertar. Chega um ponto que eu desisto é conserto manualmente.&lt;/p&gt;

&lt;p&gt;Por falar nisso, costumo alterar e editar a mensagem de commit gerada eu mesmo. Às vezes, falta uma parte crítica de contexto, ou o Claude entendeu algo errado, e é simplesmente mais fácil e rápido consertar por conta própria do que ficar insistindo com o &lt;a href=&quot;https://en.wikipedia.org/wiki/Clanker&quot;&gt;clanker&lt;/a&gt; até ele fazer certo.&lt;/p&gt;

&lt;p&gt;Então, qual é o veredito? No geral, estou satisfeito, mas certamente há espaço para melhorias.&lt;/p&gt;

&lt;h2 id=&quot;o-que-você-deveria-fazer&quot;&gt;O Que Você Deveria Fazer?&lt;/h2&gt;
&lt;p&gt;Você pode fazer o que quiser, claro, mas se está buscando conselhos sobre como obter as melhores mensagens de commit possíveis do seu LLM de preferência, aqui vai: &lt;strong&gt;garanta que você dê contexto a ele.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Você não precisa usar scoped commits, embora eu recomende experimentar. Você não precisa usar minha skill &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit-message&lt;/code&gt;, nem nenhuma skill, se não quiser.&lt;/p&gt;

&lt;p&gt;Apenas garanta que, seja qual for o fluxo de trabalho que você use para gerar mensagens de commit, exista uma etapa em que você forneça o contexto, o “porquê” por trás da sua mudança. Essa é a informação mais importante que uma mensagem de commit deve conter, e seu pequeno robô assistente não vai conseguir isso sozinho. Ele precisa da sua ajuda.&lt;/p&gt;
</description>
        <pubDate>Wed, 12 Aug 2026 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/great-commit-messages-ai-era</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/great-commit-messages-ai-era</guid>
        
        <category>tutorial</category>
        
        <category>git</category>
        
        <category>ai</category>
        
        <category>llm</category>
        
        <category>claude</category>
        
        <category>version-control-system</category>
        
        <category>best-practices</category>
        
        
      </item>
    
      <item>
        <title>Operador LIKE do PostgreSQL: Um Guia Detalhado</title>
        <description>
&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    Info
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;&lt;em&gt;Nota editorial: escrevi esse post originalmente para o blog da CoderPad. Você pode &lt;a href=&quot;https://coderpad.io/blog/development/postgresql-like-operator-a-detailed-guide/&quot;&gt;conferir o original aqui, em inglês, no site deles&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Ao trabalhar com bancos de dados, precisar buscar valores que correspondam a um padrão é bem comum. Você pode querer achar todos os alunos que o sobrenome comece com uma determinada letra, ou atualizar todos os produtos cujo id contenha uma string específica. Se você usa PostgreSQL, vai usar o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; para isso.&lt;/p&gt;

&lt;p&gt;Se você quer aprender mais sobre o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; do PostgreSQL, chegou ao lugar certo, já que este post é totalmente dedicado a esse operador. Ao final do post, você vai ter aprendido:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;o que o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; do PostgreSQL faz, e por que você gostaria de usá-lo&lt;/li&gt;
  &lt;li&gt;como ele difere do operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; em diferentes bancos de dados&lt;/li&gt;
  &lt;li&gt;como ele difere do operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILIKE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mas só teoria sem prática iriam tornar esse post chato demais. Então, antes de encerrar, você vai ver exemplos do operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; na prática.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pré-requisitos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se você quiser acompanhar a parte prática do post, você vai precisar de:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;instância funcional do PostgreSQL instalada na sua máquina&lt;/li&gt;
  &lt;li&gt;conseguir se conectar a essa instância através de um cliente&lt;/li&gt;
  &lt;li&gt;ter ao menos um pouco de experiência com o banco de dados PostgreSQL e com a linguagem SQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;like-do-postgresql-fundamentos&quot;&gt;LIKE do PostgreSQL: Fundamentos&lt;/h2&gt;

&lt;p&gt;Com os pré-requisitos resolvidos, vamos começar cobrindo alguns fundamentos sobre o assunto de hoje.&lt;/p&gt;

&lt;h3 id=&quot;o-que-é-o-like-do-postgresql&quot;&gt;O Que É o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; do PostgreSQL?&lt;/h3&gt;

&lt;p&gt;O &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; do PostgreSQL é a implementação, feita pelo PostgreSQL, do operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; da linguagem SQL. Você usa o LIKE quando quer encontrar linhas nas quais uma ou mais colunas textuais correspondem a um determinado padrão. Na introdução, dei um exemplo: achar alunos cujo sobrenome comece com uma determinada letra. Então, vamos ver uma query real que faz exatamente isso usando o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; do PostgreSQL:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;students&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;M%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A query acima recupera algumas colunas da tabela &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;students&lt;/code&gt;, mas apenas as linhas que atendem à condição: o valor da coluna &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;last_name&lt;/code&gt; precisa começar com a letra “M”. Tem alguns pontos interessantes neste primeiro exemplo:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Você usa o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; na cláusula &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WHERE&lt;/code&gt; de uma query&lt;/li&gt;
  &lt;li&gt;Ele vai no mesmo lugar em que você colocaria qualquer operador de comparação, como “==”, “&amp;gt;”, “&amp;lt;”, e assim por diante&lt;/li&gt;
  &lt;li&gt;O caractere de porcentagem (%) é usado como um wildcard para corresponder a qualquer quantidade de caracteres&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E se você quisesse apenas os alunos cujo primeiro nome termina com “k”? Simples, basta trocar a letra e o wildcard de posição:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;students&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%k&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Outro exemplo: vamos buscar alunos cujo endereço de e-mail contenha a palavra “gmail”:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;students&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%gmail%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Isso mesmo: se você quer buscar valores que contenham uma string, basta envolver a string com sinais de porcentagem (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%&lt;/code&gt;).&lt;/p&gt;

&lt;h3 id=&quot;qual-a-diferença-entre-like-e-ilike-no-postgresql&quot;&gt;Qual a Diferença Entre LIKE e ILIKE no PostgreSQL?&lt;/h3&gt;

&lt;p&gt;Ao ler código PostgreSQL por aí, você pode encontrar queries que usam o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILIKE&lt;/code&gt; em vez do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; e ficar confuso. A diferença é que o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; diferencia maiúsculas de minúsculas (é &lt;em&gt;case sensitive&lt;/em&gt;). Já o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILIKE&lt;/code&gt; não diferencia (é &lt;em&gt;case insensitive&lt;/em&gt;) — daí o “i” no nome. Ele não distingue letras maiúsculas de minúsculas, e por isso você deveria usá-lo quando não se importa com a caixa das letras.&lt;/p&gt;

&lt;p&gt;Um detalhe importante a se ter em mente: o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILIKE&lt;/code&gt; não existe no SQL ANSI; na verdade, é uma extensão específica do PostgreSQL. Isso significa que usar o ILIKE torna seu código SQL menos portável, caso você precise trocar de banco de dados no futuro.&lt;/p&gt;

&lt;h2 id=&quot;like-do-postgresql-casos-de-uso-práticos&quot;&gt;LIKE do PostgreSQL: Casos de Uso Práticos&lt;/h2&gt;

&lt;p&gt;Tendo coberto o básico sobre o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; do PostgreSQL, vamos agora ver vários exemplos de uso. Vamos começar preparando o banco de dados para os testes.&lt;/p&gt;

&lt;h3 id=&quot;preparando-o-banco-de-dados&quot;&gt;Preparando o Banco de Dados&lt;/h3&gt;

&lt;p&gt;Usando seu cliente preferido, conecte-se à sua instância do PostgreSQL, garantindo que existe um banco de dados ao qual você pode se conectar para os testes.&lt;/p&gt;

&lt;p&gt;Vamos começar criando uma tabela e inserindo algumas linhas nela:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;              &lt;span class=&quot;nb&quot;&gt;SERIAL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;           &lt;span class=&quot;nb&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;          &lt;span class=&quot;nb&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;release_year&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;release_year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Abbey Road&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;The Beatles&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1969&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;release_year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Construção&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Chico Buarque&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1971&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;release_year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;The Dark Side of the Moon&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Pink Floyd&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1973&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;release_year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Reckless&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Bryan Adams&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1984&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;release_year&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Ryan Adams&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Ryan Adams&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2014&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;correspondendo-a-um-único-caractere&quot;&gt;Correspondendo a um Único Caractere&lt;/h3&gt;

&lt;p&gt;Como você viu, a tabela agora contém álbuns tanto do Bryan quanto do Ryan Adams. Isso não é coincidência. Primeiro, use a seguinte query para recuperar álbuns dos dois cantores:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%yan%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A query acima corresponde a todos os artistas que contenham a string “yan” em qualquer parte do nome. Veja como fica o resultado:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; id |   title    |   artist    | release_year 
----+------------+-------------+--------------
  4 | Reckless   | Bryan Adams |         1984
  5 | Ryan Adams | Ryan Adams  |         2014
(2 rows)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;O operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; oferece um wildcard adicional, o caractere de sublinhado (_), que corresponde a um único caractere. Dessa forma, é possível reescrever a query de modo que apenas Ryan Adams seja retornado:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;_yan%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;E aqui, novamente, está o resultado:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; id |   title    |   artist   | release_year 
----+------------+------------+--------------
  5 | Ryan Adams | Ryan Adams |         2014
(1 row)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;correspondências-negativas&quot;&gt;Correspondências Negativas&lt;/h3&gt;

&lt;p&gt;Ao trabalhar com tabelas de banco de dados, muitas vezes você precisa recuperar dados que &lt;em&gt;não&lt;/em&gt; correspondam a um certo padrão. Para isso, você pode usar o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NOT LIKE&lt;/code&gt;. Por exemplo, vamos buscar apenas artistas cujo nome não comece com “The”:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;The%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Já que o único artista que começa com “The” é The Beatles, ele não será retornado pela query acima.&lt;/p&gt;

&lt;h3 id=&quot;correspondência-sem-diferenciar-maiúsculas-de-minúsculas&quot;&gt;Correspondência Sem Diferenciar Maiúsculas de Minúsculas&lt;/h3&gt;

&lt;p&gt;Como falei antes, o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILIKE&lt;/code&gt; é uma extensão especial do PostgreSQL para o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; que faz correspondências sem diferenciar maiúsculas de minúsculas. Vamos ver isso na prática. Primeiro, vamos usar o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; para obter todos os artistas que contenham um “A” maiúsculo:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%A%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Apenas “Bryan Adams” e “Ryan Adams” são retornados, o que faz sentido:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; id |   title    |   artist    | release_year 
----+------------+-------------+--------------
  4 | Reckless   | Bryan Adams |         1984
  5 | Ryan Adams | Ryan Adams  |         2014
(2 rows)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agora vamos substituir o operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LIKE&lt;/code&gt; pelo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILIKE&lt;/code&gt; e rodar a query novamente:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ILIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%A%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; id |   title    |    artist     | release_year 
----+------------+---------------+--------------
  1 | Abbey Road | The Beatles   |         1969
  2 | Construção | Chico Buarque |         1971
  4 | Reckless   | Bryan Adams   |         1984
  5 | Ryan Adams | Ryan Adams    |         2014
(4 rows)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agora, todos os artistas são retornados, exceto Pink Floyd.&lt;/p&gt;

&lt;h3 id=&quot;escapando-os-wildcards&quot;&gt;Escapando os Wildcards&lt;/h3&gt;

&lt;p&gt;Para este exemplo, vamos atualizar duas linhas:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;The%Beatles&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Chico_Buarque&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agora, digamos que queremos recuperar álbuns de artistas cujo nome contenha um sinal de porcentagem ou um sublinhado:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%%%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%_%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Como você provavelmente já imaginou, nenhuma das duas queries funciona: ambas retornam todas as linhas. Felizmente, existe uma forma de contornar esse problema: é possível escapar um wildcard para usá-lo como um caractere normal. Basta colocar uma barra invertida antes do caractere problemático:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\%&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;E aqui está o resultado:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; id |   title    |    artist     | release_year 
----+------------+---------------+--------------
  1 | Abbey Road | The Beatles   |         1969
(1 rows)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;O mesmo funcionaria para o caractere de sublinhado. Mas, antes de encerrar, vamos complicar as coisas só um pouco mais — porque sim.&lt;/p&gt;

&lt;p&gt;Primeiro, vamos atualizar a linha do “Abbey Road” mais uma vez:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;The&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\B&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;eatles&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agora, para usar o LIKE e recuperar uma linha que contenha o caractere de barra invertida, você teria que escrever esta query:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;%&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Você precisa escapar o caractere de escape. Não é tão terrível assim, mas talvez você queira escrever uma versão mais legível. Se for esse o caso, é possível escolher um caractere diferente como caractere de escape: basta usar a cláusula &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESCAPE&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;artist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%$&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\%&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ESCAPE&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;$&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Com a cláusula &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESCAPE&lt;/code&gt;, você pode escolher um caractere diferente para servir de escape. Dessa forma — pelo menos na minha opinião — a query resultante fica mais explícita quanto à forma como escapa o wildcard.&lt;/p&gt;

&lt;h2 id=&quot;conclusão-like-do-postgresql--aprenda-e-aproveite&quot;&gt;Conclusão: LIKE do PostgreSQL — Aprenda e Aproveite&lt;/h2&gt;

&lt;p&gt;Neste post, você aprendeu sobre o operador LIKE no PostgreSQL: o que é, para que serve, e como funciona, através de vários exemplos. Como você viu, o funcionamento do operador é bem simples assim que você entende como os wildcards funcionam. Também percorremos alguns exemplos de uso, como correspondência a um único caractere e a realização de correspondências negativas.&lt;/p&gt;

&lt;p&gt;Para onde ir agora? Para começar, continue aprendendo sobre correspondência de padrões no PostgreSQL. Aqui vão algumas sugestões de tópicos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIMILAR TO&lt;/code&gt;, uma cláusula mais recente&lt;/li&gt;
  &lt;li&gt;a função &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;substring()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;a função &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;regexp_like()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obrigado pela leitura, até a próxima!&lt;/p&gt;
</description>
        <pubDate>Tue, 14 Jul 2026 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/guia-operador-like-postgresql</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/guia-operador-like-postgresql</guid>
        
        <category>databases</category>
        
        <category>postgresql</category>
        
        <category>sql</category>
        
        
      </item>
    
      <item>
        <title>Construindo o git em Go do zero - Parte 2</title>
        <description>&lt;p&gt;Bem-vindo de volta à minha jornada de construir o git do zero em Go, com o objetivo de aprender mais sobre os dois. Se você não sabe do que estou falando, leia &lt;a href=&quot;/pt/implementando-git-em-go&quot;&gt;o primeiro post&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;já-faz-um-tempo&quot;&gt;Já faz um tempo&lt;/h2&gt;

&lt;p&gt;Eu postei o primeiro post em 9 de março. O que eu fiquei fazendo, e por que demorei tanto para continuar a série?&lt;/p&gt;

&lt;p&gt;A resposta é o que você provavelmente já sabe: eu sou um adulto ocupado e não tenho muito tempo. Além disso, outros projetos pessoais também demandam atenção.&lt;/p&gt;

&lt;p&gt;Mas chega de desculpa. Vamos falar sobre o que consegui implementar desde a última atualização.&lt;/p&gt;

&lt;h2 id=&quot;comandos-plumbing-vs-porcelain&quot;&gt;Comandos Plumbing vs Porcelain&lt;/h2&gt;

&lt;p&gt;Antes de entrar em detalhes sobre o que implementei, preciso falar rapidinho sobre uma distinção que existe entre os comandos do git.&lt;/p&gt;

&lt;p&gt;Quando você pensa em comandos do git, o que provavelmente vem à mente são coisas como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git init&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;, e por aí vai. E mesmo isso só vale se você realmente usa a linha de comando. Muita gente usa interfaces gráficas para tudo e nunca aprende nem os comandos básicos.&lt;/p&gt;

&lt;p&gt;Esses são os chamados comandos “porcelain”. São os comandos de alto nível, voltados para os usuários finais do git, como você e eu.&lt;/p&gt;

&lt;p&gt;Existe outra camada de comandos, conhecida como comandos “plumbing”. Os comandos plumbing são os de baixo nível, que realizam a manipulação de dados que permite aos comandos de alto nível fazer o seu trabalho.&lt;/p&gt;

&lt;p&gt;Recentemente, estive implementando alguns desses comandos plumbing que servem de fundação para grande parte do que o git faz. São eles: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;entendendo-o-hash-object-e-o-cat-file&quot;&gt;Entendendo o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt; e o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Vou falar rapidamente sobre o que esses comandos fazem antes de contar minha experiência. O &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt; é o comando usado para salvar dados como um blob (binary large object) dentro de um repositório git. Você passa um texto para o comando, ele salva um objeto com aquela informação e te devolve um hash SHA1.&lt;/p&gt;

&lt;p&gt;O &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt; faz o oposto. Você passa um hash de objeto e ele retorna o conteúdo (ou o tamanho, ou o tipo, dependendo de como você o chama).&lt;/p&gt;

&lt;h3 id=&quot;calculando-o-hash-do-seu-primeiro-objeto&quot;&gt;Calculando o hash do seu primeiro objeto&lt;/h3&gt;

&lt;p&gt;Quer testar? Execute o seguinte comando:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;hi | git hash-object &lt;span class=&quot;nt&quot;&gt;--stdin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Você deverá ver exatamente este hash como resultado: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;45b983be36b73c0788dc9cbcb76cbb80fc7bb057&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    Info
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Se você está no Linux ou em outro sistema Unix, você provavelmente viu  o resultado acima. O mesmo vale para Windows usando o Git Bash. Mas se você está no Windows usando o prompt de comando ou o PowerShell, o resultado provavelmente foi diferente. Isso acontece por causa das diferenças de terminadores de linha entre os sistemas.&lt;/p&gt;

  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;O que aconteceu aqui é que o git calculou um hash para a string “hi” e o retornou para você. Usamos a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--stdin&lt;/code&gt; para poder passar o conteúdo pela entrada padrão.&lt;/p&gt;

&lt;p&gt;Porém, nada foi salvo em disco. Para de fato gravar os dados, você precisa usar uma versão diferente do comando, e desta vez dentro de um repositório.&lt;/p&gt;

&lt;h3 id=&quot;salvando-um-objeto&quot;&gt;Salvando um objeto&lt;/h3&gt;

&lt;p&gt;Vá para algum lugar, crie uma nova pasta e inicialize um repositório nela:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;testing-commands
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;testing-commands
git init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pronto. Agora você pode fazer o seguinte:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;hi | git hash-object &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--stdin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;O comando é parecido com o anterior, mas repare na flag extra &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt;. Ela significa &lt;strong&gt;write&lt;/strong&gt; (escrever) e é o que faz o git salvar o conteúdo em um arquivo. Você ainda receberá o hash SHA1 como resposta, igual a antes, mas agora um novo objeto blob foi salvo em algum lugar. Quer ver?&lt;/p&gt;

&lt;p&gt;Vá até a pasta onde o repositório foi criado, dentro de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testing-commands&lt;/code&gt;. Use um explorador de arquivos, não a linha de comando. Ative as configurações necessárias para visualizar pastas e arquivos ocultos. Você verá uma pasta &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Entre nessa pasta e você verá basicamente esta estrutura:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;├───hooks
├───info
├───objects   
└───refs
- config
- description
- HEAD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;description&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; são arquivos; os outros são pastas. Entre na pasta &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt;. Você provavelmente vai encontrar as pastas &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pack&lt;/code&gt; lá. Elas não importam pra gente.&lt;/p&gt;

&lt;p&gt;O que nos interessa aqui é uma pasta cujo nome tem dois caracteres. Se você executou os comandos acima no Linux ou no Git Bash do Windows, ela deve ser &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;45&lt;/code&gt;. Caso contrário, deve começar com os dois primeiros caracteres do hash que você recebeu ao rodar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;echo hi | git hash-object -w --stdin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Entre nessa pasta. Dentro, você vai encontrar um arquivo cujo nome é formado pelo restante dos caracteres do hash. No meu caso, vejo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b983be36b73c0788dc9cbcb76cbb80fc7bb057&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Esse é o seu blob.&lt;/strong&gt; Esse arquivo é o objeto que o git salvou quando você executou o comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt; com a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;lendo-objetos-de-volta&quot;&gt;Lendo objetos de volta&lt;/h3&gt;

&lt;p&gt;Tente abrir o arquivo do blob no seu editor de texto favorito. O arquivo abre normalmente, mas o conteúdo é puro lixo que não dá pra ler. Isso porque ele está em formato binário comprimido, não em texto puro.&lt;/p&gt;

&lt;p&gt;O que o git faz, em sequência, é o seguinte:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Cria um cabeçalho concatenando a palavra “blob”, um espaço e o tamanho do conteúdo em bytes. Por exemplo, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blob 2&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Concatena isso com um &lt;a href=&quot;https://pt.wikipedia.org/wiki/Caractere_nulo&quot;&gt;caractere nulo&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Concatena o conteúdo real em seguida. No nosso exemplo, “hi”.&lt;/li&gt;
  &lt;li&gt;Gera o SHA1 da string completa.&lt;/li&gt;
  &lt;li&gt;Se você não usou a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt;, o git retorna o SHA1 e para por aí.&lt;/li&gt;
  &lt;li&gt;Caso tenha usado a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt;, o git comprime a string completa (cabeçalho + byte nulo + conteúdo).&lt;/li&gt;
  &lt;li&gt;Pega os dois primeiros caracteres do hash SHA1 e cria um diretório com esse nome dentro de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Por fim, cria um arquivo dentro dessa pasta, com o nome formado pelos caracteres restantes do hash SHA1, e grava nesse arquivo o conteúdo comprimido com zlib.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para ler esses dados de volta, você usa o comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt; com uma de suas flags. Para ler o conteúdo, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file -p&lt;/code&gt;, onde &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-p&lt;/code&gt; significa “pretty print”:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git cat-file &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ao executar o comando acima, você recebe “hi” de volta. Você também pode usar a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-t&lt;/code&gt; para obter o tipo do objeto, ou &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-s&lt;/code&gt; para retornar seu tamanho em bytes:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git cat-file &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
blob

git cat-file &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;implementação-no-go-gitter&quot;&gt;Implementação no Go-Gitter&lt;/h2&gt;

&lt;p&gt;Agora que você entende o que esses dois comandos fazem, vamos falar sobre como os implementei no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go-gitter&lt;/code&gt;, começando pelo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;implementando-o-hash-object&quot;&gt;Implementando o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Meu primeiro passo foi implementar a versão mais básica do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt;, sem a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt;. O comando conseguiria exibir o hash SHA1 de um texto passado como argumento, mas ainda sem salvar nada em disco.&lt;/p&gt;

&lt;p&gt;Como você pode ver no &lt;a href=&quot;https://github.com/carlosschults/go-gitter/commit/3ae9cc58f32059cda6091aa27dbab4507cebbca7&quot;&gt;commit&lt;/a&gt;, o código está longe de ser um exemplo de código limpo. Ele mistura o parsing de argumentos com a lógica real no mesmo arquivo. Naquele ponto, eu ainda nem tinha criado funções separadas para cada comando, mas fiz isso depois.&lt;/p&gt;

&lt;p&gt;A parte do código que realiza o hash em si acabou sendo bem simples, assim que entendi qual deveria ser o formato:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;blob %s%c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strconv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Itoa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sha1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hashedData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hashedString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EncodeToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hashedData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hashedString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Como você pode ver, criamos o cabeçalho concatenando a palavra “blob” mais um espaço com o tamanho do conteúdo e depois o caractere nulo, representado aqui pelo inteiro zero. Em seguida, hasheamos tudo, codificamos como string e imprimimos.&lt;/p&gt;

&lt;p&gt;Precisei pesquisar um pouco para encontrar as bibliotecas necessárias e a sintaxe do Go, já que as regras que eu criei pra mim proíbem o uso de LLMs para geração de código, mas acabou dando certo.&lt;/p&gt;

&lt;p&gt;No &lt;a href=&quot;https://github.com/carlosschults/go-gitter/commit/8b08cb93545f3966b1485989ce67501e1a5ff3ba&quot;&gt;commit seguinte&lt;/a&gt;, adicionei suporte à flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt;. Nesse ponto, como você pode ver, criei uma função para o comando.&lt;/p&gt;

&lt;p&gt;A diferença não é grande. O que acrescentei foi um parsing de argumentos bem simples para identificar se o conteúdo deve ser gravado em disco.&lt;/p&gt;

&lt;p&gt;Então, o código que efetivamente faz a gravação:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;saveFile&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// cria o diretório para o blob&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mkdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.git/objects/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;folderName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModePerm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// comprime o conteúdo com zlib e salva o arquivo&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zlib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WriteFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.git/objects/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;folderName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0666&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Demorei um pouco para acertar. Em grande parte porque, em determinado momento, eu estava entendendo completamente errado o que o git faz. Achei que deveria comprimir e salvar o &lt;em&gt;hash&lt;/em&gt; que calculei. Sim, eu sei, não faz sentido nenhum, mas o que posso dizer?&lt;/p&gt;

&lt;p&gt;Depois que entendi o fluxo correto, fazer funcionar foi principalmente uma questão de descobrir como usar a compressão zlib. O Google e a documentação resolveram, como nos bons tempos.&lt;/p&gt;

&lt;h3 id=&quot;implementando-o-cat-file&quot;&gt;Implementando o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;O &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt; foi mais fácil de implementar, porque é essencialmente o caminho inverso. A partir de um hash, localizar o arquivo correspondente, descomprimir o arquivo e ler o conteúdo.&lt;/p&gt;

&lt;p&gt;Desta vez, criei uma função dedicada para o novo comando desde o início, como pode ser visto no &lt;a href=&quot;https://github.com/carlosschults/go-gitter/commit/81c9f03e1ca76a483335876b42637833f8a0a524&quot;&gt;primeiro commit&lt;/a&gt;. Esse commit implementa apenas a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-p&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Abaixo está uma versão resumida do código desse commit, sem o boilerplate da função e também sem o tratamento de erros:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;folderName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fileName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fullPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.git/objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;folderName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fullPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zlib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;uncompressedContents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;contentsWithoutHeader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uncompressedContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contentsWithoutHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A variável &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt; é o SHA1 recebido pelo comando. A partir dela, extraímos o nome do diretório e do arquivo, que usamos para montar o caminho completo, ler o conteúdo do arquivo e descomprimi-lo.&lt;/p&gt;

&lt;p&gt;Por fim, faço um split da string pelo caractere nulo e retorno a segunda parte, que é tudo o que vem depois do cabeçalho.&lt;/p&gt;

&lt;p&gt;O &lt;a href=&quot;https://github.com/carlosschults/go-gitter/commit/56d10d3cb2ad0baa217a357b8f5d204eb5970620&quot;&gt;commit seguinte&lt;/a&gt; implementa as flags restantes. Não vou percorrer linha por linha, já que a parte importante é bem simples:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uncompressedContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-p&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-t&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-s&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para os programadores Go que estão lendo isso: eu sei que esse código não seja o mais bonito e idiomático que você já viu, e prometo que, conforme for aprendendo mais sobre a linguagem, vou refatorar. A prioridade no momento era fazer funcionar.&lt;/p&gt;

&lt;h2 id=&quot;o-que-aprendi-até-agora&quot;&gt;O que aprendi até agora&lt;/h2&gt;

&lt;p&gt;O objetivo deste projeto é aprender a linguagem Go e também mais sobre a implementação do Git. Então, o que aprendi sobre os dois ao completar esses dois comandos?&lt;/p&gt;

&lt;p&gt;Primeiro, o lado do Git. Posso dizer que me surpreendeu a simplicidade com que o git salva objetos. É realmente só o tipo do objeto, um espaço, o tamanho, um caractere nulo como delimitador e o conteúdo. Eu entendia, em alto nível, como o git armazenava objetos, mas implementar de fato me deu uma nova apreciação pela simplicidade e elegância do design.&lt;/p&gt;

&lt;p&gt;E sobre o lado do Go? De maneira geral, estou gostando muito. Eu gosto da legibilidade da linguagem. Acho que até alguém com zero experiência em Go conseguiria ler este código e ao menos entender a essência, desde que já seja programador.&lt;/p&gt;

&lt;p&gt;Gosto também do fato de Go ser opinativo. Por exemplo, se você tem um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt;, precisa usar as chaves. Do contrário, o código não compila. Isso elimina mais uma coisa para os programadores brigarem, reuniões sobre padrões de código, regras de linter. Simplifica a vida.&lt;/p&gt;

&lt;p&gt;Um aspecto que não gosto é o tratamento de erros. Ter aqueles &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; verificando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;err&lt;/code&gt; em todo lugar polui o código. Em C#/.NET, quando ocorre um erro que deveria ser absolutamente impossível, eu só deixo a exceção subir até o middleware de tratamento de exceções no nível mais alto, onde ela é logada e o usuário recebe uma mensagem com o nível adequado de detalhes.&lt;/p&gt;

&lt;p&gt;Talvez exista alguma forma idiomática de fazer algo assim em Go também, mas por enquanto não conheço. Fora isso, estou gostando muito da linguagem.&lt;/p&gt;

&lt;h2 id=&quot;o-que-vem-a-seguir&quot;&gt;O que vem a seguir?&lt;/h2&gt;

&lt;p&gt;Para o próximo passo vou implementar outro comando plumbing chamado &lt;a href=&quot;https://git-scm.com/docs/git-update-index&quot;&gt;update-index&lt;/a&gt;. Ele é necessário para eu poder stagear mudanças e eventualmente fazer commits.&lt;/p&gt;

&lt;p&gt;Se quiser experimentar o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go-gitter&lt;/code&gt;, instale assim:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;github.com/carlosschults/go-gitter/ggt@latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Depois é só usar os comandos assim:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;hi | ggt hash-object &lt;span class=&quot;nt&quot;&gt;--stdin&lt;/span&gt;
ggt cat-file &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Você deve conseguir fazer o hash de algo com o git de verdade e ler com o go-gitter, e vice-versa.&lt;/p&gt;

&lt;p&gt;Obrigado por ler, e até a próxima atualização.&lt;/p&gt;
</description>
        <pubDate>Fri, 29 May 2026 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/construindo-git-em-go-parte2</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/construindo-git-em-go-parte2</guid>
        
        <category>projetos</category>
        
        <category>git</category>
        
        <category>go</category>
        
        <category>go-gitter</category>
        
        <category>controle-de-versao</category>
        
        
      </item>
    
      <item>
        <title>Suas Mensagens de Commit São Um Lixo. Vou Te Ajudar a Melhorar</title>
        <description>&lt;p&gt;Suas mensagens de commit são um lixo. Na melhor das hipóteses, elas são inúteis. Mas geralmente, elas são piores do que nada.
Eu não digo isso pra ser babaca. Na verdade, é o contrário. Eu quero te ajudar.&lt;/p&gt;

&lt;p&gt;Se você sabe que você é exceção pra isso, você pode parar de ler. É sério, fecha a aba e vai pro YouTube. Pronto, te dei alguns minutos de volta, de nada.&lt;/p&gt;

&lt;p&gt;Se você ainda tá aqui, então você sabe que tem um problema. Como eu dizia, suas mensagens de commit não servem pra nada.
Não fique ofendido. Isso não é culpa só sua. É bem provável que ninguém nunca te ensinou como escrever boas mensagens de commit, ou nem o porquê disso ser importante. E escrever é realmente muito difícil.&lt;/p&gt;

&lt;p&gt;A boa notícia é que agora você finalmente tem alguém pra te ajudar. Nesse post, eu vou explicar tudo que você precisa saber sobre mensagens de commit horríveis, e o que fazer pra escrever as que não são horríveis.&lt;/p&gt;

&lt;h2 id=&quot;suas-mensagens-de-commit-são-um-lixo-porque&quot;&gt;Suas Mensagens de Commit São um Lixo Porque…&lt;/h2&gt;

&lt;p&gt;Por que a maioria das mensagens de commit é tão ruim? Na minha experiência, os motivos se resumem ao que vou falar agora. Vale lembrar que não tem nada de científico ou baseado em dados aqui. É tudo baseado na minha experiência pessoal.&lt;/p&gt;

&lt;h3 id=&quot;você-só-liga-pra-código&quot;&gt;…Você Só Liga pra Código&lt;/h3&gt;

&lt;p&gt;Se você é como a maioria dos devs, você só — ou quase só — liga pra codar. É onde a diversão mora, e tudo o mais você vê como perda de tempo.
Eu sei também que você provavelmente está sob muita pressão pra performar, pra entregar o máximo de valor o mais rápido possível. Então o que você mais quer é terminar o que está fazendo, mergar o PR e então pegar outro ticket do Jira/Azure/Linear pra começar a implementar.&lt;/p&gt;

&lt;p&gt;O que acaba acontecendo é que tudo que não é código é tratado como detalhe secundário e não recebe a devida atenção. Isso inclui testes, documentação, preparar uma revisão da feature implementada pra retrospectiva semanal e, claro, escrever mensagens de commit e descrições de PR.&lt;/p&gt;

&lt;h3 id=&quot;às-vezes-você-não-entende-o-que-está-fazendo&quot;&gt;…Às Vezes Você Não Entende o Que Está Fazendo&lt;/h3&gt;

&lt;p&gt;Boas mensagens de commit — e boa documentação em geral — devem focar no &lt;em&gt;porquê&lt;/em&gt; das coisas. Qual é a motivação por trás das suas mudanças? Qual é o problema que você está tentando resolver, por que vale a pena resolvê-lo, de que forma isso ajuda seu time e sua empresa?&lt;/p&gt;

&lt;p&gt;Pode parecer loucura que um programador comece a trabalhar numa tarefa que não entende completamente. Mas eu já fiz isso, e aposto que você também. E claro, como você vai explicar o porquê de uma mudança se nem você mesmo entende direito?&lt;/p&gt;

&lt;h3 id=&quot;escrever-é-difícil&quot;&gt;…Escrever é Difícil&lt;/h3&gt;

&lt;p&gt;Como Phil Karlton disse uma vez&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, &lt;a href=&quot;https://martinfowler.com/bliki/TwoHardThings.html&quot;&gt;só existem duas coisas difíceis em ciência da computação&lt;/a&gt;, e dar nome às coisas é uma delas.&lt;/p&gt;

&lt;p&gt;Se você parar pra pensar, “dar nome às coisas” é uma forma de escrever. Um subconjunto da escrita, digamos assim. Então sim, escrever mensagens de commit é difícil porque escrever, em geral, é difícil.&lt;/p&gt;

&lt;h3 id=&quot;ninguém-te-ensinou&quot;&gt;…Ninguém Te Ensinou&lt;/h3&gt;

&lt;p&gt;Acho que a formação de desenvolvedores frequentemente falha em ensinar muita coisa importante que você realmente vai precisar como engenheiro de software. Tratamento de erros de verdade é um exemplo.&lt;/p&gt;

&lt;p&gt;Tudo bem, eles vão te ensinar a mecânica de como um try-catch-finally funciona, mas raramente vão te ensinar quando capturar uma exceção, quando não capturar, quando lançar uma exceção, quando logar ou não, e assim por diante.&lt;/p&gt;

&lt;p&gt;E escrever mensagens de commit é uma dessas coisas.&lt;/p&gt;

&lt;h3 id=&quot;o-github-te-ensinou-maus-hábitos&quot;&gt;…O GitHub Te Ensinou Maus Hábitos&lt;/h3&gt;

&lt;p&gt;Vamos deixar uma coisa clara: eu uso o GitHub todo dia e gosto muito. O GitHub é o &lt;a href=&quot;https://pt.wikipedia.org/wiki/Aplicativo_matador&quot;&gt;aplicativo matador/killer app&lt;/a&gt; do Git, e o Git não teria tido o mesmo nível de adoção sem ele.&lt;/p&gt;

&lt;p&gt;Dito isso, acredito que a popularidade do GitHub e dos pull requests fez as pessoas se importarem mais com os PRs do que com os commits individuais. E faz sentido: pull requests suportam discussões que ficam como artefatos históricos do projeto, suportam anexos, texto rico e tudo mais.&lt;/p&gt;

&lt;p&gt;Então faz sentido que algumas pessoas não se esforcem muito pra escrever boas mensagens de commit, argumentando que podem escrever descrições ricas no PR.&lt;/p&gt;

&lt;p&gt;Claro que o que acaba acontecendo frequentemente é que elas não escrevem as descrições de PR também!&lt;/p&gt;

&lt;h3 id=&quot;a-flag--m-do-git-te-viciou&quot;&gt;…A Flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; do Git Te Viciou&lt;/h3&gt;

&lt;p&gt;Acho que a maioria dos programadores nem sabe que mensagens de commit podem ter um corpo com várias linhas. E a culpada aqui é a forma como a maioria das pessoas ensina o comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Alguma mensagem&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sem nem mencionar que a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; é só uma conveniência pra quando você tem uma mensagem de uma linha, o que deveria ser a exceção, não a regra.&lt;/p&gt;

&lt;h3 id=&quot;você-não-tem-higiene-de-commits&quot;&gt;…Você Não Tem Higiene de Commits&lt;/h3&gt;

&lt;p&gt;Escrever mensagens de commit que não são lixo faz parte de algo mais amplo que algumas pessoas chamam de “higiene de controle de versão.”&lt;/p&gt;

&lt;p&gt;É exatamente o que parece: não seja porco na hora de escrever código.&lt;/p&gt;

&lt;p&gt;Às vezes você tem dificuldade pra escrever uma mensagem de commit porque trabalha de forma bagunçada. Se suas mudanças são uma salada de correções de bug, refatorações, código morto e ideias de implementação pela metade, claro que você vai ter problema pra escrever uma mensagem descritiva e útil.&lt;/p&gt;

&lt;p&gt;Isso costuma ser causado por falta de domínio do Git. Se você não domina ferramentas como stash, reset, rebase interativo e outras, é mais provável que você transforme seu trabalho num caos.&lt;/p&gt;

&lt;h2 id=&quot;taxonomia-das-mensagens-de-commit-ruins&quot;&gt;Taxonomia das Mensagens de Commit Ruins&lt;/h2&gt;

&lt;p&gt;Descobri que mensagens de commit ruins se encaixam em algumas categorias. Vou cobrir algumas delas agora.&lt;/p&gt;

&lt;h3 id=&quot;a-mensagem-de-uma-linha-quase-inútil&quot;&gt;A Mensagem de Uma Linha Quase Inútil&lt;/h3&gt;

&lt;p&gt;Essa é a mensagem de uma linha que dá uma explicação superficial do que foi mudado. Eu chamo de “quase” inútil porque pelo menos o resumo é preciso.&lt;/p&gt;

&lt;p&gt;Mas aí ela falha em dar qualquer contexto adicional. Fico com perguntas como:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Qual foi o problema que originou essa mudança?&lt;/li&gt;
  &lt;li&gt;Por que o autor considerou essa a melhor forma de resolver o problema?&lt;/li&gt;
  &lt;li&gt;Existe algum issue ou ticket associado a esse trabalho?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alguns exemplos, com meus comentários:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Added new index to table # que índice? que tabela? com qual propósito?
Enable EF Core execution strategy # o que é essa tal &quot;strategy&quot;? por que você teve que habilitar?
Added Required attribute to model # qual model? isso não é uma breaking change que vai afetar os usuários atuais?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;a-mensagem-de-uma-linha-inútil&quot;&gt;A Mensagem de Uma Linha Inútil&lt;/h3&gt;

&lt;p&gt;A mensagem de uma linha inútil é… bem, como a quase inútil, mas completamente inútil.&lt;/p&gt;

&lt;p&gt;Os exemplos não precisam de mais comentários:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;changes
ui
not working
more changes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Quer dizer, no momento em que você escreve “changes” como mensagem de commit, você poderia simplesmente escrever “batata”. Ou contar uma piada. Seria igualmente inútil, mas pelo menos poderia ter graça.&lt;/p&gt;

&lt;h3 id=&quot;só-a-referência-do-sistema-de-tickets&quot;&gt;Só a Referência do Sistema de Tickets&lt;/h3&gt;

&lt;p&gt;É quando as pessoas colocam apenas o id de um issue/ticket/card do sistema de gerenciamento, e nada mais. Alguns exemplos:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;JIRA-42
AZ-2234
&lt;span class=&quot;c&quot;&gt;#125&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Acho que essa categoria consegue ser ao mesmo tempo mais útil e mais irritante do que as anteriores. Sim, é mais útil, já que posso sempre ir ao sistema de tickets, procurar o issue, e aprender mais sobre o trabalho. Claro, nada garante que o commit vai conter apenas mudanças relacionadas ao issue em questão, mas isso é conversa pra outro momento.&lt;/p&gt;

&lt;p&gt;É mais irritante também porque obriga o leitor a parar e ir a outro lugar pra entender o contexto daquela mudança. Não sei você, mas eu prefiro aprender o motivo por trás de um commit pelo próprio commit, como &lt;del&gt;Deus&lt;/del&gt;Linus quis.&lt;/p&gt;

&lt;p&gt;Além do incômodo, existe um risco maior aqui: a possibilidade de que, um dia, sua empresa migre do sistema de tickets atual e você fique sem aquelas descrições. Todas as empresas em que trabalhei como desenvolvedor fizeram pelo menos uma migração dessas, e tenho certeza que você já passou por pelo menos uma também.&lt;/p&gt;

&lt;h3 id=&quot;a-mensagem-de-uma-linha-enganosa&quot;&gt;A Mensagem de Uma Linha Enganosa&lt;/h3&gt;

&lt;p&gt;Às vezes você tem uma mensagem que parece inofensiva, como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add PrintHtmlOutput() method&lt;/code&gt;. Aí você vai ver as mudanças e elas também incluem uma breaking change em um endpoint ou alteram a forma como a aplicação interage com o banco de dados.&lt;/p&gt;

&lt;h2 id=&quot;você-vai-escrever-boas-mensagens-de-commit-quando&quot;&gt;Você Vai Escrever Boas Mensagens de Commit Quando…&lt;/h2&gt;

&lt;p&gt;Agora você entende por que escreve mensagens ruins, e &lt;em&gt;como&lt;/em&gt; elas são ruins. Pronto pra aprender a melhorar?&lt;/p&gt;

&lt;h3 id=&quot;escrever-suas-mensagens-em-inglês&quot;&gt;…Escrever Suas Mensagens Em Inglês&lt;/h3&gt;
&lt;p&gt;Um dos posts mais visitados desse blog discute se &lt;a href=&quot;/pt/programar-portugues-ou-ingles/&quot;&gt;devemos escrever código em português ou inglês&lt;/a&gt;. Eu considero que fiz bons argumentos, mostrando os prós e constras de ambos os lados e deixando meu posicionamento bem claro.&lt;/p&gt;

&lt;p&gt;Ainda assim, alguns leitores me acusaram de ficar em cima do muro.&lt;/p&gt;

&lt;p&gt;Dessa vez, então, vou falar sem sombra de dúvida: &lt;strong&gt;ESCREVA SUAS MENSAGENS DE COMMIT EM INGLÊS.&lt;/strong&gt; É simplesmente o padrão do mercado, e o quanto antes você se acostumar com isso, melhor.&lt;/p&gt;

&lt;p&gt;E é por isso, inclusive, que os exemplos de mensagem de commit deste post estão todos em inglês. Eu escrevi o post originalmente em inglês e agora estou traduzindo para português, mas deixei as mensagens em inglês de propósito mesmo, por causa desse ponto.&lt;/p&gt;

&lt;h3 id=&quot;parar-de-escrever-mensagens-de-uma-linha&quot;&gt;…Parar de Escrever Mensagens de Uma Linha&lt;/h3&gt;

&lt;p&gt;Mensagens de uma linha são ótimas quando o escopo da mudança é pequeno. Se o seu commit só corrige um typo, então &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix typo&lt;/code&gt; é uma mensagem de commit válida. Mas na maioria das vezes os commits contêm muito mais mudanças, e nesses casos escrever uma mensagem de uma linha é uma oportunidade perdida de criar uma documentação duradoura.&lt;/p&gt;

&lt;p&gt;Então, por favor, pare de usar a flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; na hora de commitar. Escreva um corpo adequado com mais detalhes na maioria das suas mensagens.&lt;/p&gt;

&lt;h3 id=&quot;começar-pelo-o-quê-expandir-com-o-por-quê-e-o-como&quot;&gt;…Começar pelo “O Quê”, Expandir com o “Por Quê” e o “Como”&lt;/h3&gt;

&lt;p&gt;Agora você sabe que deve escrever um resumo e um corpo na maioria das suas mensagens de commit. O que colocar em cada um?&lt;/p&gt;

&lt;p&gt;Simples: comece com o resumo, descrevendo &lt;em&gt;o que&lt;/em&gt; você fez. Seja descritivo, mas conciso.&lt;/p&gt;

&lt;p&gt;No corpo, descreva qual é o problema que você está tentando resolver, ou o motivo que motivou a mudança. Em seguida, explique como você resolveu, mas de forma macro. Não entre em muito detalhe, porque lembre-se que seu leitor sempre pode ver o diff.&lt;/p&gt;

&lt;p&gt;Se necessário, adicione mais informações, como:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;trade-offs envolvidos na sua decisão&lt;/li&gt;
  &lt;li&gt;alternativas que você considerou mas decidiu não usar&lt;/li&gt;
  &lt;li&gt;links de referência para termos que possam ser desconhecidos (por exemplo, um link para um artigo da Wikipedia, ou para o &lt;a href=&quot;https://refactoring.com/catalog/&quot;&gt;Catálogo de Refatorações&lt;/a&gt; do Martin Fowler)&lt;/li&gt;
  &lt;li&gt;links de referência para a solução que você aplicou (por exemplo, um link para uma resposta no Stack Overflow)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;seguir-a-regra-do-5072&quot;&gt;…Seguir a Regra do 50/72&lt;/h3&gt;

&lt;p&gt;A regra do 50/72 é o mais próximo que temos de um padrão quando se trata de mensagens de commit. Foi &lt;a href=&quot;https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html&quot;&gt;proposta pela primeira vez por Tim Pope&lt;/a&gt;&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; e funciona assim:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Comece com um resumo, com a primeira letra maiúscula, com no máximo 50 caracteres&lt;/li&gt;
  &lt;li&gt;Adicione uma linha em branco&lt;/li&gt;
  &lt;li&gt;Em seguida, adicione um corpo, quebrando as linhas em no máximo 72 caracteres&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esses limites podem parecer arbitrários, mas existem razões históricas pra eles terem sido escolhidos. Pra resumir, eles funcionam bem com muitas ferramentas diferentes que trabalham com mensagens de commit.&lt;/p&gt;

&lt;p&gt;Outro ponto importante: você deve escrever o resumo no modo imperativo. Ou seja, “Implement password hashing” em vez de “Implemented password hashing”, por exemplo. A princípio isso pode parecer estranho, mas é o padrão que o próprio Git usa. Se não acreditar, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git revert&lt;/code&gt; pra reverter um commit e vai ver que a mensagem gerada está no modo imperativo:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Revert &lt;span class=&quot;s2&quot;&gt;&quot;Add line of text&quot;&lt;/span&gt;

This reverts commit 5ab08c5d3ee7bfdb334406d418d96f76d08962fe.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Viu? “Revert” em vez de “Reverted.”&lt;/p&gt;

&lt;p&gt;Adicionalmente, e de forma opcional, você pode adicionar um trailer ao commit. Trailers são metadados que você pode adicionar no final da mensagem de commit, seguindo a sintaxe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Nome: valor&lt;/code&gt;. Eles servem pra adicionar metadados úteis, como quem aprovou uma mudança, quem co-autorou algo com você, e também pra associar seu commit a um issue ou ticket.&lt;/p&gt;

&lt;p&gt;Por exemplo, se você usa GitHub Issues, você pode adicionar um trailer assim:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Closes: #456&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;E ele vai automaticamente associar o commit ao issue e fechá-lo. Existem outras palavras-chave que você pode usar, como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fixes&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Resolves&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Resolved&lt;/code&gt;, e assim por diante. Você pode aprender mais sobre como fechar issues do GitHub automaticamente &lt;a href=&quot;https://docs.github.com/pt/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;adotar-commits-atômicos&quot;&gt;…Adotar Commits Atômicos&lt;/h3&gt;

&lt;p&gt;A ideia dos commits atômicos é simples: um commit deve conter apenas mudanças logicamente relacionadas. É o oposto da falta de higiene de controle de versão que mencionei antes.&lt;/p&gt;

&lt;p&gt;Digamos que você está trabalhando numa feature. Aí seu chefe te pede pra parar e corrigir um bug. Você vai lá e corrige o bug, e agora tem aquelas mudanças misturadas com as do início da sua implementação de feature.&lt;/p&gt;

&lt;p&gt;Não commita tudo junto! Commita apenas as mudanças do bug fix como uma unidade coesa, com uma mensagem descritiva e de qualidade. Aí você volta pra sua feature e commita aquilo.&lt;/p&gt;

&lt;p&gt;Fazer isso exige que você domine as ferramentas do Git. Você precisa saber como fazer stage das mudanças e commitar apenas aquelas em vez de tudo. Precisa saber usar o stash. Com frequência, vai precisar saber como commitar coisas e depois editar esse histórico.&lt;/p&gt;

&lt;p&gt;Essas habilidades valem a pena ter. Vai atrás delas!&lt;/p&gt;

&lt;h3 id=&quot;commitar-sempre-polir-depois&quot;&gt;…Commitar Sempre, Polir Depois&lt;/h3&gt;

&lt;p&gt;Você não precisa esperar estar “pronto” pra commitar. Pelo contrário, você deve commitar o tempo todo. Trabalhe em incrementos pequenos e commite ao longo do caminho.&lt;/p&gt;

&lt;p&gt;Assim, se cometer erros e precisar descartar algum trabalho, você vai reverter apenas alguns minutos de trabalho em vez de horas. Você também tem esses checkpoints pra voltar caso a luz caia ou algo do tipo.&lt;/p&gt;

&lt;p&gt;Por exemplo, quem pratica TDD (desenvolvimento orientado a testes)&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; frequentemente commita toda vez que chega na fase verde. Ou seja, toda vez que os testes passam.&lt;/p&gt;

&lt;p&gt;Também é uma boa ideia manter todos os seus commits limpos. Com isso quero dizer que todos os seus commits, quando aplicados, devem deixar o projeto em um estado onde ele builda com sucesso e todos os testes passam. Isso facilita para você ou outra pessoa usar o &lt;a href=&quot;/pt/git-bisect-intro/&quot;&gt;git bisect no futuro pra encontrar onde um bug foi introduzido&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mas se você seguir essa dica, pode acabar com muitos commits pequeninhos que não têm boas mensagens, ou que não representam um conjunto coeso de mudanças. Como resolver isso?&lt;/p&gt;

&lt;p&gt;A resposta é: &lt;a href=&quot;/pt/git-historico-bonito/&quot;&gt;você edita seu histórico pra deixá-lo bonito&lt;/a&gt;. Editar o histórico é mal visto — e com razão — quando é uma branch da qual outras pessoas já dependem. Mas se você está trabalhando na sua própria branch isolada e ninguém depende das suas mudanças, você pode fazer o que quiser até aquele ponto. Então commite cedo e com frequência, e depois use amend e rebase até ter um histórico que faça sentido e tenha ótimas mensagens de commit.&lt;/p&gt;

&lt;h2 id=&quot;exemplos-de-boas-mensagens-de-commit&quot;&gt;Exemplos de Boas Mensagens de Commit&lt;/h2&gt;

&lt;p&gt;Finalmente chegou a hora de mostrar alguns exemplos de mensagens de commit valiosas que incorporam tudo que cobrimos até aqui.&lt;/p&gt;

&lt;p&gt;Por exemplo, em vez de:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Added Required attribute to model
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Escreva:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Make PhoneNumber required on /reservations endpoint

The /reservations endpoint originally didn&lt;span class=&quot;s1&quot;&gt;&apos;t require a phone number.
The reservations were being accepted but, as data flowed to downstream
systems, the lack of phone number was causing some processes to crash.

We are now adding the [Required] attribute to the PhoneNumber property
on the ReservationRequestModel. This is a breaking change, so that&apos;&lt;/span&gt;s
why, as part of this changes, we are versioning the endpoint as 2.0

Fixes: AB#456
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Veja como fica:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;A mensagem começa com um resumo que descreve o que foi feito&lt;/li&gt;
  &lt;li&gt;O corpo começa com uma descrição do problema, depois explica como a mudança atual o resolve&lt;/li&gt;
  &lt;li&gt;Por fim, temos um trailer para associar e fechar um ticket no board&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para o segundo exemplo, vamos fazer algo um pouco mais elaborado. Em vez de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enable EF Core execution strategy&lt;/code&gt;, você pode usar:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Enable EF Core execution strategy &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;Azure SQL

After migrating to Azure SQL, save operations started failing
intermittently &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;production with transient connection errors.
Azure SQL occasionally drops connections during scaling events
and failovers, and Entity Framework does not retry failed
operations by default.

Enabled the built-in SQL Server execution strategy &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;EF Core,
which automatically retries failed operations using exponential
backoff when a transient error is detected.

An execution strategy is a configurable EF Core component that
intercepts database operations and decides whether to retry
them on failure. The SQL Server provider ships with a strategy
that knows which error codes Azure SQL considers transient.

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1]: https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency

Closes: &lt;span class=&quot;c&quot;&gt;#89&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Todas as mensagens precisam ter esse nível de profundidade? Claro que não. Por exemplo, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix typo&lt;/code&gt; é uma ótima mensagem de commit, se tudo que você está fazendo naquele commit é corrigir um typo. O mesmo vale para &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Remove commented-out code&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Remove blank lines&lt;/code&gt;, e assim por diante.
O tamanho da sua mensagem de commit precisa ser diretamente proporcional ao tamanho e escopo da sua mudança.&lt;/p&gt;

&lt;h2 id=&quot;a-ia-muda-tudo-ouserá-que-não&quot;&gt;A IA Muda Tudo. Ou…Será Que Não?&lt;/h2&gt;

&lt;p&gt;Eu sei o que você ficou se perguntando durante todo esse tempo. “Mas…mas…mas…e o ChatGPT?”&lt;/p&gt;

&lt;p&gt;Minha opinião sincera é que a IA muda pouco, ou nada, do que discutimos até aqui.&lt;/p&gt;

&lt;p&gt;Pra começar, com IA ou sem IA, os fundamentos continuam os mesmos:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Boas mensagens de commit ainda devem focar mais no porquê do que no quê e no como.&lt;/li&gt;
  &lt;li&gt;A regra do 50/72 ainda é uma boa diretriz a seguir.&lt;/li&gt;
  &lt;li&gt;Usar o modo imperativo nos resumos continua sendo o padrão para muitas ferramentas, incluindo o próprio Git e o GitHub.&lt;/li&gt;
  &lt;li&gt;Boas mensagens de commit ainda têm imenso valor para leitores futuros, que podem incluir a própria IA.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Mas a IA é ótima pra escrever mensagens de commit. Por que eu deveria me preocupar?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Quando se trata de mensagens de commit, a IA é de fato ótima em uma coisa. E essa coisa é resumir um conjunto de mudanças e escrever, de forma muito bem escrita, gramaticalmente correta, com tom profissional… uma listagem detalhada de todas as mudanças.&lt;/p&gt;

&lt;p&gt;Que é exatamente o que você não deveria estar fazendo! Onde a IA falha é exatamente na parte mais importante, que a esta altura você já deve estar cansado de ler: o porquê.&lt;/p&gt;

&lt;p&gt;Não estou dizendo que você não deve usar IA pra te ajudar a criar mensagens de commit. Claro que pode. Eu uso bastante. Este é um exemplo de prompt que uso frequentemente com o Claude, com algumas variações:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Write a concise, well-crafted commit message for the diff I&apos;m going to give you.
Make it more high-level, focusing on the why rather than listing all changes in great detail.
Follow these rules:
- Summary
	- Brief description of what was done
	- 50 chars at the most
	- Use imperative mood
	- Do not use conventional commits
- Body
	- Brief description of the &quot;how&quot;, but focus more on the reason for the changes
	- Use prose rather than bullet points.
	- Use past tense
	- Lines no longer than 72 chars
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Depois eu rodo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git diff | clip&lt;/code&gt; e colo o resultado junto com esse prompt.&lt;/p&gt;

&lt;p&gt;O que eu recebo de volta é sempre uma mensagem muito bem escrita, muito mais detalhada sobre descrever as mudanças do que eu gostaria, e que perde completamente o ponto do porquê estamos fazendo as mudanças. O que não surpreende nada, porque como diabos ela saberia se eu não contei?&lt;/p&gt;

&lt;p&gt;O que faço então é explicar os motivos da mudança. E pedir pra tentar de novo, mais alto nível e incluindo a explicação. Às vezes a segunda versão já está boa o suficiente, mas geralmente preciso de pelo menos três até ficar satisfeito.&lt;/p&gt;

&lt;p&gt;Entendeu o padrão? Isso é uma colaboração entre a IA e eu. Estamos trabalhando juntos pra criar uma mensagem. Não estou terceirizando 100% pra IA.&lt;/p&gt;

&lt;p&gt;Quando uso o Claude Code, essas regras do prompt acima ficam no arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claude.md&lt;/code&gt; do projeto. Nesse cenário, ele tende a ir muito melhor em entender o “porquê”, porque tudo começou com um prompt em que eu expliquei o motivo por trás da mudança, e então fizemos uma sessão de planejamento antes de começar a implementar.&lt;/p&gt;

&lt;p&gt;Mas mesmo assim, a IA frequentemente ainda precisa de muita orientação até conseguir escrever uma mensagem de commit que realmente foque nos motivos por trás da mudança e que dê informações no nível certo de abstração. Por conta própria, a IA produz mensagens bem escritas que são essencialmente um diff em prosa.&lt;/p&gt;

&lt;h2 id=&quot;conclusão&quot;&gt;Conclusão&lt;/h2&gt;

&lt;p&gt;A essa altura, você provavelmente percebeu que este é um post bem opinionado. Algumas das coisas cobertas aqui estão muito perto de ser um padrão, como a regra do 50/72 e a ideia de escrever resumos no modo imperativo.&lt;/p&gt;

&lt;p&gt;Porém, algumas coisas que discuti são preferências pessoais. Por exemplo, eu normalmente não uso &lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/&quot;&gt;Conventional Commits&lt;/a&gt;. Os motivos pra isso estão além do escopo deste post, mas existem. São motivos bastante pessoais, então não vou te julgar se você gosta de usar Conventional Commits.&lt;/p&gt;

&lt;p&gt;A principal lição que quero que você leve deste post é: coloque trabalho nas suas mensagens de commit. Não escreva qualquer coisa; elabore suas mensagens. Trabalhe nelas, aperfeiçoe-as, até não conseguir mais melhorar.&lt;/p&gt;

&lt;p&gt;Sim, é difícil. Pode ser frustrante. Pode parecer uma perda de tempo ficar 10, 15 ou até 20 minutos elaborando uma mensagem que o seu LLM favorito teria gerado em segundos.&lt;/p&gt;

&lt;p&gt;Mas eu garanto: anos depois, quando você estiver investigando um incidente crítico em produção e se deparar com ótimas mensagens de commit que oferecem insights valiosos sobre o porquê de algumas mudanças terem sido feitas… você vai ficar feliz por ter feito isso.&lt;/p&gt;

&lt;p&gt;Obrigado por ler.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Phil Karlton foi engenheiro principal na Netscape nos anos 90. A formulação exata da frase varia dependendo da fonte — Martin Fowler tem &lt;a href=&quot;https://martinfowler.com/bliki/TwoHardThings.html&quot;&gt;uma boa nota sobre sua origem&lt;/a&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Tim Pope é um desenvolvedor open source prolífico, muito conhecido na comunidade Vim por plugins como vim-fugitive (integração com Git) e vim-surround. Seu post de 2008 sobre mensagens de commit continua sendo uma das referências mais citadas sobre o assunto. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;O ciclo do TDD é: escrever um teste que falha (vermelho), escrever o mínimo de código para fazê-lo passar (verde), depois limpar o código sem quebrar nada (refatorar). Commitar a cada fase verde gera um histórico granular, sempre funcional, que você pode percorrer com confiança usando o git bisect. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/suas-mensagens-de-commit-sao-um-lixo</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/suas-mensagens-de-commit-sao-um-lixo</guid>
        
        <category>tutorial</category>
        
        <category>git</category>
        
        <category>rant</category>
        
        <category>controle-de-versao</category>
        
        <category>boas-praticas</category>
        
        
      </item>
    
      <item>
        <title>Implementando o git em Go do Zero: Unindo o Útil ao...Agradável?</title>
        <description>&lt;p&gt;Recentemente comecei a trabalhar no meu projeto mais novo: construir o git em Go, do zero. &lt;em&gt;Qual é o sentido disso?&lt;/em&gt;, você pode estar se perguntando.&lt;/p&gt;

&lt;p&gt;Tipo, é um projeto bastante inútil no sentido de que, você sabe, o git existe há 20 anos. (Obrigado, Linus.)
Meu objetivo com esse projeto é duplo:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;aprender a linguagem Go&lt;/li&gt;
  &lt;li&gt;aprofundar meu conhecimento sobre os internos do git&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;escopo-do-projeto&quot;&gt;Escopo do Projeto&lt;/h2&gt;
&lt;p&gt;Não pretendo implementar 100% do git. Isso seria muito difícil. O que vou fazer é implementar um subconjunto pequeno de comandos do git, apenas em suas variações mais básicas.
Esta é a lista atual do que pretendo implementar:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git init&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa lista não é estática. Posso decidir implementar mais comandos, ou menos. Tudo depende de eu decidir que aprendi o suficiente. Vamos ver como isso vai.&lt;/p&gt;

&lt;h2 id=&quot;fluxo-de-trabalho-do-projeto-eu-realmente-não-sabia-como-chamar-essa-seção&quot;&gt;Fluxo de Trabalho do Projeto (eu realmente não sabia como chamar essa seção)&lt;/h2&gt;
&lt;p&gt;Como vou fazer tudo isso, na prática? Já estou fazendo, já que comecei há cerca de uma semana. Então, a forma como estou conduzindo isso é basicamente percorrer essa lista de comandos, implementando um por um, e documentando meus aprendizados neste blog.&lt;/p&gt;

&lt;p&gt;Ainda não tenho certeza sobre a cadência das postagens. Sinto que atualizações semanais são demais; já que tenho apenas cerca de 30 a 50 minutos por dia para trabalhar nisso, não quero perder muito tempo escrevendo as atualizações em si.&lt;/p&gt;

&lt;p&gt;Então acho que vou começar escrevendo os posts sempre que sentir que acumulei atualizações interessantes o suficiente para compartilhar, e aí compartilho. Pode ser que depois eu estabeleça em uma cadência regular, mas também pode ser que não.&lt;/p&gt;

&lt;h2 id=&quot;sobre-o-uso-de-llms&quot;&gt;Sobre o Uso de LLMs&lt;/h2&gt;
&lt;p&gt;Impus algumas regras a mim mesmo para este projeto. A mais importante é que zero linhas de código serão escritas por IA/LLMs. Isso derrotaria o propósito, já que o objetivo é realmente aprender a linguagem.&lt;/p&gt;

&lt;p&gt;Isso não significa que não estou usando IA. Estou usando o Claude para me ajudar a planejar o roteiro, por assim dizer. Ele tem me ajudado a decidir a ordem dos comandos que faz mais sentido, quais são os conceitos de Go necessários para construir isso e quais posso pular, e assim por diante.&lt;/p&gt;

&lt;p&gt;Para o meu aprendizado de Go em si, estou usando a documentação do Go e a boa e velha busca na web. Como nos velhos tempos.&lt;/p&gt;

&lt;h2 id=&quot;construindo-o-git-em-go-a-primeira-atualização&quot;&gt;Construindo o git em Go: A Primeira Atualização&lt;/h2&gt;
&lt;p&gt;Então, o que fiz até agora?
Comecei este projeto na segunda-feira, 2026-03-02. Uma semana atrás no momento em que escrevo. Durante os primeiros três dias, segui o &lt;a href=&quot;https://go.dev/tour/welcome/1&quot;&gt;Go Tour&lt;/a&gt; para relembrar as poucas coisas que eu sabia sobre a linguagem e aprender mais dos fundamentos.&lt;/p&gt;

&lt;p&gt;Na quinta-feira, terminei o tour. Passei pelos conteúdos sobre generics bem rapidamente e pulei completamente os de concorrência. Nesse dia, criei o &lt;a href=&quot;https://github.com/carlosschults/go-gitter&quot;&gt;repositório&lt;/a&gt; e escrevi um “Hello World.”&lt;/p&gt;

&lt;p&gt;Por algum motivo, não mexi no projeto na sexta-feira. Sábado foi o dia em que implementei de fato meu primeiro comando, e o único implementado até agora: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ggt init&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ah sim, a propósito: meu executável se chamará &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ggt&lt;/code&gt;, porque o próprio projeto se chama &lt;strong&gt;go-gitter&lt;/strong&gt;. Isso é um trocadilho idiota com a expressão em inglês “go-getter”, que se refere a uma pessoa que está sempre em ação, realizando muitas coisas e tal.&lt;/p&gt;

&lt;p&gt;Implementar o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt; foi muito fácil e tenho certeza de que só vai ficar mais difícil a partir de agora. Criar um repositório git é surpreendentemente simples, e é algo que você pode fazer manualmente, sem usar o git em si. Duvida? Ok, vou te ensinar.&lt;/p&gt;

&lt;p&gt;Vá a algum lugar no seu computador e crie uma pasta. Entre nessa pasta e crie uma nova chamada &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt;. Exatamente assim.&lt;/p&gt;

&lt;p&gt;Agora, entre em &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt; e crie um arquivo de texto chamado HEAD. Exatamente assim, sem extensão. Dentro desse arquivo, coloque o seguinte texto e salve:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ref: refs/heads/main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Próximo passo: crie duas novas pastas, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refs&lt;/code&gt;. Dentro de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt;, crie mais duas pastas vazias: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pack&lt;/code&gt;. Dentro de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refs&lt;/code&gt;, crie &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heads&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tags&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Agora, usando o terminal, vá ao mesmo nível onde a pasta .git está e execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;. Você verá um resultado assim:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;On branch main

No commits yet

nothing to commit (create/copy files and use &quot;git add&quot; to track)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Parabéns! Você acabou de criar um repositório git manualmente. Isso é exatamente o que &lt;a href=&quot;https://github.com/carlosschults/go-gitter/blob/main/ggt/main.go&quot;&gt;meu código Go está fazendo&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;acompanhe-as-atualizações&quot;&gt;Acompanhe as Atualizações&lt;/h2&gt;
&lt;p&gt;As atualizações deste progresso serão rastreadas pela tag &lt;a href=&quot;/tag_ptbr/go-gitter&quot;&gt;go-gitter&lt;/a&gt;, então você pode salvar essa página nos favoritos, se quiser.
Já vinculei ao repositório, mas aqui está novamente, caso você tenha perdido: &lt;a href=&quot;https://github.com/carlosschults/go-gitter&quot;&gt;go-gitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Obrigado pela leitura. Até a próxima atualização.&lt;/p&gt;
</description>
        <pubDate>Mon, 09 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/implementando-git-em-go</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/implementando-git-em-go</guid>
        
        <category>projetos</category>
        
        <category>git</category>
        
        <category>go</category>
        
        <category>go-gitter</category>
        
        <category>controle-de-versao</category>
        
        
      </item>
    
      <item>
        <title>O Que São Breaking Changes?</title>
        <description>&lt;p&gt;&lt;img src=&quot;/img/what-are-breaking-changes/cover.jpg&quot; alt=&quot;&quot; /&gt;
Foto por &lt;a href=&quot;https://unsplash.com/@denisolvr?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Denis Oliveira&lt;/a&gt; no &lt;a href=&quot;https://unsplash.com/photos/grayscale-photography-of-speedboat-yplNhhXxBtM?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Estou começando uma série de artigos onde vou definir alguns conceitos ou termos que são comuns no desenvolvimento de software, e estou começando com &lt;strong&gt;Breaking Changes&lt;/strong&gt;. Afinal, por que começar com A como uma pessoa normal?&lt;/p&gt;

&lt;p&gt;Beleza, mas… por que escrever uma série assim?&lt;/p&gt;

&lt;p&gt;Principalmente porque quero criar os recursos que gostaria de ter tido quando estava começando.&lt;/p&gt;

&lt;p&gt;Naquela época, me deixava louco quando as pessoas falavam de coisas como se eu já soubesse o que elas significavam.&lt;/p&gt;

&lt;p&gt;Olha, eu sou um desenvolvedor &lt;del&gt;velho&lt;/del&gt; experiente, o que significa que na minha época eu não tinha um amiguinho de IA pra simplesmente perguntar essas coisas. Sim, o Google já existia, também não sou tão &lt;del&gt;velho&lt;/del&gt; experiente assim né, porra.&lt;/p&gt;

&lt;p&gt;O problema é que muitas vezes as explicações que você encontrava no Google não eram lá essas coisas. Frequentemente o Stack Overflow ajudava, mas nem sempre. Hoje em dia, claro, você pode perguntar pro seu LLM favorito pra explicar as coisas pra você, se você não se importar com o tom genérico, desprovido de qualquer voz humana autêntica ou anedotas.&lt;/p&gt;

&lt;p&gt;Então, estou escrevendo esses artigos pra ajudar os iniciantes por aí a entender um pouco melhor alguns conceitos chave do desenvolvimento de software, um de cada vez, de forma simples e interessante, espero. Tudo cortesia do seu amigo aqui.
Vamos começar?&lt;/p&gt;

&lt;h2 id=&quot;o-que-é-um-breaking-change&quot;&gt;O que é um breaking change?&lt;/h2&gt;
&lt;p&gt;“Breaking change” significa qualquer mudança que você faz no seu software que pode fazer o código dos seus usuários quebrar, depois que eles fizerem o upgrade. Breaking changes só fazem sentido quando você pensa em software que você cria e de alguma forma distribui para usuários terceiros.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/workflow.png&quot; alt=&quot;Uma tira de quadrinhos sobre breaking changes&quot; title=&quot;Sempre tem um XKCD relevante&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pense em coisas como:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;APIs&lt;/li&gt;
  &lt;li&gt;bibliotecas/pacotes&lt;/li&gt;
  &lt;li&gt;frameworks&lt;/li&gt;
  &lt;li&gt;ferramentas CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos ver um exemplo. Enquanto desenvolvia uma aplicação pra sua empresa, você extraiu algumas funcionalidades comuns como uma biblioteca e decidiu publicar isso como um pacote open-source hospedado no &lt;a href=&quot;https://www.nuget.org&quot;&gt;https://www.nuget.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Depois de um tempo, você publica uma nova versão onde muda o nome de um dos métodos mais importantes e usados dentro do pacote. Os usuários fazem upgrade pra sua versão mais nova e agora o código deles não compila mais, porque ainda se refere ao método usando o nome original. &lt;strong&gt;Isso é um breaking change!&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    NOTA
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Importante: pra algo ser um breaking change, não é necessário que 100% dos usuários quebrem quando fazem upgrade. No nosso exemplo, é possível que nem todos os usuários estivessem realmente usando aquele método específico no código deles, o que significa que o código deles não teria quebrado. Mas a mudança ainda é um breaking change, porque o potencial de quebrar está lá.&lt;/p&gt;


  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;exemplos-de-breaking-changes&quot;&gt;Exemplos de Breaking Changes&lt;/h2&gt;

&lt;p&gt;Na prática, que tipos de mudanças são breaking changes?&lt;/p&gt;

&lt;p&gt;Eu diria que a mais comum, ou pelo menos o que a maioria das pessoas pensaria como breaking change, seria excluir ou renomear coisas.&lt;/p&gt;

&lt;p&gt;Se você renomeia um endpoint de API, uma classe pública ou método do seu pacote, ou um comando do seu CLI, código que usa essas coisas não vai mais funcionar. E, pra todos os efeitos práticos, renomear é a mesma coisa que excluir, porque aquela versão antiga não existe mais.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/travolta.gif&quot; alt=&quot;&amp;quot;John Travolta confuso procurando algo&amp;quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cadê o método que estava aqui?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Existem outros tipos de breaking changes, então vamos revisar alguns deles.&lt;/p&gt;

&lt;h3 id=&quot;novos-parâmetros-obrigatórios&quot;&gt;Novos Parâmetros Obrigatórios&lt;/h3&gt;

&lt;p&gt;Se você adiciona novos parâmetros a um método, e eles são obrigatórios, então todo código existente que chama o método vai falhar na compilação. A solução aqui seria adicionar novos parâmetros como opcionais, ou até criar um novo método.&lt;/p&gt;

&lt;h3 id=&quot;parâmetros-opcionais-removidos-ou-tornados-obrigatórios&quot;&gt;Parâmetros opcionais removidos ou tornados obrigatórios&lt;/h3&gt;

&lt;p&gt;Essa é uma continuação lógica da anterior. Se você remove um parâmetro opcional, código que chama aquele método passando o parâmetro vai quebrar. Por outro lado, se você torna um parâmetro opcional obrigatório, acontece o oposto: agora todos os lugares que não passam o parâmetro vão quebrar.&lt;/p&gt;

&lt;h3 id=&quot;novos-membros-adicionados-a-uma-interface&quot;&gt;Novos Membros Adicionados a Uma Interface&lt;/h3&gt;

&lt;p&gt;Aqui estou falando especificamente de linguagens estaticamente tipadas que têm o conceito de interface onde você define comportamentos que classes cliente precisam implementar.&lt;/p&gt;

&lt;p&gt;Adicionar um novo membro a uma interface é um breaking change porque agora todas as classes que a implementam não teriam implementado o novo membro.&lt;/p&gt;

&lt;p&gt;Recentemente, o time do C# resolveu esse problema de uma forma que gerou alguma controvérsia: adicionando a possibilidade de &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces/&quot;&gt;implementar métodos nas próprias interfaces!&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;mudou-o-tipo-de-um-parâmetro-de-método&quot;&gt;Mudou o Tipo de um Parâmetro de Método&lt;/h3&gt;

&lt;p&gt;Se você muda o tipo de um parâmetro de, digamos, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; para &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt;, você está garantindo que muito código cliente vai quebrar.&lt;/p&gt;

&lt;h3 id=&quot;mudou-o-tipo-de-retorno-de-um-método-ou-função&quot;&gt;Mudou o tipo de retorno de um método ou função&lt;/h3&gt;

&lt;p&gt;Novamente, dependendo dos tipos antigo e novo, isso pode nem quebrar, mas ainda é um breaking change em geral.&lt;/p&gt;

&lt;h3 id=&quot;mudou-a-ordem-dos-parâmetros&quot;&gt;Mudou a ordem dos parâmetros&lt;/h3&gt;

&lt;p&gt;Esse é interessante porque pode quebrar de uma forma diferente dos outros. Para a maioria dos exemplos que eu tenho dado até agora, “quebrar” significa que o código que consome seu código vai falhar na compilação.&lt;/p&gt;

&lt;p&gt;Com este, você pode fazer de uma forma que o código ainda compile, mas falhe em funcionar corretamente.&lt;/p&gt;

&lt;p&gt;Por exemplo, veja esse código:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IReadOnlyList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetProductsByCategory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;categoryId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;companyId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// implementação&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Se você invertesse a ordem entre &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;categoryId&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;companyId&lt;/code&gt;, o código ainda compilaria mas não funcionaria corretamente. Ainda seria um breaking change, mas um que falha de forma mais sutil.&lt;/p&gt;

&lt;p&gt;Claro que se os dois parâmetros são de tipos diferentes, então falharia no sentido de falhar na compilação. E é por isso que muita gente argumenta que você não deveria usar primitivos pra coisas como ids, mas criar seus próprios &lt;a href=&quot;https://carlosschults.net/pt-br/genai-tiny-types&quot;&gt;tiny types&lt;/a&gt; pra isso.&lt;/p&gt;

&lt;h3 id=&quot;comportamento-de-tratamento-de-erro-modificado-lançando-exceções-diferentes&quot;&gt;Comportamento de tratamento de erro modificado (lançando exceções diferentes)&lt;/h3&gt;

&lt;p&gt;Se o seu método costumava lançar um certo tipo de exceção e agora lança uma diferente, isso é um breaking change, porque código que foi escrito pra capturar aquela primeira exceção específica não vai funcionar pra nova, a menos que ela herde da primeira.&lt;/p&gt;

&lt;h3 id=&quot;tornou-métodos-ou-propriedades-públicas-privadas&quot;&gt;Tornou métodos ou propriedades públicas privadas&lt;/h3&gt;

&lt;p&gt;Na prática, do pontos de vista do cliente, isso é o mesmo que excluir algo, então é um breaking change óbvio.&lt;/p&gt;

&lt;h3 id=&quot;adicionou-requisitos-de-autenticação-onde-não-existiam&quot;&gt;Adicionou requisitos de autenticação onde não existiam&lt;/h3&gt;

&lt;p&gt;Até agora, todos os exemplos foram pra bibliotecas ou pacotes. Agora vamos ver alguns exemplos pra APIs web. O primeiro tem a ver com autenticação: se um endpoint não requeria autenticação mas agora requer, isso é um breaking change, porque código existente que costumava chamar isso agora vai receber um erro &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/401&quot;&gt;401 Unauthorized&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;adicionou-novas-propriedades-obrigatórias-a-um-payload&quot;&gt;Adicionou novas propriedades obrigatórias a um payload&lt;/h3&gt;

&lt;p&gt;Isso é similar a adicionar novas propriedades obrigatórias a um método público, certo? Se seu endpoint agora espera um payload diferente do que esperava antes, código existente vai quebrar, provavelmente recebendo um erro &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/400&quot;&gt;400 Bad Request&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;renomear-ou-deletar-um-endpoint&quot;&gt;Renomear ou deletar um endpoint&lt;/h3&gt;

&lt;p&gt;Esse é auto-explicativo.&lt;/p&gt;

&lt;h2 id=&quot;o-que-fazer-sobre-breaking-changes&quot;&gt;O que fazer sobre breaking changes?&lt;/h2&gt;

&lt;p&gt;Isso deveria ser óbvio agora, mas vamos deixar claro: breaking changes são Uma Coisa Ruim™. Tente ao máximo evitá-las.&lt;/p&gt;

&lt;p&gt;Se você distribui qualquer código ou software publicamente e existem pessoas que dependem dele, você não vai querer ficar quebrando os workflows delas frequentemente, ou elas vão ficar bravas com você, e com razão.&lt;/p&gt;

&lt;p&gt;Às vezes não tem jeito. Você simplesmente precisa fazer um breaking change, seja removendo um método ou classe que se tornou obsoleta, ou mudando a assinatura de uma função.&lt;/p&gt;

&lt;p&gt;Quando você tem que fazer algo assim, algumas coisas são aconselhadas.&lt;/p&gt;

&lt;h3 id=&quot;depreciação-gradual&quot;&gt;Depreciação Gradual&lt;/h3&gt;

&lt;p&gt;Adicionar um breaking change é algo que você não deveria levar de forma leviana porque pode dramaticamente interromper o workflow dos seus usuários. Além disso, não faça isso de repente, do nada, e de uma vez.&lt;/p&gt;

&lt;p&gt;Antes de remover classes/métodos/etc obsoletos, primeiro anuncie publicamente que você está fazendo isso, várias versões antes. Então, você marca aquele artefato como deprecated de alguma forma, mas ainda não remove. Por exemplo, em C# você pode usar o atributo &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.obsoleteattribute?view=net-9.0&quot;&gt;Obsolete&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Então, depois de algumas versões, você finalmente faz seu breaking change.&lt;/p&gt;

&lt;h3 id=&quot;adicione-instruções-às-suas-release-notes&quot;&gt;Adicione Instruções às Suas Release Notes&lt;/h3&gt;

&lt;p&gt;Se você está publicando software publicamente pra uso de terceiros, você provavelmente tem algum tipo de release notes onde comunica quais foram as mudanças nesta nova versão. Aproveite isso.&lt;/p&gt;

&lt;p&gt;Quando for hora de realmente publicar uma versão com breaking change, use suas release notes pra descrever, em detalhes, qual é a mudança e como vai afetar seus usuários.&lt;/p&gt;

&lt;p&gt;Geralmente, quando um breaking change consiste em aposentar um método/classe/endpoint, vem acompanhado de uma nova forma de fazer a mesma coisa. Afinal, você não estaria aposentando a forma antiga só porque sim.&lt;/p&gt;

&lt;p&gt;Nesses casos, também use suas release notes pra explicar em detalhes como os usuários podem adaptar seu código pra migrar da forma antiga pra nova de fazer a tarefa.&lt;/p&gt;

&lt;h3 id=&quot;use-semantic-versioning&quot;&gt;Use Semantic Versioning&lt;/h3&gt;

&lt;p&gt;Finalmente, use &lt;a href=&quot;https://semver.org/&quot;&gt;Semantic Versioning&lt;/a&gt; e use o número da versão pra comunicar que isso é um breaking change, lançando uma versão major.&lt;/p&gt;

&lt;p&gt;Semantic Versioning (ou SemVer pra abreviar) é um padrão de versionamento onde você usa um número de versão neste formato: major.minor.patch.&lt;/p&gt;

&lt;p&gt;Quando sua nova versão só contém correções de bugs, e elas não adicionam breaking changes, você incrementa o componente patch.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2.0.0 -&amp;gt; 2.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Se a versão contém nova funcionalidade que não quebra compatibilidade, então você incrementa o componente minor e zera o componente patch:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2.0.1 -&amp;gt; 2.1.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Agora vem a parte mais importante. Quando sua versão contém breaking changes, seja por nova funcionalidade, correções de bugs, ou ambos, você incrementa o número major e zera os outros dois:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2.1.0 -&amp;gt; 3.0.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dessa forma, você comunica claramente aos seus usuários a presença ou ausência de breaking changes na sua release mais recente.&lt;/p&gt;

&lt;h2 id=&quot;conclusão&quot;&gt;Conclusão&lt;/h2&gt;

&lt;p&gt;Neste post, expliquei o conceito de breaking change, por que geralmente é ruim, e o que fazer sobre isso. Resumo rápido:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Breaking changes são mudanças que quebram o código dos seus usuários, no contexto de software que é distribuído para usuários terceiros.&lt;/li&gt;
  &lt;li&gt;Evite adicionar breaking changes ao seu software, porque prejudicam a experiência dos seus clientes.&lt;/li&gt;
  &lt;li&gt;Às vezes você não pode evitar adicionar um breaking change. Nesses casos, use depreciação gradual, comunique claramente o que mudou e como se adaptar, e use semantic versioning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Acho que é isso. Obrigado por ler, espero que tenha sido útil e nos vemos novamente no próximo episódio desta série, onde provavelmente vou voltar pra letra A, porque sou esquisito assim mesmo.&lt;/p&gt;
</description>
        <pubDate>Fri, 26 Sep 2025 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/o-que-sao-breaking-changes</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/o-que-sao-breaking-changes</guid>
        
        <category>de-a-a-z</category>
        
        <category>breaking-changes</category>
        
        <category>engenharia-de-software</category>
        
        <category>boas-praticas</category>
        
        
      </item>
    
      <item>
        <title>Como Melhorar a Experiência do Desenvolvedor: 7 Coisas Para Mudar</title>
        <description>
&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    NOTA
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Escrevi este post originalmente para a Nimbus. Você pode ler o &lt;a href=&quot;https://www.usenimbus.com/post/how-to-improve-developer-experience-7-things-to-change&quot;&gt;original no site deles, em inglês&lt;/a&gt;.&lt;/p&gt;


  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;o-que-é-experiência-do-desenvolvedor-por-que-você-deveria-se-importar&quot;&gt;O Que é Experiência do Desenvolvedor? Por Que Você Deveria Se Importar?&lt;/h2&gt;

&lt;p&gt;No desenvolvimento de software, falamos muito sobre experiência do usuário, e com razão. Como é o usuário final que se beneficia diretamente do software que a gente escreve, faz sentido que ele esteja sempre no centro de todos os nossos esforços. Mas recentemente, outro termo começou a ganhar força no contexto de melhorar a qualidade do software: experiência do desenvolvedor, ou &lt;em&gt;developer experience&lt;/em&gt; no original em inglês.&lt;/p&gt;

&lt;p&gt;É sobre isso que este post trata — experiência do desenvolvedor. Vamos começar explicando o que é experiência do desenvolvedor e por que todas as organizações de software deveriam se importar com isso. A partir daí, vamos partir para a parte prática, apresentando uma lista de sugestões que você pode adotar imediatamente para melhorar a experiência do desenvolvedor na sua equipe ou empresa.&lt;/p&gt;

&lt;p&gt;Aqui está minha definição de experiência do desenvolvedor: quão confortável e “desenrolado” é o processo de desenvolvimento de software para uma determinada equipe ou organização.&lt;/p&gt;

&lt;p&gt;Por que a experiência do desenvolvedor é tão importante? Por que as pessoas começaram a falar tanto sobre isso recentemente?&lt;/p&gt;

&lt;p&gt;Não é difícil de entender. Software é tremendamente valioso, então as pessoas que criam software também são tremendamente valiosas. É do interesse de qualquer empresa que cria software manter seus desenvolvedores felizes e produtivos, especialmente num mercado aquecido onde desenvolvedores recebem oportunidades o tempo todo.&lt;/p&gt;

&lt;p&gt;Se você melhorar a experiência do desenvolvedor na sua empresa, é mais provável que você atraia ótimos desenvolvedores e mantenha os que já tem. A produtividade provavelmente vai aumentar, assim como a qualidade do trabalho.&lt;/p&gt;

&lt;h2 id=&quot;experiência-do-desenvolvedor-melhore-com-essas-7-dicas&quot;&gt;Experiência do Desenvolvedor: Melhore com Essas 7 Dicas&lt;/h2&gt;

&lt;p&gt;Chega de enrolação, vamos ver sete sugestões práticas que você pode adotar hoje para melhorar a experiência do desenvolvedor na sua empresa ou equipe.&lt;/p&gt;

&lt;h3 id=&quot;1-minimize-as-interrupções&quot;&gt;&lt;strong&gt;1. Minimize as Interrupções&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;De forma geral, desenvolvedores de software odeiam interrupções. Não é porque somos uns bichos do mato que não podem ser incomodados com reuniões ou atividades que podem ser descritas como “sociais” (ok, eu admito, alguns são).&lt;/p&gt;

&lt;p&gt;O problema com interrupções é que o desenvolvimento de software é uma &lt;strong&gt;atividade que requer longos períodos de foco intenso&lt;/strong&gt;. Como qualquer profissional cuja área exige esse nível de concentração vai dizer, alcançar esse estado demora tempo e esforço. No entanto, perdê-lo é fácil: basta o João da contabilidade ou seu gerente aparecer na sua mesa ou te mandar uma mensagem no Slack para fazer esse foco desaparecer no ar.&lt;/p&gt;

&lt;p&gt;Para melhorar a experiência do desenvolvedor, minimize as interrupções. Em termos mais práticos, faça o seguinte:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Use comunicação assíncrona o máximo possível.&lt;/strong&gt; Tente usar newsletter interno, artigos na wiki e atualizações por e-mail em vez de reuniões e chamadas.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Adote um dia livre de reuniões.&lt;/strong&gt; Escolha um dia da semana, ou pelo menos meio dia, em que a agenda de todos fica bloqueada e não pode ser reservada. Isso vai dar a todos a chance de ter tempo dedicado para concentração profunda.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Otimize o horário e duração das reuniões.&lt;/strong&gt; Reuniões são inevitáveis às vezes. Quando esse for o caso, escolha um horário e duração que facilite para as pessoas se concentrarem. Por exemplo, se o horário de trabalho da sua empresa termina às 18h, não agende uma reunião que termina às 17h30. Esses últimos trinta minutos provavelmente serão perdidos, já que não são suficientes para os desenvolvedores alcançarem o foco profundo que precisam.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-invista-em-excelência-técnica&quot;&gt;&lt;strong&gt;2. Invista em Excelência Técnica&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;A maioria dos desenvolvedores quer saber que seu trabalho importa. Eles querem saber que estão trabalhando numa equipe que cria software com os mais altos padrões, usando as melhores práticas disponíveis e encantando usuários com ótimas funcionalidades entregues rapidamente.&lt;/p&gt;

&lt;p&gt;Portanto, investir em excelência técnica é uma ótima forma de melhorar a experiência dos desenvolvedores. A lista do que você pode fazer inclui o seguinte:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Adotar testes automatizados e, opcionalmente, &lt;a href=&quot;/pt/testes-unitarios-csharp-intro-tdd/&quot;&gt;TDD (desenvolvimento guiado por testes)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Usar integração contínua (CI) e entrega e deployment contínuos (CD).&lt;/li&gt;
  &lt;li&gt;Ter um processo de revisão de código ou, em vez, programação em par.&lt;/li&gt;
  &lt;li&gt;Usar analisadores estáticos e linters para detectar problemas comuns no código.&lt;/li&gt;
  &lt;li&gt;Coletar e acompanhar métricas de qualidade.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essas são apenas algumas sugestões sobre o que você pode fazer para fomentar uma cultura de excelência técnica na qual os desenvolvedores sentem orgulho do seu trabalho e sentem que seu trabalho tem propósito.&lt;/p&gt;

&lt;h3 id=&quot;3-dê-autonomia-aos-desenvolvedores&quot;&gt;&lt;strong&gt;3. Dê Autonomia aos Desenvolvedores&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Autonomia é um grande motivador de produtividade e felicidade no trabalho. Para se sentirem realizadas, as pessoas precisam ter pelo menos algum grau de autonomia sobre a forma como fazem seus trabalhos.&lt;/p&gt;

&lt;p&gt;De forma geral, desenvolvedores deveriam receber um alto grau de autonomia sobre como fazem seu trabalho. Permita que as equipes decidam o seguinte:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Qual workflow de branching melhor atende suas necessidades&lt;/li&gt;
  &lt;li&gt;Se eles estimam usando pontos, tamanhos de camiseta, Fibonacci, horas ou algo completamente diferente&lt;/li&gt;
  &lt;li&gt;Quão rigorosamente eles querem aderir às cerimônias do seu sabor preferido de agile (por exemplo, se devem ou não ter um daily scrum)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No nível individual, permita que desenvolvedores escolham se querem trabalhar remotamente, no escritório ou de forma híbrida. Dê ao colaborador flexibilidade para montar um pacote de benefícios que faça sentido para ele (algumas pessoas têm filhos, outras não, então benefícios que atendem apenas pessoas casadas com filhos certamente vão alienar uma parte considerável da sua força de trabalho).&lt;/p&gt;

&lt;h3 id=&quot;4-remova-o-atrito-ao-criar-ambientes-de-desenvolvimento&quot;&gt;&lt;strong&gt;4. Remova o Atrito ao Criar Ambientes de Desenvolvimento&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Uma coisa que quase todo desenvolvedor odeia é um processo manual, tedioso e propenso a erros ao criar um novo ambiente de desenvolvimento. Esses processos fazem com que desenvolvedores demorem muito tempo até conseguirem contribuir com código para a equipe. Pior ainda, os processos frequentemente não são facilmente reproduzíveis, o que significa que diferenças entre ambientes podem ser introduzidas.&lt;/p&gt;

&lt;p&gt;Como consequência, o ambiente de desenvolvimento se afasta do staging e produção, tornando bugs mais prováveis e criando a famosa desculpa “funciona na minha máquina”.&lt;/p&gt;

&lt;p&gt;Para melhorar a experiência do desenvolvedor, invista em formas de facilitar a criação de ambientes consistentes e reproduzíveis. Soluções de container como Docker são uma ótima forma de alcançar isso. Alternativamente, você pode aproveitar soluções que oferecem a criação de ambientes de desenvolvimento na nuvem.&lt;/p&gt;

&lt;h3 id=&quot;5-invista-na-educação-dos-desenvolvedores&quot;&gt;&lt;strong&gt;5. Invista na Educação dos Desenvolvedores&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Debs também têm uma ótima experiência quando sentem que dominam as ferramentas do seu trabalho. A sensação de estar no controle é muito boa. Isso não só leva a um resultado de maior qualidade, mas também é mais prazeroso.&lt;/p&gt;

&lt;p&gt;Então, uma forma certeira de melhorar a experiência do desenvolvedor é investir na educação deles. Há várias formas de fazer isso:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Oferecer aos desenvolvedores uma verba mensal ou anual que eles podem usar livremente para investir em cursos, livros ou certificações.&lt;/li&gt;
  &lt;li&gt;Dar aos desenvolvedores tempo (tempo remunerado da empresa, sim!) durante o qual eles podem estudar e praticar&lt;/li&gt;
  &lt;li&gt;Oferecer recursos de aprendizado pagos pela empresa, como uma biblioteca da empresa ou serviços como Udemy ou Pluralsight&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;6-não-seja-pão-duro-com-ferramentas&quot;&gt;&lt;strong&gt;6. Não Seja Pão-Duro com Ferramentas&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Se você quer que seus desenvolvedores façam um ótimo trabalho, você deve dar a eles as ferramentas para fazê-lo. &lt;strong&gt;Se seus desenvolvedores não conseguem entregar um ótimo trabalho devido a um computador lento ou falta de licença de software, a culpa é sua&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Seus programadores deveriam ter ótimo hardware, como laptop fornecido pela empresa, monitor, teclado e por aí vai (e até complementos de escritório como uma ótima cadeira).&lt;/p&gt;

&lt;p&gt;Você também deveria fornecer o software necessário. Isso inclui licenças de IDE, assinaturas de serviços, plugins e o que mais for preciso. Não importa o que seus desenvolvedores precisam para realizar seu trabalho, a empresa deveria, dentro do razoável, fornecer.&lt;/p&gt;

&lt;h3 id=&quot;7-ouça-o-feedback-dos-desenvolvedores-e-aja-baseado-nele&quot;&gt;&lt;strong&gt;7. Ouça o Feedback dos Desenvolvedores (e Aja Baseado Nele)&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Por último, mas não menos importante, aqui está o item final da nossa lista: ouça seus desenvolvedores!&lt;/p&gt;

&lt;p&gt;Entende o seguinte: desenvolvedores de software geralmente são pessoas inteligentes que se importam com o que fazem. As chances são de que eles tenham ideias muito boas sobre como melhorar não apenas sua própria experiência, mas a de suas equipes e organizações como um todo.&lt;/p&gt;

&lt;p&gt;Ouça seus desenvolvedores. Quando fizer sentido, coloque suas sugestões em prática. Além do benefício criado pela sugestão em si, isso terá o benefício adicional de melhorar o moral da equipe. Seus desenvolvedores vão se sentir valorizados e como parte essencial da equipe. O que, é claro, eles são.&lt;/p&gt;

&lt;h3 id=&quot;melhore-a-experiência-do-desenvolvedor-melhore-sua-empresa&quot;&gt;&lt;strong&gt;Melhore a Experiência do Desenvolvedor, Melhore Sua Empresa&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Se sua organização é uma organização de tecnologia, então desenvolvedores de software são indiscutivelmente seus ativos mais preciosos. Então, melhorar a experiência do desenvolvedor, além de ser uma coisa decente e humana a se fazer, também é um ótimo investimento. É do seu interesse manter seus desenvolvedores felizes e produtivos, e como você viu neste post, isso é algo que você pode alcançar relativamente facilmente.&lt;/p&gt;

&lt;p&gt;As sugestões neste post são simplesmente sugestões. Seus resultados podem variar (por exemplo, se você trabalha numa indústria altamente regulamentada, dar aos desenvolvedores um alto grau de autonomia pode não se aplicar). Como sempre, use seu julgamento. Considere a lista neste post como um ponto de partida. Ajuste conforme necessário, corte e adicione a ela. O que importa é que você melhore a experiência do desenvolvedor na sua empresa pelo bem dos seus desenvolvedores, seus usuários finais e a empresa como um todo.&lt;/p&gt;

&lt;p&gt;Obrigado pela leitura!&lt;/p&gt;
</description>
        <pubDate>Tue, 08 Jul 2025 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/melhorar-experiencia-desenvolvedor</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/melhorar-experiencia-desenvolvedor</guid>
        
        <category>devex</category>
        
        <category>opiniao</category>
        
        <category>carreira</category>
        
        
      </item>
    
      <item>
        <title>Git Switch Branch: Tudo o Que Você Precisa Saber</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    NOTA
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Escrevi este post originalmente para a Cloudbees. Você pode ler o &lt;a href=&quot;https://www.cloudbees.com/blog/git-switch-branch-everything-to-know&quot;&gt;original, em inglês, no site deles&lt;/a&gt;.&lt;/p&gt;


  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Repositórios no &lt;a href=&quot;/tag_ptbr/git/&quot;&gt;Git&lt;/a&gt; funcionam de uma maneira fundamentalmente diferente da maioria das outras ferramentas. Um dos exemplos mais marcantes dessas diferenças é o branching. Na maioria das outras ferramentas de controle de versão, criar um branch é uma cerimônia elaborada. Eles fazem um grande alarde sobre isso, e os desenvolvedores acabam desistindo, preferindo fluxos de trabalho que não dependem de muitos branches.&lt;/p&gt;

&lt;p&gt;No Git, o oposto é frequentemente verdadeiro: criar branches é tão barato que a maioria das pessoas faz isso muito. As pessoas frequentemente ficam confusas ao tentar gerenciar seus branches. Este post tenta esclarecer parte dessa confusão, oferecendo um guia sobre como fazer o git switch branch de maneira fácil e segura. Antes de chegarmos lá, no entanto, começamos com alguns fundamentos, explicando o que realmente são branches no Git, como funcionam e como você as cria.&lt;/p&gt;

&lt;p&gt;Antes de concluir, compartilhamos uma dica bônus, abordando como fazer checkout de branches remotas. Vamos começar!&lt;/p&gt;

&lt;h2 id=&quot;como-funcionam-os-branches-no-git&quot;&gt;Como Funcionam os Branches no Git?&lt;/h2&gt;

&lt;p&gt;Como funcionam os branches no Git? A primeira coisa que você precisa saber é que um repositório no Git é composto por &lt;strong&gt;objetos&lt;/strong&gt; e &lt;strong&gt;referências&lt;/strong&gt;. Os principais tipos de objetos em um repositório Git são commits. Referências apontam para outras referências ou para objetos. Os principais tipos de referências são—você adivinhou—branches.&lt;/p&gt;

&lt;p&gt;Objetos no Git são imutáveis. Você não pode alterar um commit de forma alguma ou mover sua posição no histórico. Existem comandos que parecem mudar as coisas, mas na verdade eles criam novos commits. Referências, por outro lado, mudam bastante. Por exemplo, quando você cria um novo commit, a referência do branch atual é atualizada para apontar para ele.&lt;/p&gt;

&lt;p&gt;Quando você cria um novo branch, tudo o que acontece é que uma nova referência é criada apontando para um commit. É por isso que criar branches no Git é tão barato e rápido. Falando nisso…&lt;/p&gt;

&lt;h2 id=&quot;como-crio-um-novo-branch&quot;&gt;Como Crio um Novo Branch?&lt;/h2&gt;

&lt;p&gt;Nós já temos um post completo explicando como &lt;a href=&quot;/pt/git-criar-branch/&quot;&gt;você pode criar um branch no Git&lt;/a&gt;, cobrindo as quatro principais maneiras de fazer isso.&lt;/p&gt;

&lt;p&gt;Aqui, vamos apenas cobrir a maneira mais fácil de criar um branch no Git, que é simplesmente usar o comando branch a partir do branch atual. Vejamos um exemplo:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;git-switch-demo
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;git-switch-demo
git init
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file1.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create first file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file2.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create second file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file3.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create third file&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No exemplo acima, criamos um novo repositório e adicionamos três commits a ele, criando um novo arquivo por commit. Aqui está uma representação visual do estado atual do nosso repositório:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img1.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Para criar um novo branch a partir do ponto atual, só precisamos executar:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Criamos um branch, mas ainda não mudamos para ele. É assim que nosso repositório se parece agora:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img2.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;E se adicionássemos um novo commit enquanto ainda estamos no branch master? Isso afetaria o branch example? A resposta é não. Execute os seguintes comandos:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Another file&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; file4.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create fourth file&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Na próxima seção, mostraremos como você pode fazer git switch branch e, em seguida, poderá ver por si mesmo como esse novo branch não contém o quarto commit. Por enquanto, dê uma olhada na representação visual do estado atual do nosso repositório:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img3.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;como-você-muda-de-branch&quot;&gt;Como Você Muda de Branch?&lt;/h2&gt;

&lt;p&gt;Durante a maior parte da história do Git, o comando checkout era usado para isso. Embora você ainda possa usá-lo, a versão 2.23 do Git adicionou o comando switch (bem como o comando restore) em uma tentativa de ter comandos mais específicos para algumas das muitas tarefas para as quais o comando checkout é usado.&lt;/p&gt;

&lt;h3 id=&quot;como-uso-o-git-checkout&quot;&gt;Como Uso o Git Checkout?&lt;/h3&gt;

&lt;p&gt;A maneira mais antiga e mais conhecida de mudar de branch no Git é usando o comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout&lt;/code&gt;. Seguindo nosso exemplo, se quiséssemos mudar para o branch “example”, só teríamos que executar:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Após executar o comando, você deverá ver uma mensagem dizendo que mudou com sucesso para o branch example:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img4.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Agora você está no novo branch, isso significa que pode adicionar quantos commits quiser, sabendo que o branch master não será afetado. O comando checkout, seguido por um nome de branch, atualiza a árvore de trabalho e o índice, e atualiza a referência HEAD, apontando-a para o branch que você acabou de fazer checkout. E se você tivesse alterações não commitadas no momento da mudança? Essas seriam mantidas para permitir que você as commitasse no novo branch.&lt;/p&gt;

&lt;p&gt;O Git permite que você use o comando checkout de diferentes maneiras. Por exemplo, um cenário incrivelmente comum é criar um branch e imediatamente mudar para ele. Na verdade, eu diria que criar um branch e &lt;em&gt;não&lt;/em&gt; mudar para ele na hora é a exceção, e não a regra. Então, o Git nos oferece um atalho. Em vez de criar um branch e depois fazer checkout dele, você pode fazer isso em uma única etapa usando o comando checkout com o parâmetro &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Então, fazer isso:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; new
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;é equivalente a isso:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch new
git checkout new
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Checkout não funciona apenas com branches, no entanto. Você também pode fazer checkout de commits diretamente. Por que você gostaria de fazer isso?&lt;/p&gt;

&lt;p&gt;Bem, dar uma olhada em como o projeto estava há algum tempo atrás é frequentemente útil, particularmente para fins de teste. Mas há mais. Fazer checkout de um commit coloca seu repositório em um estado chamado &lt;a href=&quot;/pt/git-detached-head&quot;&gt;“detached HEAD”&lt;/a&gt; que permite criar alterações experimentais, adicionando commits que você pode então escolher manter ou descartar.&lt;/p&gt;

&lt;h3 id=&quot;o-que-é-git-switch&quot;&gt;O Que é Git Switch?&lt;/h3&gt;

&lt;p&gt;Durante a maior parte da vida do Git, o comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout&lt;/code&gt; era o único que você usaria para mudar de branch. O problema é que esse comando também faz outras coisas, &lt;a href=&quot;https://redfin.engineering/two-commits-that-wrecked-the-user-experience-of-git-f0075b77eab1&quot;&gt;o que pode levar à confusão, especialmente entre novos usuários&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A versão 2.23.0 do Git resolve isso adicionando dois novos comandos: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;restore&lt;/code&gt;. O comando restore não é relevante para nós hoje. O comando switch, por outro lado, é uma nova maneira de mudar para branches.&lt;/p&gt;

&lt;p&gt;A &lt;a href=&quot;https://git-scm.com/docs/git-switch/pt_BR&quot;&gt;página do manual para o comando&lt;/a&gt; lista todas as suas muitas opções. Em sua forma mais básica, você o usa da mesma maneira que o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout&lt;/code&gt;, apenas trocando o nome do comando:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git switch example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Se você quiser voltar ao branch anterior, pode usar um atalho em vez do nome completo:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git switch -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;E se você quiser criar um novo branch e imediatamente mudar para ele? Com checkout, poderíamos usar este atalho:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; &amp;lt;nome-do-branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;O novo comando também oferece um atalho, mas neste caso, usamos a letra “c”:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git switch &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &amp;lt;nome-do-branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Vale a pena usar o novo comando? Bem, eu provavelmente continuarei usando o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout&lt;/code&gt;, desde que eles não o mudem, principalmente por causa da memória muscular. Mas ao ensinar Git para iniciantes? Então eu definitivamente usarei o comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt;. Ele tem um nome que está mais relacionado à tarefa que executa e, portanto, é mais memorável.&lt;/p&gt;

&lt;h3 id=&quot;como-faço-para-mudar-para-um-branch-remoto&quot;&gt;Como Faço para Mudar para um Branch Remoto?&lt;/h3&gt;

&lt;p&gt;Antes de concluir, compartilhamos uma dica final: como mudar para branches remotas?&lt;/p&gt;

&lt;p&gt;Para este exemplo, vamos usar um projeto de código aberto chamado &lt;a href=&quot;https://github.com/nodatime/nodatime&quot;&gt;Noda Time,&lt;/a&gt; que é uma API alternativa de data e hora para .NET. Comece clonando o repositório:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/nodatime/nodatime.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Se tudo funcionou bem, você deve ter uma pasta “nodatime” agora. Entre na pasta e execute o seguinte comando:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;O comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;branch&lt;/code&gt; lista os branches em seu repositório. A opção “-a” significa que você quer ver todos os branches, não apenas os locais. O resultado deve ser parecido com isto:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img5.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Como você pode ver, temos apenas um branch local, que é o branch master. Você pode ver, em vermelho, todos os branches remotos. Então, digamos que você queira fazer checkout do branch chamado “slow-test”. Como você faria isso?&lt;/p&gt;

&lt;p&gt;Bem, tecnicamente falando, o Git não permite que você trabalhe nos branches de outras pessoas. E é isso que são os branches remotos. O que você realmente faz é criar uma “cópia” local do branch de outra pessoa para trabalhar. Então, vamos ver como fazer isso.&lt;/p&gt;

&lt;p&gt;Quando você cria um branch, pode passar um commit ou nome de branch como parâmetro. Então, para criar um branch local a partir do branch remoto “slow-test”, eu só teria que fazer:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch slow-test origin/slow-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No exemplo, estou usando “slow-test” como o nome para o meu branch local, mas eu poderia realmente ter usado qualquer outro nome válido.&lt;/p&gt;

&lt;p&gt;Alternativamente, eu poderia ter usado o comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout&lt;/code&gt; com a opção -b ou o comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; com a opção -c. Então, as duas linhas a seguir são equivalentes à linha acima:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; slow-test origin/slow-test
git switch &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; slow-test origin/slow-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finalmente, há uma maneira ainda mais fácil. Eu poderia ter simplesmente usado:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout slow-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;e o resultado teria sido o mesmo. Isso funciona porque quando você tenta fazer checkout de um branch e o Git não encontra um branch com esse nome, ele tenta corresponder a um branch remoto de um de seus remotes. Se ele conseguir corresponder com sucesso, as coisas simplesmente funcionam.&lt;/p&gt;

&lt;h2 id=&quot;branches-do-git-use-com-moderação&quot;&gt;Branches do Git: Use com Moderação&lt;/h2&gt;

&lt;p&gt;Neste post, mostramos como mudar de branch no Git. Mas fomos além disso: explicamos o que são branches e como funcionam. Esperamos que, a esta altura, você esteja mais confortável criando e usando branches no Git.&lt;/p&gt;

&lt;p&gt;Antes de irmos, uma ressalva final: só porque você pode fazer algo, não significa que deva. Às vezes, as pessoas ficam tão entusiasmadas com a facilidade de criar branches no Git que acabam usando &lt;a href=&quot;https://rollout.io/blog/pitfalls-feature-branching/&quot;&gt;fluxos de trabalho que dependem de vários branches de longa duração&lt;/a&gt;, o que torna seu processo de desenvolvimento muito complexo e propenso a erros, além de atrasar a integração.&lt;/p&gt;

&lt;p&gt;Obrigado por ler e até a próxima!&lt;/p&gt;
</description>
        <pubDate>Tue, 15 Apr 2025 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/git-switch-branch</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/git-switch-branch</guid>
        
        <category>git</category>
        
        <category>tutorial</category>
        
        <category>controle-de-versao</category>
        
        
      </item>
    
      <item>
        <title>C# Type Safe: Como a IA Generativa Torna os Tiny-Types Viáveis</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dz5ppacuo/image/upload/v1466341001/csharp-min_buiizq.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;É estranho como nossa memória funciona, não é? Não consigo lembrar exatamente o que jantei há duas noites, ou o motivo pelo qual deixei de ir à academia em alguns dias da semana passada.
Mas me lembro vividamente de um bug específico que corrigi no meu primeiro emprego como programador depois de me formar na faculdade.&lt;/p&gt;

&lt;p&gt;Havia este método que não estava funcionando corretamente, e sua assinatura era algo assim:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProcessOrder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Eu revisei o código e não consegui encontrar nada de errado. Mas quando comecei a debugar, percebi que o local da chamada estava passando os argumentos na ordem errada — ou seja, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;customerId&lt;/code&gt; primeiro e depois &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;orderId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Erros como este são fáceis de cometer e difíceis de detectar mesmo em revisões de código. Até mesmo os testes podem deixar passar, já que você pode ter o azar de fornecer valores que acidentalmente fazem o código funcionar sem explodir tudo.&lt;/p&gt;

&lt;p&gt;Como acontece, existe uma ótima maneira de prevenir problemas como o que acabei de descrever. O problema? A maioria dos desenvolvedores acharia que é trabalho demais para se preocupar.&lt;/p&gt;

&lt;h2 id=&quot;tiny-types-a-melhor-técnica-de-design-de-software-que-ninguém-usa&quot;&gt;Tiny Types: A Melhor Técnica de Design de Software Que Ninguém Usa&lt;/h2&gt;

&lt;p&gt;Eu sei, eu sei. Vou ser o primeiro a admitir que este título é exagerado. “Uma Técnica Interessante de Design de Software Que Muitas Pessoas Não Usam” simplesmente não tem o mesmo impacto, foi mal.&lt;/p&gt;

&lt;p&gt;Então, o que é essa coisa de “tiny types”? É uma solução radical para o code smell de obsessão primitiva. Essencialmente, em vez de usar tipos primitivos para conceitos de domínio — por exemplo, usar um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; para representar um identificador único — você envolve todos eles usando um &lt;a href=&quot;/pt/value-objects-ferramenta/&quot;&gt;objeto de valor&lt;/a&gt; extremamente simples.&lt;/p&gt;

&lt;p&gt;Usando tiny types, poderíamos reescrever a assinatura do método anterior assim:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProcessOrder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;implementando-um-tiny-type&quot;&gt;Implementando um Tiny Type&lt;/h3&gt;
&lt;p&gt;Como seria o tipo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Para começar, já que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt; deve envolver um int, ele deve receber um int como parâmetro e armazená-lo em algum lugar. Vejamos:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;Value must be a positive integer!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Acho que o exemplo acima é um bom começo, você não concorda? Recebemos um int como parâmetro, validamos e lançamos uma exceção em caso de valores zero ou negativos, e então o atribuímos a um campo privado readonly, o que é apropriado, já que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt;, como um objeto de valor, deve ser imutável.&lt;/p&gt;

&lt;p&gt;Você sabe do que mais os objetos de valor — e, por consequência, os tiny types — precisam? Igualdade estrutural. Ou seja, ao compará-los, devemos considerar apenas seus valores, não se suas referências apontam para o mesmo objeto.&lt;/p&gt;

&lt;p&gt;Então, vamos começar sobrescrevendo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Equals&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(Para um estilo C# mais moderno, poderíamos ter usado pattern matching, mas acho que a abordagem acima é mais clara.)&lt;/p&gt;

&lt;p&gt;Agora recebo um aviso do compilador porque meu tipo sobrescreve &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Equals&lt;/code&gt; mas não &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetHashCode&lt;/code&gt;, então vamos corrigir isso:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt; é um tipo simples representando valores únicos e imutáveis, ele deveria realmente ser uma &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; em vez de uma classe, de acordo com as &lt;a href=&quot;https://learn.microsoft.com/pt-br/dotnet/standard/design-guidelines/type&quot;&gt;Diretrizes de Design de Tipos da Microsoft&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Structs são o caso geral de tipos de valor e devem ser reservadas para tipos pequenos e simples, semelhantes aos primitivos da linguagem.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Mas as diretrizes de design também dizem que todas as structs devem implementar a interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEquatable&amp;lt;T&amp;gt;&lt;/code&gt;, então vamos fazer isso. Aliás, já que estamos aqui, vamos também implementar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IComparable&amp;lt;T&amp;gt;&lt;/code&gt; e dar overload nos operadores de comparação:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IEquatable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;Value must be a positive integer!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Existem mais coisas que poderíamos adicionar, como conversões implícitas/explícitas, mas nosso tipo já é funcional como está. Para aqueles que usam C# moderno, poderíamos alcançar o mesmo com uma sintaxe mais concisa:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;O valor deve ser um inteiro positivo!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;tiny-types-são-muito-caros&quot;&gt;Tiny Types São Muito Caros&lt;/h3&gt;
&lt;p&gt;Meu pequeno tipo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt; ali ocupa 42 linhas no meu Visual Studio. Sim, existem algumas escolhas estilísticas envolvidas — por exemplo, eu não gosto quando as linhas têm mais de 80 caracteres de comprimento — mas mesmo assim, é bastante trabalho.&lt;/p&gt;

&lt;p&gt;A versão mais concisa, que aproveita o recurso record do C# moderno, é mais curta, mas ainda requer uma quantidade razoável de código.&lt;/p&gt;

&lt;p&gt;Agora imagine fazer isso para todos os ids em sua aplicação! E não apenas ids, claro. Imagine fazer isso para mais tipos que exigem validação/análise mais complexa:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;CEPs&lt;/li&gt;
  &lt;li&gt;Placas de carro&lt;/li&gt;
  &lt;li&gt;Números de telefone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E assim por diante.&lt;/p&gt;

&lt;p&gt;Essa é a principal razão pela qual desenvolvedores que conhecem esta técnica não a usam. Mesmo quando gostam da ideia e entendem como ela poderia ser benéfica, eles acham que fazer tudo isso não vale o trabalho.&lt;/p&gt;

&lt;h2 id=&quot;llms-ao-resgate&quot;&gt;LLMs ao Resgate&lt;/h2&gt;

&lt;p&gt;Já se passaram dois anos desde que a OpenAI &lt;a href=&quot;https://openai.com/index/chatgpt/&quot;&gt;apresentou o ChatGPT ao mundo&lt;/a&gt;, e tenho experimentado com LLMs desde então. Minha opinião atual sobre eles é que sua proposta de valor para desenvolvedores experientes é dupla:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Eles atuam como um substituto do Google ao aprender algo novo&lt;/li&gt;
  &lt;li&gt;Eles atuam como um gerador de código para coisas mundanas que eu preferiria não fazer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Há alguns meses, tornei-me um assinante pago do &lt;a href=&quot;https://claude.ai&quot;&gt;Claude&lt;/a&gt;. Tenho usado principalmente como auxílio em um projeto hobby no qual estou trabalhando, e devo dizer que estou muito satisfeito com os resultados que obtenho, já que o Claude é muito melhor que o ChatGPT para tarefas de programação.&lt;/p&gt;

&lt;p&gt;Fui ao Claude com o seguinte prompt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Gere um tipo chamado OrderId. Deve ser um wrapper sobre um int. Não permita valores zero ou negativos. Implemente igualdade, hash code, sobrecarga de operadores de comparação e igualdade.&lt;/p&gt;

  &lt;p&gt;Não adicione conversões explícitas ou implícitas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E este é o resultado que obtive:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IEquatable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Order ID must be greater than zero&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;É um bom começo, mas ainda não estou completamente satisfeito:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Pode torná-lo um record para que a implementação seja mais concisa? Além disso, use métodos com corpo de expressão para as linhas únicas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E agora o Claude me deu isso:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Order ID must be greater than zero&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finalmente, fui ao Claude e perguntei isto:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Imagine que existe uma classe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; que precisa ser salva no banco de dados. 
Usamos Entity Framework. Como garantir que tudo funcione já que este modelo usa o tipo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E esta é minha resposta, completa com o modelo e a configuração necessária do EF para lidar com nosso
tipo personalizado:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HasConversion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderIdValueConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ValueGeneratedOnAdd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Usar auto-incremento do banco de dados&lt;/span&gt;
            
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CustomerName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsRequired&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasMaxLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasPrecision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusão&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Este post tinha dois objetivos. Primeiro, apresentar o conceito de tiny types para aqueles de vocês que nunca ouviram falar dele. Espero que concordem que, apesar de ser uma ideia simples, o padrão tiny types é algo que pode ajudar você a escrever código mais robusto.&lt;/p&gt;

&lt;p&gt;Segundo, e de forma mais ampla, demonstrar como os LLMs podem desempenhar um papel interessante no fomento de um melhor design de software. No passado, muitas técnicas de design de software podem ter sido descartadas por serem consideradas trabalho demais para valer a pena. Agora, com a ajuda do Claude, ChatGPT ou assistentes de código como o Copilot, podemos agilizar a escrita de código “chato”, o que faz com que a economia das técnicas de design, como a que apresentei neste post, faça mais sentido.&lt;/p&gt;
</description>
        <pubDate>Tue, 10 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt-br/genai-tiny-types</link>
        <guid isPermaLink="true">https://carlosschults.net/pt-br/genai-tiny-types</guid>
        
        <category>csharp</category>
        
        <category>ia</category>
        
        <category>boas-praticas</category>
        
        <category>modelagem-de-software</category>
        
        
      </item>
    
      <item>
        <title>Erros de Aprendizado Para Se Evitar Como Desenvolvedor de Software</title>
        <description>&lt;p&gt;&lt;img src=&quot;/img/software-developer-learning-mistakes/cover.webp&quot; alt=&quot;&quot; /&gt;
Foto de &lt;a href=&quot;https://unsplash.com/pt-br/@francisco_legarreta?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Francisco De Legarreta C.&lt;/a&gt; na &lt;a href=&quot;https://unsplash.com/pt-br/fotografias/um-homem-com-oculos-esta-olhando-para-um-laptop-hHg9MC-G8_Y?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    Info
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Agradeço ao amigo &lt;a href=&quot;https://www.linkedin.com/in/andre-godasi/&quot;&gt;André Gonçalves da Silva&lt;/a&gt; por ler e revisar esboços deste post, e sugerir melhorias.&lt;/p&gt;

  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Se você trabalha com desenvolvimento de software, com certeza já ouviu frases do tipo “Nunca pare de estudar”, “Tem que se atualizar sempre”, “A nossa área muda muito rápido”, e assim por diante.&lt;/p&gt;

&lt;p&gt;Claro, todas essas frases estão certas, em algum nível. Mas sair por aí repetindo como um papagaio “nunca pare de estudar” não é a coisa mais &lt;strong&gt;útil&lt;/strong&gt; do mundo no sentido de fornecer um direcionamento para o seu aprendizado.&lt;/p&gt;

&lt;p&gt;O que acaba acontecendo na prática é que muita gente, por não ter aprendido a aprender da forma correta, comete muitos erros de aprendizado que comprometem seu desenvolvimento profissional. Esses erros podem levar a um progresso lento, frustração e até mesmo estagnação na carreira - algo que ninguém está a fim de passar.&lt;/p&gt;

&lt;p&gt;Por isso, nesse post, resolvi trazer um compilado do que acredito serem os erros mais comuns de aprendizado que devs em geral cometem. Essa lista é fruto de anos de experiência pessoal, observação de colegas desenvolvedores e muitas conversas com gente da área. Eu sei na prática do que estou falando porque muitos desses erros são coisas que eu já cometi.&lt;/p&gt;

&lt;p&gt;(Sendo sincero, alguns eu ainda cometo e tô sempre precisando me policiar para parar, mas não conta pra ninguém. ;))&lt;/p&gt;

&lt;p&gt;Identificar e entender esses erros é o primeiro passo para superá-los. Ao evitá-los, você pode otimizar seu processo de aprendizado, acelerar seu crescimento profissional e se manter relevante em um campo que está sempre evoluindo.&lt;/p&gt;

&lt;p&gt;Então, sem mais delongas, aqui vai a lista dos erros de aprendizado para você evitar. Para cada erro, você vai ver:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a explicação do erro&lt;/li&gt;
  &lt;li&gt;o problema que ele causa&lt;/li&gt;
  &lt;li&gt;como remediá-lo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bora lá?&lt;/p&gt;

&lt;h2 id=&quot;índice&quot;&gt;Índice&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#achar-que-apenas-consumo-de-conteúdo--aprendizado&quot;&gt;Achar Que Apenas Consumo de Conteúdo == Aprendizado&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#não-aplicar-o-conteúdo-dos-recursos-de-aprendizado&quot;&gt;Não Aplicar o Conteúdo dos Recursos de Aprendizado&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#falta-de-foco&quot;&gt;Falta de Foco&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#falta-de-consistência&quot;&gt;Falta de Consistência&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#subestimar-a-importância-das-bases&quot;&gt;Subestimar a Importância das Bases&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#viver-embaixo-de-uma-pedra-não-se-antenar-com-o-que-está-acontecendo&quot;&gt;Viver Embaixo de Uma Pedra (Não se antenar com o que está acontecendo)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusão&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;achar-que-apenas-consumo-de-conteúdo--aprendizado&quot;&gt;Achar Que Apenas Consumo de Conteúdo == Aprendizado&lt;/h2&gt;

&lt;p&gt;Comecei a lista com esse que acredito ser o erro de aprendizado mais comum atualmente, pelo simples fato de que a gente vive em uma época onde se produz conteúdo pra caramba.&lt;/p&gt;

&lt;h3 id=&quot;por-que-caímos-nessa-armadilha&quot;&gt;Por que caímos nessa armadilha?&lt;/h3&gt;

&lt;p&gt;Consumir conteúdo é &lt;strong&gt;fácil, conveniente e(potencialmente) divertido.&lt;/strong&gt; Vamos entender o porquê:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fácil: É algo passivo, você não tem que pensar muito ou tomar decisões, e o ser humano tende a procurar o caminho do menor esforço.&lt;/li&gt;
  &lt;li&gt;Conveniente: Você pode geralmente consumir o conteúdo enquanto faz outras coisas:
    &lt;ul&gt;
      &lt;li&gt;Ouvir um podcast enquanto se exercita ou lava a louça&lt;/li&gt;
      &lt;li&gt;Assistir um vídeo enquanto almoça&lt;/li&gt;
      &lt;li&gt;Ler posts no Reddit enquanto espera na fila do banco&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Divertido: Muitos criadores percebem que, pra engajar o público, precisam adicionar um toque de entretenimento e transformar o conteúdo numa performance que segure a atenção.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pronto, a armadilha está montada. Aí você vai lá, bola uma estratégia para preencher cada momento livre do dia com o consumo de podcasts, vídeos no Youtube, blog posts, Reddit, e sei lá o que mais.&lt;/p&gt;

&lt;h3 id=&quot;as-consequências-desse-erro&quot;&gt;As consequências desse erro&lt;/h3&gt;

&lt;p&gt;No fim, você vai ter:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Consumido seu tempo com informações superficiais&lt;/li&gt;
  &lt;li&gt;Retido quase nada do que consumiu&lt;/li&gt;
  &lt;li&gt;Um vago sentimento de que “aprendeu” alguma coisa&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mas e na hora de aplicar isso de maneira significativa no seu dia-a-dia? É aí que a conta não fecha.&lt;/p&gt;

&lt;p&gt;A longo prazo, as consequências podem ser ainda mais sérias:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Estagnação profissional, pois você não está realmente desenvolvendo novas habilidades&lt;/li&gt;
  &lt;li&gt;Frustração ao perceber que não está progredindo como esperava&lt;/li&gt;
  &lt;li&gt;Possível burnout ao tentar constantemente “ficar por dentro” de tudo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pra deixar bem claro: o erro aqui não é “consumir conteúdo.” E sim achar que apenas o consumo desenfreado de conteúdo é o suficiente para você evoluir como profissional.&lt;/p&gt;

&lt;h3 id=&quot;como-remediar-esse-erro&quot;&gt;Como remediar esse erro&lt;/h3&gt;

&lt;p&gt;A solução é simples em teoria, o que não necessariamente significa que é fácil. Aqui vai:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Diminua a parcela do seu tempo de aprendizado que você gasta com consumo passivo de conteúdos, e aumenta a parcela gasta com aprendizado prático, principalmente projetos pessoais.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As sugestões aqui são:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Crie ou contribua com um projeto open-source&lt;/li&gt;
  &lt;li&gt;Faça um site ou aplicativo para uma ONG, entidade assistencial, ou sua igreja&lt;/li&gt;
  &lt;li&gt;Solucione algum problema que você ou algum familiar tem criando uma automação simples&lt;/li&gt;
  &lt;li&gt;Reinvente a roda:&lt;a href=&quot;https://github.com/codecrafters-io/build-your-own-x&quot;&gt; Implemente uma tecnologia ou ferramenta conhecida&lt;/a&gt; (exemplos: git, Docker, um servidor HTTP) simplesmente com o objetivo de aprender.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lista acima não é exaustiva, mas serve apenas pra começar a te inspirar. Cinco minutos de Google ou de conversa com o Chat GTP vai render muitas ideias de projetos legais para fazer.&lt;/p&gt;

&lt;h2 id=&quot;não-aplicar-o-conteúdo-dos-recursos-de-aprendizado&quot;&gt;Não Aplicar o Conteúdo dos Recursos de Aprendizado&lt;/h2&gt;

&lt;p&gt;Se você comprar um livro e não o ler, você joga dinheiro fora. Se você comprar o livro, ler, e o aprendizado daquilo não impactar a maneira como você faz seu trabalho, então você desperdiça o seu dinheiro e o seu tempo!&lt;/p&gt;

&lt;p&gt;O mesmo se aplica a cursos, tutoriais, e outros recursos de aprendizado. Ser desenvolvedor de software é uma profissão prática; como você espera se beneficiar do que aprendeu, se não o colocar em prática?&lt;/p&gt;

&lt;p&gt;Antes que alguém reclame: sim, é claro que existem livros, vídeos, etc., cujo conteúdo não tem uma aplicação prática direta. Talvez você tenha lido &lt;a href=&quot;https://pt.wikipedia.org/wiki/The_Mythical_Man-Month&quot;&gt;O Mítico Homem-Mês&lt;/a&gt; pra pegar alguns insights e aprender sobre a história do desenvolvimento de software, mas isso não muda necessariamente como você escreve código. E tá tudo bem, esses casos existem – use seu bom senso.&lt;/p&gt;

&lt;p&gt;Como o erro #2 difere do anterior?&lt;/p&gt;

&lt;p&gt;A gente pode resumir o primeiro erro como “gastar 100% do seu tempo de aprendizado com o consumo de conteúdo.” Ou seja, você não faz mais nada além de consumir coisas.&lt;/p&gt;

&lt;p&gt;Este erro aqui é na linha de “não aplicar o que você aprende com o conteúdo assistido.”&lt;/p&gt;

&lt;p&gt;Ou seja, é possível cometer o segundo erro sem cometer o primeiro. Por exemplo, você pode dedicar 60% do seu tempo de aprendizado à criação de projetos pessoais e 40% ao consumo de conteúdo. Mas se ainda sim você não aplicar de nenhuma forma o conteúdo que você aprendeu nesses 40% do tempo, você vai ter cometido o erro #2. Ficou claro?&lt;/p&gt;

&lt;h3 id=&quot;motivo-desse-erro&quot;&gt;Motivo Desse Erro&lt;/h3&gt;

&lt;p&gt;Por que tanta gente (este que vos fala incluso) comete esse erro? Provavelmente o que rola aqui é uma certa pressão psicológica que muitos sentimos, no sentido de atingir números. Quantas pessoas você conhece que criam umas metas assim?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ler x livros técnicos por ano&lt;/li&gt;
  &lt;li&gt;Fazer y cursos até o segundo semestre&lt;/li&gt;
  &lt;li&gt;etc…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se você se sente realmente a fim de atingir esse tipo de meta, não tem jeito: precisa “gastar” o menor tempo possível com cada conteúdo. Do contrário, a conta não fecha.&lt;/p&gt;

&lt;h3 id=&quot;problemas-causados-por-este-erro&quot;&gt;Problemas Causados Por Este Erro&lt;/h3&gt;

&lt;p&gt;Uma consequência grave que você pode sofrer com este erro é a falta de motivação. Você leu todos os livros famosos da área que te indicaram, concluiu todos os cursos no seu &lt;a href=&quot;https://mereo.com/blog/pdi/&quot;&gt;PDI&lt;/a&gt;, e parece que nada mudou. Assim fica difícil ter a motivação pra insistir no aprendizado, quando a sensação é de que nada disso gera impacto real na maneira como você trabalha.&lt;/p&gt;

&lt;p&gt;É essa a tal da frustração com a falta de evolução na carreira, que a gente citou no erro anterior. Outra consequência séria desse erro é o próprio desperdício de tempo, dinheiro e energia: o aprendizado é um investimento que precisa ter um retorno para ser justificado.&lt;/p&gt;

&lt;h3 id=&quot;qual-a-solução&quot;&gt;Qual a solução?&lt;/h3&gt;

&lt;p&gt;O remédio para este erro tem dois passos:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Priorizar qualidade ao invés de quantidade&lt;/li&gt;
  &lt;li&gt;Aplique constantemente o que aprendeu&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Então, aqui fica a minha sugestão prática:: &lt;strong&gt;só inicie outro curso/livro/etc após ter aplicado o aprendizado do anterior.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Por exemplo, digamos que você está fazendo um curso na Udemy. Após cada aula ou seção, pare e crie um pequeno projeto no qual você exercita o que você acabou de aprender. Não precisa ser um projeto grande, nem mesmo útil. De preferência, jogue fora depois de terminar: o importante é a prática.&lt;/p&gt;

&lt;p&gt;Aqui estão mais alguns exemplos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Após assistir um tutorial de programação, dedique tempo para replicar o projeto por conta própria, sem olhar o vídeo&lt;/li&gt;
  &lt;li&gt;Leu um artigo sobre uma nova técnica de refatoração? Aplique-a em um projeto pessoal ou no trabalho&lt;/li&gt;
  &lt;li&gt;Ouviu um podcast sobre boas práticas de código? Revise um projeto antigo e veja onde você pode aplicar essas práticas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com relação à leitura de livros técnicos, recentemente eu criei uma regra pra mim: quando eu termino um livro, eu só posso começar outro depois que eu tiver aplicado o conteúdo do livro que acabei de ler. Essa aplicação pode ter diferentes formas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;fazer os exercícios do livro, caso tenha&lt;/li&gt;
  &lt;li&gt;criar um ou mais projetos para exercitar aquele conteúdo&lt;/li&gt;
  &lt;li&gt;propor/implementar uma nova prática no meu trabalho baseado no que aprendi&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No fim das contas, é isso que importa: que você dê um jeito de aplicar o conteúdo aprendido pra melhorar a sua vida profissional. Uma pilha de livros cujo conteúdo não te impactou só serve pra juntar poeira ou de suporte para monitor.&lt;/p&gt;

&lt;h2 id=&quot;falta-de-foco&quot;&gt;Falta de Foco&lt;/h2&gt;

&lt;p&gt;Existem muito mais coisas “aprendíveis” do que você tem tempo ou energia para aprender. Você nunca vai saber tudo, e nunca vai zerar a sua fila de coisas para aprender. Isso é um fato e você precisa aceitar e abraçar esse fato, a não ser que você esteja muito a fim de um burnout.&lt;/p&gt;

&lt;p&gt;Infelizmente, a gente sente a pressão de “estar sempre estudando”, mesmo que essa frase em si não tenha nenhuma utilidade—não oferece nenhuma ajuda sobre &lt;em&gt;o quê&lt;/em&gt; estudar, ou que estratégias usar.&lt;/p&gt;

&lt;p&gt;É comum que essa pressão venha das nossas próprias empresas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Leia o livro x!&lt;/li&gt;
  &lt;li&gt;Faça esse curso!&lt;/li&gt;
  &lt;li&gt;Conclua essa trilha!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E essas pessoas são bem intencionadas, mas isso não muda o fato de que você tem uma quantidade limitada de tempo no seu dia e, mais importante, uma quantidade limitada de energia no tempo que você tem disponível&lt;/p&gt;

&lt;p&gt;Mas aí você cede à pressão e acaba cometendo o erro desse item: ficar pulando de curso em curso, livro em livro, tutorial em tutorial, sem nunca concluir nada, ou pelo menos atingir algum progresso significativo.&lt;/p&gt;

&lt;h3 id=&quot;um-disclaimer&quot;&gt;Um Disclaimer&lt;/h3&gt;

&lt;p&gt;Olha só: eu sei que no dia-a-dia do trabalho, é muito comum a gente se deparar com um número enorme de problemas diferentes que precisam ser resolvidos, e o prazo é sempre pra ontem. Nestas situações, muitas vezes a coisa correta é sim aprender somente o superficial de um assunto para conseguir dar conta da demanda e gerar valor para o usuário o mais rápido possível.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A habilidade de distinguir quando é a hora de investir em um certo item de maneira mais aprofundada e quando um conhecimento superficial basta&lt;/strong&gt; é algo que é extremamente valioso para a carreira de qualquer profissional, e a única maneira de aperfeiçoar essa habilidade é com a prática.&lt;/p&gt;

&lt;p&gt;O erro que eu aponto neste item é uma situação diferente do cenário acima. Mais especificamente, o erro é sobre tentar aprender muitas coisas ao mesmo tempo, de maneira aprofundada, com recursos densos.&lt;/p&gt;

&lt;h3 id=&quot;problemas-causados-por-este-erro-1&quot;&gt;Problemas Causados Por Este Erro&lt;/h3&gt;

&lt;p&gt;O principal problema causado pela falta de foco é que você nunca se aprofunda em nada. Você fica com uma vaga impressão de conhecimento em um milhão de coisas, mas quando rola uma situação crítica no qual o conhecimento aprofundado faria falta, você não tem o que mostrar.&lt;/p&gt;

&lt;p&gt;Como eu já disse antes, é impossível se aprofundar em tudo. Mas você deveria, sim, se aprofundar nas coisas que mais importam, aquelas que geram maior valor para sua carreira. Me refiro aos tais dos fundamentos que muita gente fala, mas vou falar mais a respeito disso em outro tópico.&lt;/p&gt;

&lt;h3 id=&quot;como-remediar&quot;&gt;Como Remediar&lt;/h3&gt;

&lt;p&gt;Este erro talvez seja o mais difícil de remediar, porque a solução envolve uma dose alta de autoconhecimento e um senso muito forte de priorização.&lt;/p&gt;

&lt;p&gt;No geral, a dica é: &lt;strong&gt;defina UM ponto de evolução para sua carreira, e foque nele por um tempo considerável, até avaliar que fez progresso.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alguns exemplos de pontos de melhoria:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Melhorar meus conhecimentos de paralelismo, concorrência, e performance&lt;/li&gt;
  &lt;li&gt;Aprender os principais design patterns e saber aplicá-los em projetos reais&lt;/li&gt;
  &lt;li&gt;Adquirir habilidades avançadas em SQL&lt;/li&gt;
  &lt;li&gt;Aprender uma nova linguagem e chegar em um nível produtivo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Não é fácil identificar este ponto de melhoria, mas aqui vão algumas dicas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Peça feedback dos gestores e colegas.&lt;/li&gt;
  &lt;li&gt;Converse com algum mentor técnico em quem você confia.&lt;/li&gt;
  &lt;li&gt;Se você está ativamente participando de processos seletivos para vagas e tem falhado, analise os pontos nos quais foi mal nas entrevistas para identificar onde melhorar.&lt;/li&gt;
  &lt;li&gt;Se não está ativamente procurando, finja que está. Peça para algum amigo ou mentor fazer uma mock interview com você, e depois peça feedback honesto.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;falta-de-consistência&quot;&gt;Falta de Consistência&lt;/h2&gt;

&lt;p&gt;O que é melhor, dedicar 30 minutos por dia pra aprender, todos os dias, ou 5 horas no final de semana, uma vez a cada três meses? A resposta é óbvia.&lt;/p&gt;

&lt;p&gt;A nossa profissão é prática, é necessária prática deliberada e consistente para que você internalize as coisas que aprende a saiba usar quando chegar a hora.&lt;/p&gt;

&lt;h3 id=&quot;consequências&quot;&gt;Consequências&lt;/h3&gt;

&lt;p&gt;As consequências aqui são bem óbvias, né? Simplesmente não tem como fazer progresso se você não se esforça com consistência. Isso na verdade se aplica em praticamente qualquer coisa na vida: atividade física, aprendizado de idiomas, tocar um instrumento, e por aí vai.&lt;/p&gt;

&lt;p&gt;Se você investe, por exemplo, 1 hora por semana para aprender algo, isso dá um total de cerca de 51 horas no ano. Agora, se você aprender 15 minutos todos os dias, isso dá um total de 5475 minutos no ano, &lt;strong&gt;o que dá mais de 91 horas&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Estudar só uma vez por semana tem outra desvantagem. Se surgir algum imprevisto e você precisar faltar, quando voltar já terão se passado duas semanas. Assim, fica complicado manter o ritmo; você precisa lembrar de onde parou 14 dias atrás, e retomar o contexto perdido não é nada fácil.&lt;/p&gt;

&lt;h3 id=&quot;como-remediar-1&quot;&gt;Como Remediar&lt;/h3&gt;

&lt;p&gt;Solucionar esse erro requer pensar em estratégias para que o aprendizado se torne uma parte natural da sua rotina diária.&lt;/p&gt;

&lt;p&gt;Para começar, defina o &lt;strong&gt;tempo **que você vai dedicar diariamente, de forma &lt;em&gt;realista&lt;/em&gt;&lt;/strong&gt;. Não adianta se comprometer com 2 horas de aprendizado diário se a sua rotina simplesmente não permite isso.&lt;/p&gt;

&lt;p&gt;Outra coisa essencial é escolher o &lt;strong&gt;horário&lt;/strong&gt; do seu tempo de aprendizado. Pra fixar bem o hábito, o ideal seria que fosse no mesmo horário todos os dias. Ao escolher esse horário, leve em consideração como seus níveis de energia mudam durante o dia. Você é uma pessoa matinal? Coloque seu tempo de aprendizado na parte da manhã. Do contrário, à noite.&lt;/p&gt;

&lt;p&gt;Vou dar o exemplo do que funciona pra mim. Eu sei que se for deixar meu tempo de aprendizado para depois do trabalho, vou estar muito cansado e provavelmente não vou fazer. Então, para mim, o melhor é reservar cerca de 50 minutos antes do trabalho para o aprendizado.&lt;/p&gt;

&lt;p&gt;Pra fazer do aprendizado um hábito, a chave é integrar na rotina e diminuir o atrito. Sabe aquela galera que dorme de roupa de academia? Mesma ideia pro estudo. Deixe o PC ligado com o VS Code aberto no seu projeto, ou configure o navegador pra abrir direto no curso da Udemy. Quanto mais fácil começar, melhor.&lt;/p&gt;

&lt;p&gt;Também é interessante que a hora de decidir o que aprender e a hora de aprender sejam momentos distintos. Se você tem 50 minutos por dia para o aprendizado, mas gasta 20 desses minutos todos os dias decidindo o que vai ler/praticar/assistir, você está desperdiçando 40% do seu tempo.&lt;/p&gt;

&lt;p&gt;Então vai a dica: no sábado, você vai definir a sua rotina de aprendizado para a semana seguinte. Você criar uma planilha definindo os dias e o que você vai fazer, ou criar um board no &lt;a href=&quot;https://trello.com/&quot;&gt;Trello&lt;/a&gt;, ou mesmo usar papel e caneta, não importa. O importante é você já ter isso definido de antemão. Aí, nos dias da semana, você simplesmente confere e segue o planejamento feito.&lt;/p&gt;

&lt;p&gt;Finalmente, algo que funciona para muitas pessoas é fazer algum tipo de compromisso público. Você declara, publicamente—por exemplo, no seu Linkedin—que vai estudar sem faltar durante x dias. O simples fato de ter feito esse compromisso frequentemente ajuda as pessoas a manterem a rotina sem faltar.&lt;/p&gt;

&lt;p&gt;Uma iniciativa legal nesse sentido é o &lt;a href=&quot;https://www.100diasdecodigo.dev/&quot;&gt;100 Dias de Código,&lt;/a&gt; que incentiva pessoas a codarem durante 100 dias seguidos, sem falta, interagindo com outros participantes no processo.&lt;/p&gt;

&lt;h2 id=&quot;subestimar-a-importância-das-bases&quot;&gt;Subestimar a Importância das Bases&lt;/h2&gt;

&lt;p&gt;Muita gente subestima a importância de se aprender os fundamentos da computação. Sim, estou falando daquelas coisas chatas que você não gostava de estudar na faculdade: algoritmos e estruturas de dados, teoria da computação, complexidade de algoritmos, e por aí vai.&lt;/p&gt;

&lt;p&gt;Esse pessoal argumenta que você não precisa saber dessas coisas todas pra fazer o seu código funcionar. Sim, isso pode ser verdade boa parte do tempo, mas não sempre.&lt;/p&gt;

&lt;p&gt;A gente pode pensar na computação como várias camadas que abstraem a camada anterior. Quando você está trabalhando em uma camada, você geralmente não precisa se preocupar com as outras. Isso é uma coisa boa, e é literalmente o motivo pelo qual a gente usa abstrações: “esconder” coisas que não são essenciais, diminuindo a complexidade do que você precisa lidar.&lt;/p&gt;

&lt;h3 id=&quot;consequências-1&quot;&gt;Consequências&lt;/h3&gt;

&lt;p&gt;Infelizmente, as abstrações não são perfeitas. Como já nos advertiu Joel Spolsky mais de 20 anos atrás, &lt;a href=&quot;https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/&quot;&gt;as abstrações em algum momento vazam&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Em outras palavras: só porque você usa um ORM não significa que você não tem que saber SQL. Mesmo quem usa uma linguagem gerenciada como C# ou Java pode se beneficiar de ter um entendimento sobre gerenciamento de memória: no mínimo, você vai ser capaz de escrever código que usa lifetimes de maneira correta, não cria alocações desnecessárias e coloca pressão no garbage collector.&lt;/p&gt;

&lt;p&gt;Falta de entendimento de complexidade de algoritmos pode derrubar um sistema. Você testa localmente seu código com algumas poucas centenas de valores, mas quando aquilo vai ao ar e tem que lidar com milhões de itens, ele simplesmente não dá conta.&lt;/p&gt;

&lt;p&gt;Em resumo: você consegue fazer algo que “funciona” sem conhecimento de fundamentos. Porém, funciona em parte dos cenários, parte do tempo, com desempenho inaceitável, e sem levar em conta edge cases.&lt;/p&gt;

&lt;p&gt;Além dos problemas que a falta de uma base sólida pode causar nos sistemas em que você trabalha, este erro pode trazer outra consequência bem séria para sua carreira.&lt;/p&gt;

&lt;p&gt;Sim, estou falando de você não ser capaz de passar nos processos seletivos das empresas. É muito comum que empresas, principalmente as de fora do país, utilizem desafios técnicos que requerem um bom conhecimento em tópicos como algoritmos, estrutura de dados, complexidade, concorrência e paralelismo, o modelo de memória da sua linguagem preferida, entre outros.&lt;/p&gt;

&lt;p&gt;Não ter esse conhecimento significa ser reprovado sumariamente nos processos.&lt;/p&gt;

&lt;h3 id=&quot;solução&quot;&gt;Solução&lt;/h3&gt;

&lt;p&gt;Se você não tem faculdade, recomendo fortemente que estude Ciência da Computação. Caso já tenha terminado a faculdade mas esqueceu todos aqueles tópicos, procure relembrar/reforçar esses conceitos.&lt;/p&gt;

&lt;p&gt;Na internet você pode achar de sobra conteúdo sobre Ciência da Computação. Por exemplo, o projeto &lt;a href=&quot;https://github.com/Clemensss/TeachYourselfCS-PT/blob/master/TeachYourselfCS-PT.md&quot;&gt;Teach Yourself Computer Science&lt;/a&gt; tem um roadmap de tópicos para aprender, com bibliografia e vídeos de aulas de universidades renomadas.&lt;/p&gt;

&lt;p&gt;O &lt;a href=&quot;https://neetcode.io/roadmap&quot;&gt;NeetCode &lt;/a&gt;é um site que traz um roadmap de estudo de algoritmos e estruturas de dados. Também oferece cursos e a funcionalidade de praticar questões reais usadas em entrevistas de emprego.&lt;/p&gt;

&lt;h2 id=&quot;viver-embaixo-de-uma-pedra-não-se-antenar-com-o-que-está-acontecendo&quot;&gt;Viver Embaixo de Uma Pedra (Não se antenar com o que está acontecendo)&lt;/h2&gt;

&lt;p&gt;Achei que seria interessante que o último erro fosse exatamente o oposto do primeiro. Enquanto o erro que abre a lista era “apenas consumir conteúdo e achar que está aprendendo”, esse aqui é “nunca consumir conteúdo nenhum.”&lt;/p&gt;

&lt;h3 id=&quot;por-que-isso-é-um-problema&quot;&gt;Por Que Isso é Um Problema?&lt;/h3&gt;

&lt;p&gt;Nós trabalhamos em uma área que muda constantemente, e cada vez mais rápido. Não se manter atualizado pode levar a:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Obsolescência das suas habilidades&lt;/li&gt;
  &lt;li&gt;Perda de oportunidades de carreira&lt;/li&gt;
  &lt;li&gt;Dificuldade em resolver problemas usando abordagens mais eficientes&lt;/li&gt;
  &lt;li&gt;Falta de inspiração para inovação no seu trabalho diário&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Em outras palavras: falta de atualização prejudica seu desempenho no seu trabalho atual, e ao mesmo tempo diminui suas chances de conseguir um potencial novo emprego. Não é isso que você quer, né?&lt;/p&gt;

&lt;h3 id=&quot;encontrando-o-equilíbrio&quot;&gt;Encontrando o equilíbrio&lt;/h3&gt;

&lt;p&gt;Por um lado, utilizar cada segundo livre para consumir cada podcast/artigo/vídeo que seja possível não é uma boa estratégia. É como comer muita porcaria que não é nutritiva: você vai se sentir cheio, mas aquela comida não vai trazer os benefícios que seu corpo precisa.&lt;/p&gt;

&lt;p&gt;Mas por outro lado, não consumir conteúdo &lt;em&gt;nenhum&lt;/em&gt; é igualmente ruim. Como desenvolvedor, é importantíssimo que você tenha pelo menos uma noção do que está acontecendo no mundo do desenvolvimento de software.&lt;/p&gt;

&lt;h3 id=&quot;o-que-manter-no-radar&quot;&gt;O que manter no radar&lt;/h3&gt;

&lt;p&gt;Aqui vai uma pequena lista de coisas que seria interessante manter no seu radar:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Lançamento de livros técnicos sobre temas que você se interessa, ou de autores que você já acompanha&lt;/li&gt;
  &lt;li&gt;Novas funcionalidades da versão mais recente da sua linguagem ou framework principais&lt;/li&gt;
  &lt;li&gt;Ferramentas ou técnicas que podem facilitar a sua vida&lt;/li&gt;
  &lt;li&gt;Tendências emergentes na indústria (por exemplo, IA.)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;onde-encontrar-conteúdo-relevante&quot;&gt;Onde encontrar conteúdo relevante&lt;/h3&gt;

&lt;p&gt;Existem muitas fontes de informação valiosas para desenvolvedores. Aqui estão algumas sugestões:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Reddit&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://old.reddit.com/r/programming&quot;&gt;r/programming&lt;/a&gt; para um apanhado geral&lt;/li&gt;
      &lt;li&gt;Subreddits específicas como r&lt;a href=&quot;https://old.reddit.com/r/csharp&quot;&gt;/csharp&lt;/a&gt;, &lt;a href=&quot;https://old.reddit.com/r/java&quot;&gt;r/java&lt;/a&gt;, &lt;a href=&quot;https://old.reddit.com/r/golang&quot;&gt;r/golang&lt;/a&gt;, etc.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Hacker News&lt;/strong&gt;: Excelente para notícias e discussões sobre tecnologia em geral&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;YouTube&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;Pesquise por canais relacionados aos seus interesses específicos&lt;/li&gt;
      &lt;li&gt;Assista a palestras de conferências de tecnologia&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Blogs técnicos&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;De empresas de tecnologia (por exemplo, blog de engenharia do &lt;a href=&quot;https://netflixtechblog.com/&quot;&gt;Netflix&lt;/a&gt;, &lt;a href=&quot;https://engineering.atspotify.com/&quot;&gt;Spotify&lt;/a&gt;, etc.)&lt;/li&gt;
      &lt;li&gt;De desenvolvedores influentes na sua área&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Podcasts de tecnologia&lt;/strong&gt;: Ótimos para consumir informação enquanto faz outras atividades&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;conclusão&quot;&gt;Conclusão&lt;/h2&gt;

&lt;p&gt;Chegamos ao fim da lista. Espero que o compilado de erros de aprendizado que você acabou de ler seja útil para sua carreira. Com essa lista eu cobri o que não fazer, mas o que você deve fazer então?&lt;/p&gt;

&lt;p&gt;Talvez no futuro eu escreva um post apenas sobre isso: como aprender da maneira correta, e no que focar. Deixa aí nos comentários caso você se interesse em algo assim.&lt;/p&gt;

&lt;p&gt;Mas, por enquanto, para saber o que fazer, basta imaginar uma estratégia de aprendizado que seja o contrário dos erros acima:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Aprenda com &lt;strong&gt;consistência&lt;/strong&gt;, de preferência um pouco todos os dias;&lt;/li&gt;
  &lt;li&gt;Tenha &lt;strong&gt;foco&lt;/strong&gt;: privilegia um ponto principal de melhoria por vez;&lt;/li&gt;
  &lt;li&gt;Prefira um &lt;strong&gt;aprendizado baseado em projetos&lt;/strong&gt;, suplementado em partes por consumo de conteúdo&lt;/li&gt;
  &lt;li&gt;Ao consumir conteúdo, sempre &lt;strong&gt;aplique o que aprendeu&lt;/strong&gt; de alguma forma prática&lt;/li&gt;
  &lt;li&gt;Aprender sobre ferramentas é importante, mas ter &lt;strong&gt;fundamentos sólidos&lt;/strong&gt; é mais importante&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agora vem a dica mais importante que eu posso deixar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feito é melhor que perfeito.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pulou um dia de aprendizado? Não tem importância, continue no próximo. Dedicou 30 minutos ao seu projeto ao invés dos 50 que tinha planejado? Ainda é infinitamente melhor do que não ter feito nada.&lt;/p&gt;

&lt;p&gt;Tendências são mais importantes do que data points. Estar indo na direção certa é mais significativo do que metas arbitrárias do tipo “vou ler 6 livros técnicos em 2024”.&lt;/p&gt;

&lt;p&gt;É difícil lidar com a pressão de desenvolvimento constante que a gente sente nessa área, eu sei bem disso. Na medida do possível, tente relaxar. Não se martirize demais. Você está indo na direção certa.&lt;/p&gt;

&lt;p&gt;Só o fato de ter lido até o final um post de quase 4 mil palavras demonstra que você é muito mais interessado(a) em seu desenvolvimento que a maioria. Por isso, eu lhe agradeço muito. Se precisar de ajuda, não hesite em &lt;a href=&quot;https://carlosschults.net/sobre/&quot;&gt;entrar em contato.&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 22 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/erros-aprendizados</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/erros-aprendizados</guid>
        
        <category>opiniao</category>
        
        <category>carreira</category>
        
        
      </item>
    
  </channel>
</rss>
