<?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>Thu, 09 Apr 2026 17:14:39 +0000</pubDate>
    <lastBuildDate>Thu, 09 Apr 2026 17:14:39 +0000</lastBuildDate>
    <generator>Jekyll v4.3.1</generator>
    
    
      <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;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; 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) 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;'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'&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'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;
</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>
        
        
      </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>
        
        
      </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>
        
        
      </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>opinion</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>
        
        
      </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>ai</category>
        
        <category>software-design</category>
        
        <category>best-practices</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>opinião</category>
        
        <category>carreira</category>
        
        
      </item>
    
      <item>
        <title>Erro 'Git Detached Head': O Que Significa e Como Resolver</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;
    Info
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;&lt;em&gt;Nota editorial: Eu originalmente escrevi este post para o blog da Cloudbees.  Você pode &lt;a href=&quot;https://www.cloudbees.com/blog/git-detached-head&quot;&gt;ler o original, em inglês, no site deles&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;h1 id=&quot;índice&quot;&gt;Índice&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#introdução&quot;&gt;Introdução&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#git-detached-head-reproduzindo-o-problema&quot;&gt;Reproduzindo o “Problema”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#o-que-é-um-head-no-git&quot;&gt;O que é um HEAD no Git?&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#você-está-no-estado-detached-head&quot;&gt;Você está no estado ‘detached HEAD’?&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#benefícios-de-um-head-desanexado&quot;&gt;Benefícios de um HEAD Desanexado&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#como-corrigir-um-head-desanexado-no-git&quot;&gt;Como Corrigir um HEAD Desanexado no Git?&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#cenário-1-estou-aqui-por-acidente&quot;&gt;Cenário #1: Estou Aqui por Acidente&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#cenário-2-fiz-mudanças-experimentais-e-quero-descartá-las&quot;&gt;Cenário #2: Fiz Mudanças Experimentais e Quero Descartá-las&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#cenário-3-fiz-mudanças-experimentais-e-quero-mantê-las&quot;&gt;Cenário #3: Fiz Mudanças Experimentais e Quero Mantê-las&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#removendo-a-mensagem-git-detached-head&quot;&gt;Removendo a Mensagem “Git Detached HEAD”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#git-detached-head-menos-assustador-do-que-parece&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;introdução&quot;&gt;Introdução&lt;/h2&gt;

&lt;p&gt;Iniciantes no Git frequentemente ficam confusos com algumas das mensagens que esta &lt;a href=&quot;https://www.atlassian.com/git/tutorials/what-is-version-control&quot;&gt;ferramenta de controle de versão&lt;/a&gt; apresenta. A mensagem “You are in ‘detached HEAD’ state” (Você está no estado ‘HEAD desanexado’) é certamente uma das mais estranhas. Após se deparar com essa mensagem, a maioria das pessoas começa a pesquisar freneticamente no Google por termos como “git detached HEAD”, “git detached HEAD fix”, ou similares, buscando qualquer coisa que possa ajudar. Se esse é o seu caso, você veio ao lugar certo.&lt;/p&gt;

&lt;p&gt;Aqui está a primeira coisa que você deve saber: &lt;em&gt;você não fez nada de errado&lt;/em&gt;. Seu repositório não está quebrado nem nada parecido. A expressão “Detached HEAD” pode soar um tanto bizarra, mas é um estado perfeitamente válido em um repositório Git. Claro, não é o estado &lt;em&gt;normal&lt;/em&gt;, que seria - você adivinhou! - quando o HEAD está anexado. A segunda coisa que você precisa saber é que voltar ao normal é super fácil. Se você só quer fazer isso e seguir com o seu dia, vá para a seção &lt;a href=&quot;#como-corrigir-um-head-desanexado-no-git&quot;&gt;“Como corrigir um HEAD desanexado no Git?”&lt;/a&gt; deste post para ver como é feito.&lt;/p&gt;

&lt;p&gt;Mas se você quer saber mais - e eu acho que quer - fique por aqui e nós vamos te ajudar. O que significa HEAD no Git? O que significa estar anexado ou desanexado? Essas são o tipo de perguntas que responderemos neste post. Ao final dele, você terá uma melhor compreensão dos fundamentos do Git, e HEADs desanexados nunca mais te incomodarão. Bora começar?&lt;/p&gt;

&lt;h2 id=&quot;git-detached-head-reproduzindo-o-problema&quot;&gt;Git Detached HEAD: Reproduzindo o “Problema”&lt;/h2&gt;

&lt;p&gt;Vamos começar com uma rápida demonstração de como chegar ao estado de HEAD desanexado. Criaremos um repositório e adicionaremos alguns commits a ele:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;git-head-demo
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;git-head-demo 
git init
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file.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 file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello World!&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; file.txt
git commit &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Add line to the file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Second file&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Com os comandos acima, criamos uma nova pasta com um novo repositório dentro dela. Em seguida, criamos um novo arquivo vazio e fizemos o commit com a mensagem “Criar arquivo”. Depois, adicionamos uma linha a esse arquivo e fizemos o commit da alteração, com a mensagem “Adicionar linha ao arquivo”. Por fim, criamos outro arquivo com uma linha de texto e também fizemos o commit. Se você usar o comando &lt;strong&gt;git log –oneline&lt;/strong&gt;, verá algo como isto:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-detached-head/image3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Digamos que, para fins de teste, precisamos ver como as coisas estavam no momento do segundo commit. Como faríamos isso? Na verdade, podemos fazer checkout de um commit da mesma forma que faríamos checkout de branches. Lembre-se, branches são apenas nomes para commits. Então, com base no exemplo de saída acima, executaríamos &lt;strong&gt;git checkout 87ec91d&lt;/strong&gt;. Tenha em mente que, se você estiver seguindo junto e executando esses comandos em seu próprio sistema, o hash para seus commits será diferente dos exemplos. Use o comando log para encontrá-lo.&lt;/p&gt;

&lt;p&gt;Após executar o comando, recebemos a mensagem “You are in ‘detached HEAD’ state[…]”. Antes de continuarmos, certifique-se de manter isso em mente: você chega ao estado de HEAD desanexado fazendo checkout diretamente de um commit.&lt;/p&gt;

&lt;h2 id=&quot;o-que-é-um-head-no-git&quot;&gt;O que é um HEAD no Git?&lt;/h2&gt;

&lt;p&gt;O que significa HEAD no Git? Para entender isso, precisamos dar um passo atrás e falar sobre os fundamentos.&lt;/p&gt;

&lt;p&gt;Um repositório Git é uma coleção de &lt;strong&gt;objetos&lt;/strong&gt; e &lt;strong&gt;referências&lt;/strong&gt;. Os objetos têm relações entre si, e as referências apontam para objetos e para outras referências. Os principais objetos em um repositório Git são commits, mas outros objetos incluem &lt;a href=&quot;https://developer.github.com/v3/git/blobs/&quot;&gt;blobs&lt;/a&gt; e &lt;a href=&quot;https://developer.github.com/v3/git/trees/&quot;&gt;trees&lt;/a&gt;. As referências mais importantes no Git são as &lt;a href=&quot;/pt/git-criar-branch&quot;&gt;branches&lt;/a&gt;, que você pode pensar como rótulos que você coloca em um commit.&lt;/p&gt;

&lt;p&gt;HEAD é outro tipo importante de referência. O propósito do HEAD é manter o controle do ponto atual em um repositório Git. Em outras palavras, HEAD responde à pergunta: “Onde eu estou agora?”&lt;/p&gt;

&lt;p&gt;Por exemplo, quando você usa o comando &lt;strong&gt;log&lt;/strong&gt;, como o Git sabe de qual commit ele deve começar a exibir os resultados? HEAD fornece a resposta. Quando você cria um novo commit, seu pai é indicado pelo local para onde o HEAD está apontando atualmente.&lt;/p&gt;

&lt;h3 id=&quot;você-está-no-estado-detached-head&quot;&gt;Você está no estado ‘detached HEAD’?&lt;/h3&gt;

&lt;p&gt;Você acabou de ver que HEAD no Git é apenas o nome de uma referência que indica o ponto atual em um repositório. Então, o que significa estar anexado ou desanexado?&lt;/p&gt;

&lt;p&gt;Na maioria das vezes, HEAD aponta para um nome de branch. Quando você adiciona um novo commit, a referência do seu branch é atualizada para apontar para ele, mas o HEAD permanece o mesmo. Quando você muda de branch, o HEAD é atualizado para apontar para o branch para o qual você mudou. Tudo isso significa que, nesses cenários, HEAD é sinônimo de “o último commit no branch atual”. Este é o estado &lt;em&gt;normal&lt;/em&gt;, no qual HEAD está &lt;em&gt;anexado&lt;/em&gt; a um branch.&lt;/p&gt;

&lt;p&gt;Uma representação visual do nosso repositório de demonstração seria assim:
&lt;img src=&quot;/img/git-detached-head/image5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Como você pode ver, HEAD aponta para o branch master, que aponta para o último commit. Tudo parece perfeito. Após executar &lt;strong&gt;git checkout 87ec91d&lt;/strong&gt;, o repositório fica assim:
&lt;img src=&quot;/img/git-detached-head/image4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Este é o estado de HEAD desanexado; HEAD está apontando diretamente para um commit em vez de um branch.&lt;/p&gt;

&lt;h3 id=&quot;benefícios-de-um-head-desanexado&quot;&gt;Benefícios de um HEAD Desanexado&lt;/h3&gt;

&lt;p&gt;Existem boas razões para você estar no estado de HEAD desanexado? Com certeza!&lt;/p&gt;

&lt;p&gt;Como você viu, você desanexa o HEAD fazendo checkout de um commit. Isso já é útil por si só, pois permite que você volte a um ponto anterior na história do projeto. Digamos que você queira verificar se um determinado bug já existia na terça-feira passada. Você pode usar o comando &lt;strong&gt;log&lt;/strong&gt;, filtrando por data, para encontrar o hash do commit relevante. Em seguida, você pode fazer checkout do commit e testar a aplicação, seja manualmente ou executando sua suíte de testes automatizados.&lt;/p&gt;

&lt;p&gt;E se você pudesse não apenas olhar para o passado, mas também mudá-lo? É isso que um HEAD desanexado permite que você faça. Vamos revisar como a mensagem de desanexação começa:&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;Você está no estado 'detached HEAD'.
Você pode olhar ao redor, fazer mudanças experimentais e fazer commits delas,
e você pode descartar quaisquer commits que fizer neste estado sem
impactar nenhum branch, simplesmente mudando de volta para um branch.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Neste estado, você pode fazer mudanças experimentais, efetivamente criando uma história alternativa. Então, vamos criar alguns commits adicionais no estado de HEAD desanexado e ver como nosso repositório fica depois:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Welcome to the alternate timeline, Morty!&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; new-file.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 new file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Another line&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; new-file.txt
git commit &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Add a new line to the file&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Agora temos dois commits adicionais que descendem do nosso segundo commit. Vamos executar &lt;strong&gt;git log –oneline&lt;/strong&gt; e ver o resultado:
&lt;img src=&quot;/img/git-detached-head/image7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Assim é como o diagrama fica agora:
&lt;img src=&quot;/img/git-detached-head/image6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;O que você deve fazer se quiser manter essas mudanças? E o que deve fazer se quiser descartá-las? É isso que veremos a seguir.&lt;/p&gt;

&lt;h2 id=&quot;como-corrigir-um-head-desanexado-no-git&quot;&gt;Como corrigir um HEAD desanexado no Git?&lt;/h2&gt;

&lt;p&gt;Você não pode corrigir o que não está quebrado. Como eu disse antes, um HEAD desanexado é um estado válido no Git. Não é um problema. Mas você ainda pode querer saber como voltar ao normal, e isso depende do motivo pelo qual você está nessa situação em primeiro lugar.&lt;/p&gt;

&lt;h3 id=&quot;cenário-1-estou-aqui-por-acidente&quot;&gt;Cenário #1: Estou aqui por acidente&lt;/h3&gt;

&lt;p&gt;Se você chegou ao estado de HEAD desanexado por acidente - ou seja, você não tinha a intenção de fazer checkout de um commit - voltar é fácil. Basta fazer checkout do branch em que você estava antes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git checkout &amp;lt;nome-do-branch&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Se você está usando o Git 2.23.0 ou mais recente, você também pode usar &lt;strong&gt;switch&lt;/strong&gt; em vez de &lt;strong&gt;checkout&lt;/strong&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git switch &amp;lt;nome-do-branch&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;cenário-2-fiz-mudanças-experimentais-e-quero-descartá-las&quot;&gt;Cenário #2: Fiz mudanças experimentais e quero descartá-las&lt;/h3&gt;

&lt;p&gt;Você entrou no estado de HEAD desanexado e fez alguns commits. O experimento não levou a lugar nenhum, e você não vai mais trabalhar nele. O que você faz? Você faz o mesmo que no cenário anterior: volta para o seu branch original. As mudanças que você fez enquanto estava na linha do tempo alternativa não terão nenhum impacto no seu branch atual.&lt;/p&gt;

&lt;h3 id=&quot;cenário-3-fiz-mudanças-experimentais-e-quero-mantê-las&quot;&gt;Cenário #3: Fiz mudanças experimentais e quero mantê-las&lt;/h3&gt;

&lt;p&gt;Se você quer manter as mudanças feitas com um HEAD desanexado, basta &lt;a href=&quot;/pt/git-criar-branch/&quot;&gt;criar um novo branch&lt;/a&gt; e mudar para ele. Você pode criá-lo logo após chegar a um HEAD desanexado ou após criar um ou mais commits. O resultado é o mesmo. A única restrição é que você deve fazê-lo antes de retornar ao seu branch normal.&lt;/p&gt;

&lt;p&gt;Vamos fazer isso em nosso repositório de demonstração:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git branch alt-history
git checkout alt-history&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Observe como o resultado de &lt;strong&gt;git log –oneline&lt;/strong&gt; é exatamente o mesmo de antes (a única diferença sendo o nome do branch indicado no último commit):
&lt;img src=&quot;/img/git-detached-head/image2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Poderíamos apenas executar &lt;strong&gt;git branch alt-history&lt;/strong&gt;, e estaríamos prontos. Essa é a nova - e final - versão do nosso diagrama:
&lt;img src=&quot;/img/git-detached-head/image1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;removendo-a-mensagem-git-detached-head&quot;&gt;Removendo a mensagem “Git Detached HEAD”&lt;/h2&gt;

&lt;p&gt;Antes de concluir, vamos compartilhar uma última dica rápida. Agora que você entende tudo sobre HEAD desanexado no Git e sabe que não é tão grave assim, ver essa mensagem toda vez que fizer checkout de um commit pode se tornar cansativo. Felizmente, há uma maneira de não ver mais o aviso. Basta executar o seguinte comando:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git config advice.detached &lt;span class=&quot;nb&quot;&gt;head false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Fácil, não é? Você também pode usar o modificador &lt;strong&gt;–global&lt;/strong&gt; se quiser que a mudança se aplique a todos os repositórios e não apenas ao atual.&lt;/p&gt;

&lt;h2 id=&quot;git-detached-head-menos-assustador-do-que-parece&quot;&gt;Git Detached HEAD: Menos assustador do que parece&lt;/h2&gt;

&lt;p&gt;Uma mensagem falando sobre cabeças não estarem anexadas não soa como uma mensagem de erro de software rotineira, certo? Bem, não é uma mensagem de erro.&lt;/p&gt;

&lt;p&gt;Como você viu neste post, um HEAD desanexado não significa que algo está errado com seu repositório. &lt;strong&gt;Detached HEAD&lt;/strong&gt; é apenas um estado menos usual em que seu repositório pode estar. Além de não ser um erro, pode ser bastante útil, permitindo que você execute experimentos que depois pode escolher manter ou descartar.&lt;/p&gt;

&lt;p&gt;Gostaria de aprender mais sobre Git? Confira alguns dos seguintes posts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/pt/git-historico-bonito/&quot;&gt;Fazendo Seu Histórico Git Ficar Bonitão Com Amend e Rebase&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/pt/git-bisect-intro/&quot;&gt;Git Bisect: Uma Introdução Para Iniciantes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/pt/git-criar-branch&quot;&gt;Git Criar Branch: 4 Maneiras Diferentes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obrigado por ler!&lt;/p&gt;
</description>
        <pubDate>Mon, 16 Sep 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/git-detached-head</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/git-detached-head</guid>
        
        <category>git</category>
        
        <category>tutorial</category>
        
        
      </item>
    
      <item>
        <title>[Tradução] Tudo o que você precisa saber sobre configuração e gerenciamento de segredos em .NET</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dz5ppacuo/image/upload/v1513817072/csharp8-1037x438_skogpz.jpg&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;Este post é uma tradução, cuja publicação foi autorizada pelo autor. Caso tenha interesse, &lt;a href=&quot;https://stenbrinke.nl/blog/configuration-and-secret-management-in-dotnet/&quot;&gt;leia o artigo original, em inglês.&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Eu decidi não traduzir as imagens, pois achei que seria muito trabalhoso. Portanto, as figuras que você verá são as mesmas do artigo original, com as informações nelas em inglês.&lt;/p&gt;

&lt;p&gt;Em respeito ao autor, procurei deixar o artigo o mais próximo possível do original: mantive &lt;em&gt;call to actions&lt;/em&gt; que o autor faz para suas palestras e conteúdos, e também mantive um pedido de contribução financeira ao final do artigo.&lt;/p&gt;

&lt;p&gt;A partir do índice, inicia-se o artigo de autoria de Sander ten Brinke. Após a conclusão do artigo, eu volto com algumas palavras antes de finalizar. Boa leitura!&lt;/p&gt;


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

&lt;h2 id=&quot;índice&quot;&gt;Índice&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#introdução&quot;&gt;Introdução&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#configuração-no-net&quot;&gt;Configuração no .NET&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#o-básico&quot;&gt;O básico&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#acesso-a-dados-estruturados&quot;&gt;Acesso a dados estruturados&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#como-tudo-isso-funciona&quot;&gt;Como tudo isso funciona&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#tratando-a-configuração-como-código&quot;&gt;Tratando a configuração como código&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#options-pattern&quot;&gt;options pattern&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#injeção-de-dependência&quot;&gt;Injeção de dependência&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#validação&quot;&gt;Validação&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#tempos-de-vida-da-configuração&quot;&gt;Tempos de vida da configuração&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#gerenciamento-de-segredos-durante-o-desenvolvimento&quot;&gt;Gerenciamento de segredos durante o desenvolvimento&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#o-provedor-de-configuração-de-user-secrets&quot;&gt;O provedor de configuração de user secrets&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#usando-user-secrets&quot;&gt;Usando user secrets&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#configurando-um-projeto-que-usa-user-secrets&quot;&gt;Configurando um projeto que usa user-secrets&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#meu-modelo-para-gerenciamento-de-configuração&quot;&gt;Meu modelo para gerenciamento de configuração&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#appsettingsjson&quot;&gt;appsettings.json&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#appsettingsdevelopmentjson&quot;&gt;appsettings.Development.json&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#user-secrets&quot;&gt;User Secrets&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#usando-o-azure-para-armazenar-a-configuração&quot;&gt;Usando o Azure para armazenar a configuração&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#armazenamento-de-segredos-no-azure-key-vault&quot;&gt;Armazenamento de segredos no Azure Key Vault&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#conectando-se-ao-azure-com-identidades-gerenciadas&quot;&gt;Conectando-se ao Azure com identidades gerenciadas&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#armazenamento-da-configuração-na-configuração-de-aplicativo-do-azure&quot;&gt;Armazenamento da configuração na Configuração de Aplicativo do Azure&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#finalizando&quot;&gt;Finalizando&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#links-para-a-demo&quot;&gt;Links para a demo&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#links-para-a-documentação-oficial&quot;&gt;Links para a documentação oficial&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#carlos-de-volta&quot;&gt;Carlos de volta&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;Este post é um complemento da minha palestra &lt;a href=&quot;https://sessionize.com/s/sander-ten-brinke/keep-it-secret-keep-it-safe-with-.net/48314&quot;&gt;Keep it secret, keep it safe with .NET&lt;/a&gt;! Se você não puder assistir a uma sessão dessa palestra, poderá ler este post em vez disso! Dessa forma, o maior número possível de pessoas poderá aprender sobre o sistema de configuração do .NET e como manter os segredos em segurança!&lt;/p&gt;

&lt;p&gt;Minha palestra oferece algumas informações mais detalhadas, portanto, se quiser saber mais, dê uma olhada na minha página &lt;a href=&quot;https://stenbrinke.nl/speaking&quot;&gt;Speaking&lt;/a&gt; para ver quando e onde darei essa palestra novamente! Você também pode &lt;a href=&quot;https://stenbrinke.nl/about/#contact-details&quot;&gt;entrar em contato&lt;/a&gt; se quiser que eu dê essa palestra em seu evento!&lt;/p&gt;

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

&lt;h2 id=&quot;introdução&quot;&gt;Introdução&lt;/h2&gt;

&lt;p&gt;Se você já escreve código há algum tempo, provavelmente já usou configuração de alguma forma. Pense em feature flags, configurações de log, configurações de autenticação etc. Talvez você tenha usado um arquivo de configuração com algumas configurações para o seu aplicativo ou talvez tenha usado variáveis de ambiente. Talvez você tenha usado ambos!&lt;/p&gt;

&lt;p&gt;Também é provável que você tenha interagido com segredos, que também considero parte de um sistema de configuração. Pense em strings de conexão e chaves de API. Elas devem ser sempre seguras!&lt;/p&gt;

&lt;p&gt;A configuração no .NET mudou radicalmente desde a introdução do .NET Core. Já se foi o tempo em que se usavam vários arquivos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Web.config&lt;/code&gt; e agora temos um sistema muito mais flexível. No entanto, um sistema flexível também pode ser um sistema complexo. É por isso que eu quis criar uma palestra e uma publicação no blog em que você aprenderá como funciona o sistema de configuração do .NET e como usá-lo de forma otimizada. Você também aprenderá a manter seus segredos seguros, tanto localmente quanto em produção, usando o poder da nuvem do Azure!&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;Este post contém &lt;strong&gt;tudo&lt;/strong&gt; que você precisa saber sobre configuração e gerenciamento de segredos no .NET. Ela não aborda todos os detalhes, mas abrange tudo o que acredito que um desenvolvedor .NET tem que saber. Considere-o um guia de bolso útil que você pode usar ou enviar a outras pessoas quando elas tiverem dúvidas sobre configuração e gerenciamento de segredos no .NET.&lt;/p&gt;

&lt;p&gt;Acho que esta post é muito útil porque são necessárias &lt;strong&gt;múltiplas horas&lt;/strong&gt; para &lt;em&gt;encontrar&lt;/em&gt; e ler completamente a documentação da Microsoft sobre esses tópicos. Se quiser saber mais, você encontrará links para a documentação oficial no final do post.&lt;/p&gt;

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

&lt;p&gt;Vamos começar!&lt;/p&gt;

&lt;h2 id=&quot;configuração-no-net&quot;&gt;Configuração no .NET&lt;/h2&gt;

&lt;p&gt;O sistema de configuração do .NET é muito flexível! Você pode usar vários provedores de configuração, sendo que cada um deles pode ter um formato de configuração diferente:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/configuracao-dotnet/configuration-overview.webp&quot; alt=&quot;Uma imagem que mostra uma visão geral do sistema de configuração do .NET com a interface IConfiguration e vários provedores&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Uma visão geral do sistema de configuração do .NET.&lt;br /&gt;
&lt;a href=&quot;https://learn.microsoft.com/dotnet/core/extensions/configuration?WT.mc_id=DT-MVP-5005050#concepts-and-abstractions&quot;&gt;Extraído da documentação oficial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outras fontes podem ser arquivos como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.xml&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ini&lt;/code&gt; e muito mais. Você pode até mesmo conectar seu sistema de configuração à nuvem, o que faremos mais adiante!&lt;/p&gt;

&lt;h3 id=&quot;o-básico&quot;&gt;O Básico&lt;/h3&gt;

&lt;p&gt;Como você pode ver, toda a sua configuração pode ser acessada usando a interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt;. Com isso, você pode recuperar seus valores de uma maneira fortemente tipada. Um exemplo:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IConfiguration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetApiKey&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;// GetValue&amp;lt;&amp;gt; permite que você passe o tipo de retorno&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiKey&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;”&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; 

    &lt;span class=&quot;c1&quot;&gt;// A variante do indexador sempre retorna uma string&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiKey&lt;/span&gt;&lt;span class=&quot;err&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;method1&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;/figure&gt;

&lt;p&gt;Você perceberá que não estamos especificando qual provedor deve ser usado para recuperar a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiKey&lt;/code&gt;. Isso ocorre porque isso não deveria importar; a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt; esconde toda essa complexidade de nós e, portanto, cria flexibilidade. O sistema de configuração decide qual provedor usar com base na ordem dos provedores. Falaremos mais sobre isso mais tarde!&lt;/p&gt;

&lt;h3 id=&quot;acesso-a-dados-estruturados&quot;&gt;Acesso a dados estruturados&lt;/h3&gt;

&lt;p&gt;Um recurso muito avançado do sistema de configuração do .NET é o fato de ele oferecer suporte a dados estruturados. Isso é muito útil porque permite que você agrupe valores de configuração relacionados. Todos os provedores oferecem suporte a dados estruturados, mas se você já trabalhou com um projeto ASP.NET Core, provavelmente reconhecerá o mais comum, que é &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt;. O JSON a seguir é um exemplo de um arquivo desse tipo:&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;{
  “Logging&quot;: {
    “LogLevel&quot;: {
      “Default” (Padrão): “Informações”,
      “Microsoft.AspNetCore&quot;: “Warning”
    }
  },
  “AllowedHosts&quot;: “*”,

  “ConnectionStrings&quot;: {
    “Banco de dados&quot;: “CONNECTIONSTRING_HERE”
  },

  “Features” (Recursos): {
    “EnableNewUI&quot;: false
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Você pode imaginar o objeto raiz e as seções &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Logging&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConnectionStrings&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Features&lt;/code&gt; como “dados estruturados”.&lt;/p&gt;

&lt;p&gt;Para interagir com essas seções no .NET, você pode usar o código a seguir.&lt;/p&gt;

&lt;div class=&quot;callout callout-warning&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;⚠️&lt;/span&gt;
    Aviso
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;O código a seguir não é a melhor maneira de interagir com dados estruturados! Falaremos sobre maneiras melhores (usando o padrão Options) &lt;a href=&quot;#options-pattern&quot;&gt;mais adiante&lt;/a&gt;.&lt;/p&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IConfiguration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;// ...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IConfigurationSection&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetFeaturesSection&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;// GetSection retorna nulo quando a seção não pode ser encontrada&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetSection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Features&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;”&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// GetRequiredSection dispara uma exceção quando a seção não pode ser encontrada.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// SEMPRE prefira esse método ao GetSection para evitar bugs desagradáveis!&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;method2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetRequiredSection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Features&lt;/span&gt;&lt;span class=&quot;err&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;method2&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;GetEnableNewUI&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;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EnableNewUI&lt;/span&gt;&lt;span class=&quot;err&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;/figure&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfigurationSection&lt;/code&gt; fornece a mesma API que a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt;, portanto, você pode chamar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;featuresSection.GetValue&amp;lt;bool&amp;gt;(“EnableNewUI”)&lt;/code&gt; para obter o valor dessa seção. Também é possível acessar diretamente um valor de configuração que existe dentro de uma seção usando um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt;, que pode ser visto em uso no método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetEnableNewUI&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;Os dados estruturados não se limitam aos arquivos JSON. Todos os provedores são compatíveis com eles, embora a sintaxe para especificar uma seção possa ser diferente. Por exemplo, para fornecer um valor para &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EnableNewUI&lt;/code&gt; usando uma variável de ambiente, você terá que criar uma chamada &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Features__EnableNewUI&lt;/code&gt;.&lt;/p&gt;

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

&lt;h3 id=&quot;como-tudo-isso-funciona&quot;&gt;Como tudo isso funciona?&lt;/h3&gt;

&lt;p&gt;Estamos usando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt; em alguns exemplos. Você deve estar se perguntando como tudo isso funciona nos bastidores; como criar uma instância de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt; e como configurá-la? Vamos dar uma olhada!&lt;/p&gt;

&lt;p&gt;Para criar uma instância de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt;, você precisará usar a classe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConfigurationBuilder&lt;/code&gt; (ou outra classe que implemente &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfigurationBuilder&lt;/code&gt;). Essa classe usa o padrão Builder para que você possa adicionar vários provedores. No final, você chama &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Build()&lt;/code&gt; e acaba com um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfigurationRoot&lt;/code&gt;. É a mesma coisa que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt;, mas também tem uma lista de todos os provedores que você adicionou. Você nunca deve usar o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfigurationRoot&lt;/code&gt; diretamente, pois não deve acessar os provedores por baixo do pano. Um exemplo:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigurationBuilder&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;AddJsonFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sharedsettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;”&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;AddJsonFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;appsettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;”&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;AddEnvironmentVariables&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// E assim por diante...&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;IConfigurationRoot&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configuration&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;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A ordem desses provedores é muito importante porque se trata de um sistema em camadas. Dê uma olhada na imagem a seguir:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/configuracao-dotnet/configuration-providers-layers.webp&quot; alt=&quot;Uma imagem que mostra a importância da ordem dos provedores de configuração&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Uma visão geral da importância da ordem dos provedores de configuração.&lt;br /&gt;
&lt;a href=&quot;https://www.manning.com/books/asp-net-core-in-action-second-edition&quot;&gt;ASP.NET Core in Action, Second Edition (Permissão concedida pelo autor Andrew Lock)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sharedsettings.json&lt;/code&gt; tenha um valor para todos os valores de configuração usados pelo aplicativo. O &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt; e as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Variáveis de ambiente&lt;/code&gt; contêm um subconjunto desses valores. Como o provedor para as variáveis de ambiente foi adicionado por último, ele tem a prioridade mais alta. Portanto, se você quiser recuperar um valor de configuração chamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiKey&lt;/code&gt;, o sistema examinará primeiro as variáveis de ambiente. Se ele existir, será retornado, mesmo que outros provedores também contenham um valor para &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiKey&lt;/code&gt;. No entanto, se as variáveis de ambiente não contiverem um valor para &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiKey&lt;/code&gt;, ele passará para o provedor que foi adicionado antes dele e pesquisará lá, e assim por diante.&lt;/p&gt;

&lt;h4 id=&quot;os-valores-default&quot;&gt;Os valores default&lt;/h4&gt;

&lt;p&gt;Talvez você esteja um pouco confuso neste ponto. Eu certamente estava quando aprendi sobre o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfigurationBuilder&lt;/code&gt; e a importância dessas camadas. Por quê? Bem, percebi que estava usando o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt; em muitos projetos, mas nunca tinha ouvido falar do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfigurationBuilder&lt;/code&gt; antes. Então, como eu poderia estar usando o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Isso funciona porque, se você trabalhar em um aplicativo .NET que &lt;a href=&quot;https://learn.microsoft.com/dotnet/core/extensions/generic-host?WT.mc_id=DT-MVP-5005050&quot;&gt;usa um Host&lt;/a&gt;, ele definirá todo um sistema de configuração para você por padrão! Por exemplo, &lt;a href=&quot;https://learn.microsoft.com/aspnet/core/fundamentals/host/generic-host?WT.mc_id=DT-MVP-5005050&quot;&gt;projetos ASP.NET Core&lt;/a&gt; e &lt;a href=&quot;https://learn.microsoft.com/dotnet/core/extensions/workers?WT.mc_id=DT-MVP-5005050#worker-service-template&quot;&gt;workers services&lt;/a&gt; usam um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Host&lt;/code&gt;, portanto, na maioria dos projetos, isso será feito para você! Agora vamos dar uma olhada em como isso funciona.&lt;/p&gt;

&lt;p&gt;Em um aplicativo ASP.NET Core padrão, o seguinte é configurado para você.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Provedor&lt;/th&gt;
      &lt;th&gt;Exemplo&lt;/th&gt;
      &lt;th&gt;Notas&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;appsettings.json&lt;/td&gt;
      &lt;td&gt;{ “Key”: “default value” }&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;appsettings.{ENVIRONMENT}.json&lt;/td&gt;
      &lt;td&gt;{ “Key”: “development value” }&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;user secrets (desenvolvimento)&lt;/td&gt;
      &lt;td&gt;dotnet user-secrets set “key” “development value”&lt;/td&gt;
      &lt;td&gt;Também pode ser definido em IDEs. Mais sobre isso posteriormente.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Variáveis de ambiente&lt;/td&gt;
      &lt;td&gt;Powershell: setx key “valor do ambiente” &lt;br /&gt; Bash: export key=‘valor do ambiente’&lt;/td&gt;
      &lt;td&gt;Também pode ser definido em IDEs. Muito popular em implantações do Docker/Kubernetes.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Argumentos da linha de comando&lt;/td&gt;
      &lt;td&gt;dotnet run –key “important value”&lt;/td&gt;
      &lt;td&gt;Também pode ser definido nos IDEs.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;O item no topo tem a prioridade mais baixa. Portanto, se você chamar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Configuration[“key”]&lt;/code&gt;, obterá como resultado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;important value&lt;/code&gt;, mesmo que o User Secrets também forneça um valor.&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;O provedor User secrets só é adicionado quando o &lt;em&gt;Environment&lt;/em&gt; é definido como &lt;em&gt;Development&lt;/em&gt;. Os ambientes serão tratados a seguir. Os user secrets são tratados em profundidade &lt;a href=&quot;#user-secrets&quot;&gt;mais adiante&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;O Visual Studio (e outros IDEs, como o JetBrains Rider) oferecem suporte à configuração de variáveis de ambiente/argumentos de linha de comando em seu IDE quando você acessa as propriedades do projeto. No entanto, aconselho &lt;strong&gt;contra&lt;/strong&gt; o uso disso durante o desenvolvimento. Eu nunca uso variáveis de ambiente ou argumentos de linha de comando durante o desenvolvimento porque é mais difícil editá-los do que simplesmente abrir um arquivo. Armazená-los em &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Development.json&lt;/code&gt; (que será abordado a seguir) é mais conveniente para você e seus colegas.&lt;/p&gt;

&lt;h4 id=&quot;configuração-e-ambientes&quot;&gt;Configuração e Ambientes&lt;/h4&gt;

&lt;p&gt;O provedor &lt;em&gt;appsettings.{&lt;strong&gt;ENVIRONMENT&lt;/strong&gt;}.json&lt;/em&gt; é um pouco diferente dos outros provedores. Isso ocorre porque ele depende do &lt;a href=&quot;https://learn.microsoft.com/aspnet/core/fundamentals/environments?WT.mc_id=DT-MVP-5005050&quot;&gt;ambiente do aplicativo&lt;/a&gt;. O ambiente atual do aplicativo é lido a partir do valor da variável de ambiente &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOTNET_ENVIRONMENT&lt;/code&gt; ou &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASPNETCORE_ENVIRONMENT&lt;/code&gt;. Se o seu projeto não for um projeto ASP.NET Core, o aplicativo verificará apenas &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOTNET_ENVIRONMENT&lt;/code&gt;. Os projetos ASP.NET Core retornam para &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOTNET_ENVIRONMENT&lt;/code&gt; quando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASPNETCORE_ENVIRONMENT&lt;/code&gt; não existe.&lt;/p&gt;

&lt;p&gt;O ambiente será considerado como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Production&lt;/code&gt; quando essas variáveis de ambiente não existirem.&lt;/p&gt;

&lt;p&gt;Quando você cria um projeto ASP.NET Core, um arquivo chamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;launchSettings.json&lt;/code&gt; será criado na pasta &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Properties&lt;/code&gt;. Aqui, você pode ver que a variável de ambiente &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASPNETCORE_ENVIRONMENT&lt;/code&gt; está definida como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Development&lt;/code&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;{
  // Muitos outros detalhes foram removidos desse arquivo para fins de brevidade
  “$schema&quot;: “https://json.schemastore.org/launchsettings.json”,
  “profiles&quot;: {
    “MY_PROJECT&quot;: {
      “commandName&quot;: “MY_PROJECT”,
      “applicationUrl&quot;: “https://localhost:7237;http://localhost:5292”,
      “environmentVariables&quot;: {
        “ASPNETCORE_ENVIRONMENT&quot;: “Development”
      }
    }
  }
}

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

&lt;p&gt;O resultado do sistema de configuração trabalhando em conjunto com o ambiente do aplicativo resulta em um recurso muito poderoso, pois permite que você crie arquivos de configuração diferentes para cada ambiente.&lt;/p&gt;

&lt;p&gt;Você pode armazenar valores padrão em &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt; e substituí-los em &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Development.json&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Test.json&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Staging.json&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Production.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por exemplo, digamos que você tenha terminado o novo design de uma página de checkout de uma loja virtual. Ele ainda precisa ser testado e revisado por outras pessoas em um ambiente de teste, mas ainda não deve entrar em produção. Esse parece ser um caso de uso perfeito para feature flags! Você poderia criar um feature flag chamado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EnableNewCheckoutUI&lt;/code&gt; e defini-lo como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; em &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt; como o valor padrão. Em seguida, você pode substituir esses valores em &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Development.json&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Test.json&lt;/code&gt; para que eles sejam ativados somente lá:&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;// appsettings.json
{
  “FeatureFlags&quot;: {
    “EnableNewCheckoutUI&quot;: false
  }
}

// appsettings.Development.json e appsettings.Test.json
{
  “FeatureFlags&quot;: {
    “EnableNewCheckoutUI&quot;: true
  }
}

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

&lt;p&gt;Você não está limitado aos nomes de ambiente mencionados acima; eles são apenas os padrões que o .NET usa. Se quiser usar um nome diferente, configure a variável de ambiente &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASPNETCORE_ENVIRONMENT&lt;/code&gt; com o nome de sua escolha e crie um arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.ENV_NAME.json&lt;/code&gt; correspondente. A única outra coisa que você precisa fazer é garantir que o ambiente em que você executa seu aplicativo tenha &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASPNETCORE_ENVIRONMENT&lt;/code&gt; ou &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOTNET_ENVIRONMENT&lt;/code&gt; definido com o valor correto.&lt;/p&gt;

&lt;h3 id=&quot;tratando-a-configuração-como-código&quot;&gt;Tratando a Configuração Como Código&lt;/h3&gt;

&lt;p&gt;Anteriormente, elogiei o sistema de configuração do .NET e o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt; por serem flexíveis e ricos em recursos. Falei sobre seu suporte a dados estruturados e sobre a recuperação de valores de uma hierarquia de configuração mais profunda. Mas você sabia que pode fazer muito mais com dados estruturados?&lt;/p&gt;

&lt;p&gt;Digamos que nosso aplicativo se comunique com uma API externa usando HTTP. Para isso, precisamos de um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiUrl&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiKey&lt;/code&gt; e talvez queiramos configurar um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TimeoutInMilliseconds&lt;/code&gt;. Do ponto de vista do código, talvez queiramos armazenar esses valores em uma classe (ou &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;record&lt;/code&gt;) porque eles pertencem um ao outro:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&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;ExternalApiSettings&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;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ApiUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ApiKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;n&quot;&gt;TimeoutInMilliseconds&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;/figure&gt;

&lt;p&gt;Em seguida, teríamos uma classe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiClient&lt;/code&gt; que usa a configuração e a classe que acabamos de criar:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&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;ExternalApiClient&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;n&quot;&gt;IConfiguration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_configuration&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;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IConfiguration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configuration&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;_configuration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configuration&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;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CallExternalApi&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;IConfigurationSection&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;externalApiSettingsSection&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetRequiredSection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExternalApiSettings&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;”&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;// Método 1 (Get&amp;lt;TType&amp;gt;() obtém os valores dessa seção e os mapeia em uma nova instância da classe fornecida)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ExternalApiSettings&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;externalApiSettingsSection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExternalApiSettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt; 

        &lt;span class=&quot;c1&quot;&gt;// Método 2 (Bind() espera uma instância existente de um tipo e mapeará os valores para essa instância existente)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ExternalApiSettings&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetRequiredSection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExternalApiSettings&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;”&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;settings2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Faça algo com essas configurações aqui...&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;/figure&gt;

&lt;p&gt;Isso parece bem legal, certo? Em vez de realizar 3 chamadas para obter cada propriedade de configuração relacionada à API individualmente, podemos mapeá-las em um objeto fortemente tipado. Agora podemos tratar nossa configuração como código! Poderíamos até criar métodos em nossa classe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiSettings&lt;/code&gt; para torná-la ainda mais poderosa!&lt;/p&gt;

&lt;p&gt;No entanto, há algumas desvantagens importantes nessa abordagem.&lt;/p&gt;

&lt;h4 id=&quot;desvantagens&quot;&gt;Desvantagens&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;A primeira desvantagem é que o nosso &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiClient&lt;/code&gt; requer uma instância de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt; para funcionar. Essa é uma dependência muito grande e um grande desperdício, considerando que ele usa apenas 3 valores de configuração! Além disso, essa classe agora pode acessar outros valores de configuração, como uma string de conexão a um banco de dados, configurações de registro, feature flags etc., mesmo que não precise dessas informações.&lt;/li&gt;
  &lt;li&gt;A segunda desvantagem é que essa classe está violando o princípio da responsabilidade única. Ela não é responsável apenas por chamar a API externa, mas também por interagir com o sistema de configuração para poder chamar essa API externa.&lt;/li&gt;
  &lt;li&gt;Como essa classe interage diretamente com o sistema de configuração, ela depende de sua estrutura e, portanto, está fortemente acoplada. Qualquer alteração na seção de configuração &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiSettings&lt;/code&gt; (como o nome ou os nomes de seus filhos) causaria problemas em tempo de execução.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então, o que podemos fazer em relação a isso? Reescrevê-la em Rust 🦀? Não, podemos usar o options pattern!&lt;/p&gt;

&lt;h2 id=&quot;options-pattern&quot;&gt;Options Pattern&lt;/h2&gt;

&lt;p&gt;O &lt;em&gt;options pattern&lt;/em&gt; (“padrão de opções”) permite que você faça um uso ainda melhor do sistema de configuração do .NET 🚀! Ele permite a você desacoplar seu aplicativo do sistema de configuração e adiciona muitos recursos poderosos a esse sistema, como:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Injeção de dependência&lt;/li&gt;
  &lt;li&gt;Validação&lt;/li&gt;
  &lt;li&gt;Diferentes tempos de vida de configuração&lt;/li&gt;
  &lt;li&gt;E muito mais!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para começar a usar o options pattern de forma eficaz, é necessário criar classes/records das suas seções de configuração. Já fizemos isso no exemplo anterior, portanto, vamos continuar com ele:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&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;ExternalApiSettings&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;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ApiUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ApiKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;n&quot;&gt;TimeoutInMilliseconds&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;/figure&gt;

&lt;h3 id=&quot;injeção-de-dependência&quot;&gt;Injeção de dependência&lt;/h3&gt;

&lt;p&gt;O options pattern funciona muito bem com a injeção de dependência! Para isso, basta registrar sua classe/record de opções na coleção de serviços. Dependendo do seu projeto, o ponto de entrada para isso pode ser o método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Startup.cs -&amp;gt; ConfigureServices(IServiceCollection services)&lt;/code&gt; ou em algum lugar em seu &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Program.cs&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExternalApiSettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Passe em uma instância existente de IConfiguration&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Isso adicionará uma instância de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptions&amp;lt;ExternalApiSettings&amp;gt;&lt;/code&gt; ao seu contêiner de injeção de dependência. Para ver os benefícios dessa abordagem, vamos dar uma olhada em como poderíamos melhorar nosso &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiClient&lt;/code&gt; de antes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&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;ExternalApiClient&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;n&quot;&gt;ExternalApiSettings&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_externalApiSettings&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;ExternalApiClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExternalApiSettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&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;// Importante: o padrão Options é “preguiçoso”. Isso significa que as opções são mapeadas somente quando você as solicita chamando .Value!&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Isso é feito apenas uma vez, portanto, você não precisa se preocupar com o desempenho.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_externalApiSettings&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&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;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CallExternalApi&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;// Faz algo com essas configurações aqui...&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;/figure&gt;

&lt;p&gt;Isso eliminou todas as desvantagens de antes! Nosso &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiClient&lt;/code&gt; não tem mais uma dependência do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt; e não está mais acoplado ao sistema de configuração. Ele também não precisa mais se preocupar com a estrutura do sistema de configuração.&lt;/p&gt;

&lt;p&gt;Você pode argumentar que temos uma dependência indireta do sistema de configuração por causa da chamada &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.Configure&amp;lt;&amp;gt;(configuration)&lt;/code&gt; de antes, mas você não é obrigado a usar esse método para configurar suas opções. Você pode criar uma instância de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptions&amp;lt;T&amp;gt;&lt;/code&gt; usando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.Extensions.Options.Options.Create()&lt;/code&gt; se precisar criar uma instância manualmente, e pode passar quaisquer dados que desejar. Você pode até mesmo criar opções com base em outras dependências usando o método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Configure&amp;lt;TDep1,...&amp;gt;()&lt;/code&gt; do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OptionsBuilder&lt;/code&gt;, que será discutido a seguir.&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;Talvez você se pergunte por que precisamos envolver nossa classe de configurações com uma interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptions&amp;lt;&amp;gt;&lt;/code&gt;. Isso ocorre porque ela permite que você use alguns recursos mais avançados sobre os quais falaremos a seguir.&lt;/p&gt;

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

&lt;h3 id=&quot;validação&quot;&gt;Validação&lt;/h3&gt;

&lt;p&gt;Meu recurso favorito do sistema de configuração do .NET é a facilidade com que é possível validar sua configuração! Acredito que essa seja uma das partes mais importantes de qualquer aplicativo, e não vejo que ela seja usada com frequência. O motivo pelo qual acredito que a configuração é uma das partes mais importantes de qualquer aplicativo é porque ela abriga definições muito importantes do seu aplicativo.&lt;/p&gt;

&lt;p&gt;Um aplicativo configurado incorretamente pode ter resultados desastrosos. Na pior das hipóteses, imagine que o seu ambiente de teste esteja se conectando acidentalmente aos recursos do ambiente de produção. Agora imagine que você testaria uma função de exclusão em massa e acidentalmente excluiria todos os seus dados de produção. Isso seria um desastre!&lt;/p&gt;

&lt;p&gt;É por isso que queremos validar nossa configuração. Se o nosso aplicativo for iniciado com um sistema de configuração incorreto, queremos sair imediatamente.&lt;/p&gt;

&lt;p&gt;Então, como configuramos isso? É mais fácil do que você imagina. Eu gosto de usar &lt;a href=&quot;https://www.infoworld.com/article/3543302/how-to-use-data-annotations-in-c-sharp.html&quot;&gt;Data Annotations&lt;/a&gt; para minhas validações de opções quando não preciso de regras de validação complexas, portanto, vamos modificar nosso &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiSettings&lt;/code&gt; desta forma:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&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;ExternalApiSettings&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;Required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Se o ApiUrl não estiver definido, a configuração é inválida&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ApiUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;n&quot;&gt;Required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Se a ApiKey não for definida, a configuração será inválida&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ApiKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;nf&quot;&gt;Range&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;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_000_00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Se o TimeoutInMilliseconds não for definido (o padrão é 0) ou for maior que 100000, a configuração será inválida&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;n&quot;&gt;TimeoutInMilliseconds&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&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;/figure&gt;

&lt;p&gt;Agora, vamos alterar a forma como registramos essas opções no contêiner de injeção de dependência:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExternalApiSettings&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;BindConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExternalApiSettings&lt;/span&gt;&lt;span class=&quot;err&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;nf&quot;&gt;ValidateDataAnnotations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Lança uma OptionsValidationException se a configuração for inválida&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ValidateOnStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Altamente recomendado!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Em vez de usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Configure&amp;lt;TType&amp;gt;(configuration)&lt;/code&gt;, agora usamos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AddOptions&amp;lt;TType&amp;gt;()&lt;/code&gt;. Isso retorna um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OptionsBuilder&lt;/code&gt; e nos permite usar alguns métodos poderosos.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;O primeiro que usamos é o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BindConfiguration()&lt;/code&gt;. Esse método recupera o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt; do contêiner de injeção de dependência e vincula a seção que passamos. Isso é útil porque não precisamos mais passar manualmente nossa configuração.&lt;/li&gt;
  &lt;li&gt;Em seguida, chamamos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ValidateDataAnnotations()&lt;/code&gt;. Isso validará nossa seção de configuração com base nos atributos que definimos nas propriedades.
    &lt;ol&gt;
      &lt;li&gt;Observação: você precisa instalar o pacote nuget &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Extensions.Options.DataAnnotations&quot;&gt;Microsoft.Extensions.Options.DataAnnotations&lt;/a&gt; se não tiver esse método disponível.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Por fim, chamamos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ValidateOnStart()&lt;/code&gt;. Essa etapa é &lt;strong&gt;muito&lt;/strong&gt; importante! Por padrão, suas opções só serão validadas quando você chamar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.Value&lt;/code&gt; nelas em algum lugar, como em uma classe onde elas são injetadas. Isso significa que seu aplicativo NÃO lançaria um erro e sairia na inicialização quando sua configuração fosse inválida! O &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ValidateOnStart()&lt;/code&gt; validará sua configuração depois que o aplicativo terminar de se inicializar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Você também pode validar seu código de muitas outras maneiras. Você pode usar a interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IValidatableOptions&amp;lt;&amp;gt;&lt;/code&gt; para implementar uma lógica de validação complexa ou pode chamar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Validate(Func&amp;lt;TOptions, bool&amp;gt; validation)&lt;/code&gt; para escrever uma lógica de validação personalizada como parte do construtor de opções. Você pode até mesmo &lt;a href=&quot;https://andrewlock.net/adding-validation-to-strongly-typed-configuration-objects-using-flentvalidation/&quot;&gt;integrá-lo ao FluentValidation&lt;/a&gt;!&lt;/p&gt;

&lt;h3 id=&quot;tempos-de-vida-da-configuração&quot;&gt;Tempos de vida da configuração&lt;/h3&gt;

&lt;p&gt;Por fim, gostaria de falar sobre o tempo de vida do padrão Options. O &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptions&amp;lt;T&amp;gt;&lt;/code&gt; é um singleton. Isso significa que, se um de seus &lt;a href=&quot;https://learn.microsoft.com/dotnet/core/extensions/configuration-providers?WT.mc_id=DT-MVP-5005050#json-configuration-provider&quot;&gt;provedores de configuração for atualizado em tempo de execução&lt;/a&gt;, as opções não serão atualizadas. Isso ocorre porque as opções são mapeadas apenas uma vez quando você chama &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.Value&lt;/code&gt; sobre elas.&lt;/p&gt;

&lt;p&gt;Isso pode ser considerado positivo, pois significa que seu aplicativo não mudará repentinamente de comportamento quando a configuração for alterada. No entanto, você também pode dizer que isso é ruim porque talvez não queira ter que fazer deploy ou reiniciar o aplicativo quando alterar a configuração. Nesse caso, é melhor usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptionsSnapshot&amp;lt;T&amp;gt;&lt;/code&gt; ou &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptionsMonitor&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/configuracao-dotnet/options-lifetimes.webp&quot; alt=&quot;Visão geral dos recursos de IOptions, IOptionsSnapshot e IOptionsMonitor&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Visão geral dos recursos de IOptions, IOptionsSnapshot e IOptionsMonitor&lt;/p&gt;

&lt;h4 id=&quot;ioptionssnapshot&quot;&gt;IOptionsSnapshot&lt;/h4&gt;

&lt;p&gt;Em vez de injetar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptions&amp;lt;T&amp;gt;&lt;/code&gt; em uma de suas classes, você pode injetar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptionsSnapshot&amp;lt;T&amp;gt;&lt;/code&gt;. Isso recarregará esse tipo específico de opções a cada &lt;a href=&quot;https://learn.microsoft.com/dotnet/core/extensions/dependency-injection?WT.mc_id=DT-MVP-5005050#scoped&quot;&gt;scope&lt;/a&gt;. Um escopo no .NET é um termo abstrato. Um escopo pode ser uma solicitação HTTP, por exemplo. Portanto, para cada solicitação HTTP, ele recarregaria as opções e elas permaneceriam consistentes para toda a solicitação. Isso significa que, se você alterar sua configuração, ela só será atualizada em uma nova solicitação.&lt;/p&gt;

&lt;div class=&quot;callout callout-warning&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;⚠️&lt;/span&gt;
    Aviso
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptionsSnapshot&amp;lt;T&amp;gt;&lt;/code&gt; pode causar &lt;a href=&quot;https://github.com/dotnet/runtime/issues/53793&quot;&gt;desempenho ruim.&lt;/a&gt;&lt;/p&gt;

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

&lt;h4 id=&quot;ioptionsmonitor&quot;&gt;IOptionsMonitor&lt;/h4&gt;

&lt;p&gt;O &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOptionsMonitor&amp;lt;T&amp;gt;&lt;/code&gt; não funciona com escopos. Em vez disso, você precisa chamar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.CurrentValue&lt;/code&gt; (em vez de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.Value&lt;/code&gt;) para recuperar a versão atual. No entanto, é preciso ter cuidado com a forma como você acessa a sua configuração! Imagine um cenário em que sua configuração é alterada no meio de uma solicitação HTTP. Chamar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.CurrentValue&lt;/code&gt; no início e no final de uma solicitação resultaria em valores diferentes, o que cria um risco de sincronização. Você pode registrar uma chamada de retorno usando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnChange()&lt;/code&gt; para ser notificado sobre esses eventos.&lt;/p&gt;

&lt;p&gt;Essa interface é mais útil em um cenário de trabalho em segundo plano que é instanciado apenas uma vez, mas que se beneficiaria da capacidade de lidar com alterações de configuração.&lt;/p&gt;

&lt;h2 id=&quot;gerenciamento-de-segredos-durante-o-desenvolvimento&quot;&gt;Gerenciamento de segredos durante o desenvolvimento&lt;/h2&gt;

&lt;p&gt;Se você vai tirar alguma conclusão dEste post, que seja a seguinte:&lt;/p&gt;

&lt;div class=&quot;callout callout-error&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;❌&lt;/span&gt;
    Importante
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Nunca armazene segredos em seu repositório git! Considere o uso de uma ferramenta de verificação de código como &lt;a href=&quot;https://docs.github.com/en/enterprise-cloud@latest/get-started/learning-about-github/about-github-advanced-security&quot;&gt;GitHub Advanced Security&lt;/a&gt;, &lt;a href=&quot;https://azure.microsoft.com/products/devops/github-advanced-security?WT.mc_id=DT-MVP-5005050&quot;&gt;GitHub Advanced Security for Azure DevOps&lt;/a&gt; ou &lt;a href=&quot;https://www.gitguardian.com/&quot;&gt;GitGuardian&lt;/a&gt; para evitar que segredos sejam vazados.&lt;/p&gt;

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

&lt;p&gt;Se você armazenar segredos em seu repositório git e o repositório for comprometido, seus segredos também serão comprometidos. Acho que não preciso explicar por que isso é ruim. Então, como podemos evitar que isso aconteça com o .NET?&lt;/p&gt;

&lt;p&gt;Usando o provedor de configuração de user secrets (segredos de usuário).&lt;/p&gt;

&lt;h3 id=&quot;o-provedor-de-configuração-de-user-secrets&quot;&gt;O provedor de configuração de user secrets&lt;/h3&gt;

&lt;p&gt;Mencionei o provedor de configuração de user secrets &lt;a href=&quot;#os-valores-default&quot;&gt;anteriormente&lt;/a&gt;. Esse provedor de configuração foi criado para desenvolvimento local &lt;em&gt;somente&lt;/em&gt;. Ele permite que você armazene segredos em seu computador local sem precisar se preocupar com o risco de eles serem versionados no repositório git, pois são armazenados em um local diferente:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Windows: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%APPDATA%\Microsoft\UserSecrets\&amp;lt;user_secrets_id&amp;gt;\secrets.json&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Mac e Linux: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.microsoft/usersecrets/&amp;lt;user_secrets_id&amp;gt;/secrets.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse arquivo é muito semelhante ao provedor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt;. Basta inserir JSON nele e você poderá acessá-lo com o sistema de configuração do .NET. Quando seu aplicativo for iniciado e sua variável de ambiente &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASPNETCORE_ENVIRONMENT&lt;/code&gt; ou &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOTNET_ENVIRONMENT&lt;/code&gt; estiver definida como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Development&lt;/code&gt;, ele carregará automaticamente o provedor de configuração de user secrets &lt;em&gt;desde que seu projeto esteja configurado para usar esse provedor&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;callout callout-warning&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;⚠️&lt;/span&gt;
    Aviso
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Mesmo que esse provedor tenha o nome “secret”, esteja avisado! O conteúdo do arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secrets.json&lt;/code&gt; não é criptografado. Se você trabalha em um ambiente em que armazenar segredos na própria máquina é arriscado, considere usar &lt;a href=&quot;#using-the-key-vault-during-local-development&quot;&gt;um armazenamento de segredos externo como o Azure KeyVault durante o desenvolvimento&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Esse provedor de configuração pode ser acessado usando a CLI ou seu IDE favorito. Talvez seja necessário instalar o pacote &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets&quot;&gt;Microsoft.Extensions.Configuration.UserSecrets&lt;/a&gt; caso você não use um &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Host&lt;/code&gt; ou tenha uma configuração personalizada.&lt;/p&gt;

&lt;h3 id=&quot;usando-user-secrets&quot;&gt;Usando User Secrets&lt;/h3&gt;

&lt;h4 id=&quot;cli&quot;&gt;CLI&lt;/h4&gt;

&lt;p&gt;Você pode usar o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dotnet&lt;/code&gt; cli para interagir com user-secrets abrindo um terminal no diretório em que reside o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.csproj&lt;/code&gt; do seu projeto.&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;# Necessário apenas quando as user-secrets ainda não foram inicializadas
dotnet user-secrets init

# Você pode usar dados estruturados usando dois pontos (:) para separar as chaves
dotnet user-secrets set “ConnectionStrings:Database” “Data Source=...”
dotnet user-secrets set “AdminPassword” “hunter2”
# Outros comandos como “list”, “remove” e “clear” também estão disponíveis

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

&lt;h4 id=&quot;visual-studio&quot;&gt;Visual Studio&lt;/h4&gt;

&lt;p&gt;Clique com o botão direito do mouse em um projeto no Solution Explorer e selecione &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Manage User Secrets&lt;/code&gt;. Um arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secrets.json&lt;/code&gt; será aberto, no qual você poderá inserir seus segredos.&lt;/p&gt;

&lt;h4 id=&quot;visual-studio-code&quot;&gt;Visual Studio Code&lt;/h4&gt;

&lt;p&gt;Instale a extensão &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=adrianwilczynski.user-secrets&quot;&gt;.NET Core User Secrets Visual Studio Code&lt;/a&gt;. Em seguida, você pode clicar com o botão direito do mouse em um arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.csproj&lt;/code&gt; e selecionar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Manage User Secrets&lt;/code&gt;. Um arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secrets.json&lt;/code&gt; será aberto, no qual você poderá inserir seus segredos.&lt;/p&gt;

&lt;h4 id=&quot;jetbrains-rider&quot;&gt;JetBrains Rider&lt;/h4&gt;

&lt;p&gt;Clique com o botão direito do mouse em um projeto no Solution Explorer e selecione &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tools&lt;/code&gt; &amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Manage User Secrets&lt;/code&gt;. Um arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secrets.json&lt;/code&gt; será aberto, no qual você poderá inserir seus segredos.&lt;/p&gt;

&lt;h3 id=&quot;configurando-um-projeto-que-usa-user-secrets&quot;&gt;Configurando um projeto que usa user-secrets&lt;/h3&gt;

&lt;p&gt;Uma desvantagem de usar segredos de usuário durante o desenvolvimento é que, se o seu projeto exigir alguns segredos para ser executado, será necessário executar algumas etapas de configuração após a clonagem do projeto. Tenho duas recomendações para lidar com isso:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Você pode criar um script que recupere os segredos do seu local de armazenamento de segredos e, em seguida, armazene-os em user-secrets, canalizando esses valores para &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dotnet user-secrets set&lt;/code&gt;. Agora você só precisa executar esse script uma vez após clonar o projeto e pronto!&lt;/li&gt;
  &lt;li&gt;Como alternativa, recomendo atualizar seu &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README.MD&lt;/code&gt; incluindo instruções de configuração que informem ao usuário quais user-secrets devem ser definidos e de onde obter esses valores. Sinta-se à vontade para criar um link para Este post se quiser explicar o que são user-secrets 😉.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;meu-modelo-para-gerenciamento-de-configuração&quot;&gt;Meu modelo para gerenciamento de configuração&lt;/h2&gt;

&lt;p&gt;Agora que abordamos os conceitos básicos e o uso avançado do sistema de configuração do .NET e como incorporar o gerenciamento de segredos locais, gostaria de mostrar minha “configuração” para o gerenciamento de configuração em um projeto .NET. Quando crio um novo projeto .NET, uso a seguinte configuração:&lt;/p&gt;

&lt;h3 id=&quot;appsettingsjson&quot;&gt;appsettings.json&lt;/h3&gt;

&lt;p&gt;O sistema de configuração do .NET permite que você seja muito flexível com todos os diferentes provedores. Isso é ótimo, mas também pode causar confusão quando seu aplicativo estiver usando valores de configuração que você não esperava ou quando não conseguir descobrir de onde vem um valor de configuração específico.&lt;/p&gt;

&lt;div class=&quot;callout callout-tip&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;💡&lt;/span&gt;
    Dica
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Use o método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfigurationRoot.GetDebugView()&lt;/code&gt; quando estiver tendo problemas com os valores de configuração. Para fazer isso, obtenha uma instância &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfiguration&lt;/code&gt;, converta-a em &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IConfigurationRoot&lt;/code&gt; e inspecione o resultado de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetDebugView()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para obter mais informações, consulte o &lt;a href=&quot;https://andrewlock.net/debugging-configuration-values-in-aspnetcore/#exposing-the-debug-view-in-your-application&quot;&gt;fantástico post de Andrew Lock&lt;/a&gt; sobre isso.&lt;/p&gt;

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

&lt;p&gt;Eu uso &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt; para armazenar um modelo de todos os valores de configuração que meu projeto usa e de onde os valores são recuperados. Esse arquivo também pode conter valores reais quando o arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt; é o único provedor para esse valor de configuração. Gosto muito dessa configuração porque ela me permite ver todos os valores de configuração que meu projeto usa em um só lugar.&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;{
  “Logging&quot;: {
    “LogLevel&quot;: {
      “Default” (Padrão): “Informações”,
      “Microsoft.AspNetCore&quot;: “Warning”
    }
  },

  “ConnectionStrings&quot;: {
    “Database”: “&amp;lt;from-azure-keyvault&amp;gt;” // O Azure Key Vault será discutido na próxima seção
  },

  “ExternalApiSettings&quot;: {
    “ApiUrl&quot;: “&amp;lt;from-environment-variables&amp;gt;”,
    “ApiKey&quot;: “&amp;lt;from-azure-keyvault&amp;gt;”,
    “TimeoutInMilliseconds&quot;: 5000
  }
}

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

&lt;h3 id=&quot;appsettingsdevelopmentjson&quot;&gt;appsettings.Development.json&lt;/h3&gt;

&lt;p&gt;A seguir, temos o arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Development.json&lt;/code&gt;. Esse arquivo pode conter valores de configuração que substituem os valores do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt;, como configurações de registro. Além disso, esse arquivo &lt;strong&gt;nunca&lt;/strong&gt; deve conter segredos! Em vez disso, ele faz referência ao provedor de configuração de user secrets. Isso torna menos provável que as pessoas insiram segredos nesse arquivo, pois elas são levadas a usar o provedor de configuração de user secrets.&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;{
  “Logging&quot;: {
    “LogLevel&quot;: {
      “Default”: “Debug”, // As configurações de log são 100% de preferência pessoal, fique à vontade para usar o que quiser
      “Microsoft.AspNetCore&quot;: “Warning”
    }
  },

  “ConnectionStrings&quot;: {
    “Database”: “&amp;lt;from-user-secrets&amp;gt;” // Cada desenvolvedor pode usar sua própria string de conexão de banco de dados local
  },

  “ExternalApiSettings&quot;: {
    “ApiUrl&quot;: “dev.externalapi.example.com”,
    “ApiKey&quot;: “&amp;lt;from-user-secrets&amp;gt;”
    // Não forneço um valor para TimeoutInMilliseconds porque não tenho problemas com o valor de appsettings.json
  }
}

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

&lt;h3 id=&quot;user-secrets&quot;&gt;User Secrets&lt;/h3&gt;

&lt;p&gt;Por fim, uso o provedor de configuração user secrets para armazenar segredos locais &lt;em&gt;e&lt;/em&gt; substituir a configuração não secreta que não quero enviar para o repositório git, como alterar as configurações de log no caso de precisar me aprofundar em um bug. Se eu alterasse esses valores de configuração no arquivo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.Development.json&lt;/code&gt;, teria que me lembrar de reverter essas alterações antes de fazer o commit do meu código. Ao usar o provedor de configuração de user secrets, não preciso me preocupar com isso.&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;{
  “Logging&quot;: {
    “LogLevel&quot;: {
      “Microsoft.AspNetCore&quot;: “Information”
    }
  },

  “ConnectionStrings&quot;: {
    “Database”: “Data Source=...”
  },

  “ExternalApiSettings&quot;: {
    “ApiKey&quot;: “abc123def456ghi7”
  }
}

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

&lt;div class=&quot;callout callout-question&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;❓&lt;/span&gt;
    Pergunta
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Como é a sua configuração? O que você acha da minha? Deixe sua opinião nos comentários abaixo!&lt;/p&gt;

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

&lt;h2 id=&quot;usando-o-azure-para-armazenar-a-configuração&quot;&gt;Usando o Azure para armazenar a configuração&lt;/h2&gt;

&lt;p&gt;Agora que sabemos como armazenar a configuração e os segredos localmente, é hora de falar sobre a execução de seus aplicativos em ambientes reais. Há muitas maneiras diferentes de configurar a configuração e o gerenciamento de segredos para ambientes não locais, portanto, tudo se resume a conhecer as vantagens e desvantagens dessas abordagens e escolher o que funciona melhor para você. Neste post, você aprenderá a usar o Azure para armazenar sua configuração e seus segredos com segurança.&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;Embora esta seção seja sobre o Azure, os conceitos também se aplicam a outros provedores de nuvem. O equivalente do Azure App Configuration no AWS é chamado de &lt;a href=&quot;https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html&quot;&gt;AWS Systems Manager Parameter Store&lt;/a&gt;. O Azure Key Vault tem um equivalente no AWS chamado &lt;a href=&quot;https://aws.amazon.com/secrets-manager/&quot;&gt;AWS Secrets Manager&lt;/a&gt; e o equivalente do Google é chamado &lt;a href=&quot;https://cloud.google.com/secret-manager&quot;&gt;Google Secret Manager&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se quiser hospedar seu gerenciamento de segredos por conta própria, dê uma olhada em &lt;a href=&quot;https://www.vaultproject.io/&quot;&gt;Hashicorp Vault&lt;/a&gt;.&lt;/p&gt;


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

&lt;h3 id=&quot;armazenamento-de-segredos-no-azure-key-vault&quot;&gt;Armazenamento de segredos no Azure Key Vault&lt;/h3&gt;

&lt;p&gt;Como dissemos anteriormente, não é possível usar o provedor de configuração User Secrets em ambientes não locais. Portanto, temos que encontrar uma maneira diferente de armazenar nossos segredos quando estivermos implantando nossos aplicativos. O &lt;a href=&quot;https://azure.microsoft.com/services/key-vault/?WT.mc_id=DT-MVP-5005050&quot;&gt;Azure Key Vault&lt;/a&gt; é um ótimo serviço para armazenar segredos, chaves e certificados de forma barata, fácil e segura.&lt;/p&gt;

&lt;p&gt;No início deste post, mencionei que é possível conectar o sistema de configuração do .NET à nuvem, o que &lt;a href=&quot;https://learn.microsoft.com/aspnet/core/security/key-vault-configuration?WT.mc_id=DT-MVP-5005050&quot;&gt;é possível com o Key Vault&lt;/a&gt;. Essa é uma ótima abordagem para o gerenciamento de segredos porque você pode simplesmente tratar o Key Vault como um provedor de configuração e não precisa mais fazer coisas complicadas no pipeline de lançamento.&lt;/p&gt;

&lt;p&gt;Para adicioná-lo como um provedor de configuração, instale os pacotes &lt;a href=&quot;https://www.nuget.org/packages/Azure.Extensions.AspNetCore.Configuration.Secrets&quot;&gt;Azure.Extensions.AspNetCore.Configuration.Secrets&lt;/a&gt; e &lt;a href=&quot;https://www.nuget.org/packages/Azure.Identity&quot;&gt;Azure.Identity&lt;/a&gt;. Em seguida, você só precisará adicionar algumas linhas de código ao seu &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Program.cs&lt;/code&gt; quando criar uma API mínima, por exemplo:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Azure.Identity&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;builder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WebApplication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CreateBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&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;n&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureAppConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HostingEnvironment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsDevelopment&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;keyVaultUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;KeyVaultUrl&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;”&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddAzureKeyVault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keyVaultUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ManagedIdentityCredential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Há outras opções de credenciais disponíveis. As Managed Identities serão abordadas em breve!&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;/figure&gt;

&lt;p&gt;O Key Vault agora é adicionado como o provedor final e, portanto, tem &lt;a href=&quot;#os-valores-default&quot;&gt;a prioridade mais alta&lt;/a&gt;. Portanto, mesmo que outros provedores tenham um valor configurado para um segredo, o Key Vault será usado em seu lugar!&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;Os segredos estruturados devem ser armazenados no Key Vault com 2 traços (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--&lt;/code&gt;) em vez de 2 sublinhados ou dois pontos devido a limitações de nomenclatura. Por exemplo, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiSettings--ApiKey&lt;/code&gt; em vez de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiSettings:ApiKey&lt;/code&gt; ou &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExternalApiSettings__ApiKey&lt;/code&gt;.&lt;/p&gt;

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

&lt;h4 id=&quot;usando-o-key-vault-durante-o-desenvolvimento-local&quot;&gt;Usando o Key Vault durante o desenvolvimento local&lt;/h4&gt;

&lt;p&gt;Anteriormente neste post, mencionei brevemente que você pode estar em um cenário em que não é possível armazenar segredos em seu computador por motivos de segurança, por exemplo. Nesse caso, usar o Key Vault durante o desenvolvimento local resolveria esse problema. Você pode pegar o exemplo de código da seção anterior e modificá-lo da seguinte forma:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Azure.Identity&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;builder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WebApplication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CreateBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&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;n&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureAppConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&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;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keyVaultUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;“&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;KeyVaultUrl&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;”&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddAzureKeyVault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keyVaultUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Esses tipos de credenciais serão abordados a seguir!&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Agora, seu aplicativo sempre se conectará ao Key Vault, mesmo durante o desenvolvimento. O resultado é que você não precisa mais armazenar segredos em seu computador, pois eles são sempre recuperados do Key Vault. Uma desvantagem dessa abordagem é que você sempre precisa de uma conexão com a Internet para se conectar à nuvem!&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;Devido aos benefícios que essa solução traz, considere o uso dessa abordagem mesmo em cenários em que o armazenamento de segredos localmente seria aceitável. Um grande benefício dessa abordagem é que você pode simplesmente clonar um projeto e, desde que tenha as permissões corretas, pode executá-lo sem precisar configurar nenhum segredo em sua máquina, pois eles são simplesmente recuperados da nuvem!&lt;/p&gt;

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

&lt;h3 id=&quot;conectando-se-ao-azure-com-identidades-gerenciadas&quot;&gt;Conectando-se ao Azure com identidades gerenciadas&lt;/h3&gt;

&lt;p&gt;Nos exemplos de código anteriores, você viu alguns tipos estranhos de credenciais: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ManagedIdentityCredential&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DefaultAzureCredential&lt;/code&gt;. Antes de discutirmos isso, considere o seguinte:&lt;/p&gt;

&lt;p&gt;Queremos nos conectar a um provedor de armazenamento seguro de segredos para obter segredos com os quais executar nosso aplicativo. Para nos conectarmos a esse provedor, precisaremos passar algumas credenciais para que o provedor possa autorizar nossa solicitação. &lt;strong&gt;Mas essas credenciais também são segredos, então onde as armazenamos&lt;/strong&gt;? Poderíamos armazená-las em outro provedor de configuração, mas isso não anula todo o propósito de ter um provedor secreto? Se essas credenciais vazassem, alguém poderia acessar nossos segredos de qualquer forma! &lt;strong&gt;Para resumir, estamos lidando com um problema de galinha e ovo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Felizmente, algumas pessoas inteligentes da Microsoft descobriram isso! Para o desenvolvimento local, você pode usar o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DefaultAzureCredential&lt;/code&gt; para se comunicar com os serviços do Azure. Esse tipo de credencial tentará se autenticar &lt;a href=&quot;https://learn.microsoft.com/dotnet/api/overview/azure/identity-readme?WT.mc_id=DT-MVP-5005050#defaultazurecredential&quot;&gt;usando vários métodos&lt;/a&gt;, como a conta da Microsoft com a qual você está conectado ao seu IDE, suas credenciais da CLI do Azure (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;az&lt;/code&gt;) e muito mais.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/configuracao-dotnet/azure-identity.webp&quot; alt=&quot;Uma visão geral de como a Identidade do Azure funciona&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A Identidade do Azure usa vários métodos para autenticar a conta do Azure de um desenvolvedor.&lt;/p&gt;

&lt;p&gt;Para ambientes de produção, a Microsoft recomenda &lt;a href=&quot;https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview&quot;&gt;Managed Identities&lt;/a&gt; para &lt;a href=&quot;https://learn.microsoft.com/dotnet/azure/sdk/authentication/?WT.mc_id=DT-MVP-5005050&quot;&gt;autenticar com recursos do Azure&lt;/a&gt;. As identidades gerenciadas são um recurso do Microsoft Entra (anteriormente conhecido como Azure Active Directory) que permite criar uma identidade para seu aplicativo no Microsoft Entra. Essa identidade pode ser usada para autenticação em outros serviços do Azure, como o Key Vault. A vantagem dessa abordagem é que você não precisa mais armazenar nenhuma credencial no aplicativo, pois a identidade é gerenciada pelo Azure AD.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/configuracao-dotnet/azure-managed-identities.webp&quot; alt=&quot;Um diagrama de como as Identidades Gerenciadas funcionam.&amp;lt;/br&amp;gt;&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;
    Info
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;As Managed Identities podem ser bastante difíceis de entender em um primeiro momento. Dê uma olhada na parte inferior do post para ver alguns links com mais informações sobre Managed Identities.&lt;/p&gt;

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

&lt;h3 id=&quot;armazenamento-da-configuração-na-configuração-de-aplicativo-do-azure&quot;&gt;Armazenamento da configuração na Configuração de Aplicativo do Azure&lt;/h3&gt;

&lt;p&gt;Por último, mas não menos importante, quero falar sobre a oferta de nuvem do Azure para gerenciamento de &lt;em&gt;configuração&lt;/em&gt;. Enquanto o Azure Key Vault abrange o gerenciamento de segredos, o &lt;a href=&quot;https://azure.microsoft.com/products/app-configuration/?WT.mc_id=DT-MVP-5005050&quot;&gt;Azure App configuration&lt;/a&gt; é uma oferta de SaaS que o ajudará a gerenciar sua configuração. Esses dois serviços funcionam muito bem juntos quando você vincula o Azure App Configuration ao Azure Key Vault. Se optar por usar esse serviço, você só precisará adicionar o &lt;a href=&quot;https://learn.microsoft.com/azure/azure-app-configuration/quickstart-aspnet-core-app?WT.mc_id=DT-MVP-5005050&quot;&gt;Azure App Configuration como um provedor de configuração&lt;/a&gt; e, em seguida, poderá usar o sistema de configuração do .NET para acessar todas as suas configurações E segredos da nuvem!&lt;/p&gt;

&lt;p&gt;Ele também tem muitos outros recursos, portanto, vale a pena dar uma olhada!&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;Considere a possibilidade de usar &lt;a href=&quot;https://learn.microsoft.com/pt-br/azure/azure-app-configuration/howto-integrate-azure-managed-service-identity?WT.mc_id=DT-MVP-5005050&amp;amp;pivots=framework-dotnet&quot;&gt;identidades gerenciadas para acessar a Configuração de Aplicativos&lt;/a&gt; para aumentar a segurança!&lt;/p&gt;


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

&lt;h2 id=&quot;finalizando&quot;&gt;Finalizando&lt;/h2&gt;

&lt;p&gt;Você chegou até o fim! Este post levou muito tempo para ser escrito, e estou feliz por finalmente ter sido concluído! Abaixo, você encontrará mais informações se quiser saber mais sobre os conceitos que abordei neste post. Se você tiver alguma dúvida, fique à vontade para deixar um comentário abaixo. Se quiser saber quando e onde darei a versão de palestra deste post, confira minha página &lt;a href=&quot;https://stenbrinke.nl/speaking&quot;&gt;Speaking&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;links-para-a-demo&quot;&gt;Links para a demo&lt;/h3&gt;

&lt;p&gt;Mencionei que o post é um complemento de uma de minhas sessões. Essa sessão contém várias demonstrações que mostram os conceitos discutidos nEste post. Você pode encontrar as demonstrações &lt;a href=&quot;https://github.com/sander1095/secure-secret-storage-with-asp-net-core/&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;links-para-a-documentação-oficial&quot;&gt;Links para a documentação oficial&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/core/extensions/configuration?WT.mc_id=DT-MVP-5005050&quot;&gt;Configuração&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/aspnet/core/fundamentals/configuration?WT.mc_id=DT-MVP-5005050&quot;&gt;Configuração (especificações do ASP.NET Core)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/aspnet/core/fundamentals/configuration/options?WT.mc_id=DT-MVP-5005050&quot;&gt;options pattern&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/aspnet/core/security/app-secrets&quot;&gt;user secrets&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/products/key-vault/?WT.mc_id=DT-MVP-5005050&quot;&gt;Azure KeyVault&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/devops/demystifying-service-principals-managed-identities/?WT.mc_id=DT-MVP-5005050&quot;&gt;Mais informações sobre Managed Identities&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;Você gostou deste post? &lt;a href=&quot;https://ko-fi.com/stenbrinke&quot;&gt;&lt;img src=&quot;https://stenbrinke.nl/images/kofi_button_blue.webp&quot; alt=&quot;Faça uma doção para o autor original em https://ko-fi.com/stenbrinke.nl&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;carlos-de-volta&quot;&gt;Carlos de volta&lt;/h2&gt;

&lt;p&gt;Carlos Schults de volta aqui. Espero que tenham gostado bastante do post, e sugiro que o coloquem nos favoritos para ser um recurso útil de consulta toda vez que surgir alguma dúvida referente ao gerenciamento de secrets e configuração.&lt;/p&gt;

&lt;p&gt;Agradeço a Sander ten Brinke, autor do artigo original, que gentilmente me autorizou a traduzí-lo. O &lt;a href=&quot;https://stenbrinke.nl/&quot;&gt;blog dele&lt;/a&gt; é fantástico, tem muitos artigos extremamente bem escritos sobre diversos tópicos relacionados a .NET. Para quem sabe inglês, recomendo fortemente a visita.&lt;/p&gt;

&lt;p&gt;Gostaria de agradecer também a &lt;a href=&quot;https://andrewlock.net/about/&quot;&gt;Andrew Lock&lt;/a&gt;, o autor do livro &lt;a href=&quot;https://www.manning.com/books/asp-net-core-in-action-third-edition&quot;&gt;ASP.NET Core in Action&lt;/a&gt;, por ter concedido autorização para reproduzir uma imagem de seu livro.&lt;/p&gt;

&lt;p&gt;A você que leu o artigo - todo ou apenas uma parte — deixo também um agradecimento e um pedido: me dê seu feedback. É extremamente importante saber se as pessoas gostam desse tipo de conteúdo, pois me motiva a continuar produzindo.&lt;/p&gt;

&lt;p&gt;Até a próxima!&lt;/p&gt;
</description>
        <pubDate>Tue, 23 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/configuracao-dotnet</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/configuracao-dotnet</guid>
        
        <category>csharp</category>
        
        <category>dotnet</category>
        
        <category>configuracao</category>
        
        <category>traducoes</category>
        
        <category>tutorial</category>
        
        
      </item>
    
      <item>
        <title>C# Regex: Como Expressões Regulares Funcionam em C#, Com Exemplos</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dz5ppacuo/image/upload/v1513817072/csharp8-1037x438_skogpz.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;NOTA: Eu originalmente escrevi esse post para o blog da empresa Stackify.  Você pode &lt;a href=&quot;https://stackify.com/c-regex-how-regular-expressions-work-in-c-with-examples/&quot;&gt;ler o artigo original, em inglês, no site deles&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A manipulação de texto é uma das tarefas mais comuns na programação, sendo que praticamente todas as principais linguagens de programação oferecem suporte a regex (expressão regular) por meio de suas bibliotecas padrão. O C# não é exceção, portanto, hoje trazemos a você um guia de regex do C#.&lt;/p&gt;

&lt;p&gt;Você aprenderá o que são expressões regulares, por que você deseja usá-las e como começar de uma maneira abrangente e acessível. Dessa forma, você poderá começar a usar expressões regulares para resolver problemas reais o mais rápido possível.&lt;/p&gt;

&lt;p&gt;Prepare-se para sua jornada de aprendizado de regex, que começa agora!&lt;/p&gt;

&lt;h2 id=&quot;o-que-é-regex&quot;&gt;O Que é Regex?&lt;/h2&gt;
&lt;p&gt;Uma expressão regular (também chamadas de regex, abreviação para &lt;em&gt;regular expression&lt;/em&gt;) é uma expressão que contém um ou vários caracteres que expressam um determinado padrão no texto. Se isso parecer um pouco vago, um exemplo vai ajudar. Considere uma data no seguinte formato:&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;28-JUL-2023
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Usando um regex, podemos expressar esse formato da seguinte forma:&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;[0-9]{2}-[A-Z]{3}-[0-9]{4}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Observe que a expressão regular acima expressa um padrão com:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;dois dígitos numéricos seguidos de um hífen&lt;/li&gt;
  &lt;li&gt;três letras maiúsculas seguidas de um hífen&lt;/li&gt;
  &lt;li&gt;mais quatro números&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Você saberá mais sobre o significado de cada parte de uma regex em um minuto. Por enquanto, lembre-se de que a regex acima não &lt;em&gt;sabe&lt;/em&gt; nada sobre datas. Acontece que conseguimos criar uma expressão regular que corresponde ao padrão ou ao formato da data. Todos os itens a seguir correspondem a essa regex, mesmo que não sejam datas válidas:&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;32-ABC-7894
30-FEV-1978
00-AAA-9999
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;existe-regex-no-c&quot;&gt;Existe Regex no C#?&lt;/h2&gt;

&lt;p&gt;Sim, é claro. Mas isso não vem da própria linguagem. Em vez disso, o suporte a regex vem da &lt;a href=&quot;https://learn.microsoft.com/pt-br/dotnet/standard/class-library-overview&quot;&gt;.NET’s BCL (Base Class Library),&lt;/a&gt; que é essencialmente a biblioteca padrão do C#.&lt;/p&gt;

&lt;h2 id=&quot;por-que-usar-regex-em-c&quot;&gt;Por Que Usar Regex em C#?&lt;/h2&gt;

&lt;p&gt;Como você viu, regex é algo a ser usado para expressar um padrão que pode corresponder a um determinado texto.&lt;/p&gt;

&lt;p&gt;Na prática, todos os usos de regex em C# ou em outras linguagens se resumem a três motivos: validação, manipulação e extração.&lt;/p&gt;

&lt;h3 id=&quot;validação&quot;&gt;Validação&lt;/h3&gt;

&lt;p&gt;Um caso de uso incrivelmente comum para regex é a validação de dados. Por exemplo, digamos que você tenha um formulário da Web e queira garantir que um determinado campo só aceite entradas em um formato específico. Como resolver isso? O Regex vem em seu socorro.&lt;/p&gt;

&lt;h3 id=&quot;manipulação&quot;&gt;Manipulação&lt;/h3&gt;

&lt;p&gt;Às vezes, você precisa alterar informações dentro do texto. Vamos voltar ao exemplo anterior. Imagine que, por motivos de compliance, você precise remover todos os números de telefone desse corpo de texto e substituí-los pela palavra “REDACTED”. Novamente, as expressões regulares seriam perfeitas para essa situação.&lt;/p&gt;

&lt;p&gt;É interessante notar que as linguagens de programação não são as únicas a usar expressões regulares para resolver problemas. Até mesmo os editores de texto, como o Notepad++, oferecem recursos de localizar e substituir com o auxílio de expressões regulares.&lt;/p&gt;

&lt;h2 id=&quot;extração&quot;&gt;Extração&lt;/h2&gt;

&lt;p&gt;Digamos que você tenha uma quantidade considerável de texto. Esse texto contém números de telefone que você precisa extrair. Você conhece o formato desses números e o fato de que eles estão dentro do texto, mas esse é o limite do seu conhecimento.&lt;/p&gt;

&lt;p&gt;Como você faria para extrair essas informações? Um regex C# bem feito certamente seria útil nessa situação.&lt;/p&gt;

&lt;h2 id=&quot;como-usar-o-regex-em-c-primeiros-passos-na-prática&quot;&gt;Como usar o Regex em C#: Primeiros passos na prática&lt;/h2&gt;

&lt;p&gt;O C# é uma &lt;a href=&quot;https://stackify.com/oop-concepts-c-sharp/&quot;&gt;linguagem orientada a objetos&lt;/a&gt;, portanto, não é de surpreender que você use uma classe para trabalhar com regex no C#. Mais especificamente, a classe de que estou falando é apropriadamente chamada de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regex&lt;/code&gt; e reside no namespace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Text.RegularExpressions&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;c-regex-um-exemplo-de-validação&quot;&gt;C# Regex: Um exemplo de validação&lt;/h3&gt;

&lt;p&gt;Vamos começar com um exemplo simples de validação sobre como usar regex para validar se várias cadeias de caracteres correspondem a um determinado padrão. A primeira etapa é adicionar a seguinte instrução &lt;strong&gt;using&lt;/strong&gt; ao seu código:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Text.RegularExpressions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Agora, vamos criar um array de strings e preenchê-la com alguns valores:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;candidates&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&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;s&quot;&gt;&quot;28-JUL-2023&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;whatever&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;89-ABC-1234&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;11-JUN-2022&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;11-JUN-2022, uma data e outras coisas&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Isso certamente não é uma data&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Por fim, percorreremos os valores e usaremos o método estático &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsMatch&lt;/code&gt; da classe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regex&lt;/code&gt; para verificar qual das cadeias de caracteres corresponde ao padrão desejado:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;[0-9]{2}-[A-Z]{3}-[0-9]{4}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;foreach&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;c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;candidates&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;Regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&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;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;A string '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;' corresponde ao padrão '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pattern&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;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;/figure&gt;

&lt;p&gt;Antes de prosseguir, vamos detalhar o padrão parte por parte:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[0-9]{2}&lt;/strong&gt;: A primeira parte significa “Corresponde exatamente a dois caracteres, que devem ser dígitos de 0 a 9”.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;-&lt;/strong&gt;: Esse caractere corresponde exatamente a um hífen.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[A-Z]{3}&lt;/strong&gt;: Aqui, a expressão diz: “Vamos corresponder exatamente a três caracteres, que podem ser qualquer uma das letras de A a Z.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;-&lt;/strong&gt;: Isso corresponde a outro hífen&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[0-9]{4}&lt;/strong&gt;: Isso já deve ser fácil de entender, certo? Exatamente quatro números.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agora, vamos executar o código e ver o que obtemos:&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;A string '28-JUL-2023' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
A string '89-ABC-1234' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
A cadeia de caracteres '11-JUN-2022' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
A cadeia de caracteres '11-JUN-2022, a date plus other stuff' corresponde ao padrão '[0-9]{2}-[A-Z]{3}-[0-9]{4}'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Os três primeiros resultados provavelmente não o surpreenderam. Eu até incluí algo que não é uma data, mas que corresponde ao padrão que estamos usando para realmente enfatizar que as expressões regulares tratam de padrões e formas e não de qualquer semântica dos dados que estamos procurando.&lt;/p&gt;

&lt;p&gt;Entretanto, o quarto resultado pode tê-lo surpreendido. O texto de fato começa com dados que correspondem ao padrão que estamos procurando, mas depois tem algum texto adicional. E mesmo assim, essa string correspondeu!&lt;/p&gt;

&lt;p&gt;A explicação para esse comportamento é simples e está explicada para nós no &lt;a href=&quot;https://learn.microsoft.com/pt-br/dotnet/api/system.text.regularexpressions.regex.ismatch?view=net-7.0#system-text-regularexpressions-regex-ismatch(system-string-system-string)&quot;&gt;summary&lt;/a&gt; do método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsMatch&lt;/code&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;Indica se a expressão regular especificada encontra uma correspondência na cadeia de caracteres de entrada especificada.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A expressão regular de fato encontrou uma correspondência na string de entrada especificada (“11-JUN-2022, a date plus other stuff”), e é por isso que foi considerada uma correspondência.&lt;/p&gt;

&lt;p&gt;Mas e se quiséssemos uma correspondência exata? Nesse caso, seria necessário alterar o padrão, adicionando um acento circunflexo (“^”) ao início do padrão e um cifrão (“$”) ao seu final. Em outras palavras, veja como o padrão deve ficar agora:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;^[0-9]{2}-[A-Z]{3}-[0-9]{4}$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Se executarmos o código agora, ele exibirá apenas as cadeias de caracteres que são uma correspondência exata com o padrão:&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;A string '28-JUL-2023' corresponde ao padrão '^[0-9]{2}-[A-Z]{3}-[0-9]{4}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;c-regex-um-exemplo-de-manipulação&quot;&gt;C# Regex: Um exemplo de manipulação&lt;/h3&gt;

&lt;p&gt;Considere que você tem um texto que contém dados sensíveis do usuário. Devido a questões de privacidade/compliance, você deseja excluir esses dados. Felizmente para você, é muito fácil usar uma regex para isso.&lt;/p&gt;

&lt;p&gt;Vamos começar criando uma matriz contendo nomes e números de telefone de pessoas fictícias:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contacts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&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;s&quot;&gt;&quot;Emily Johnson,(555) 123-4567&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Benjamin Williams,(555) 987-6543&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Olivia Davis,(555) 222-3333&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Alexander Smith,(555) 444-5555&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Sophia Brown,(555) 777-8888&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;William Anderson,(555) 111-2222&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Ava Martinez,(555) 666-7777&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;James Thompson,(555) 888-9999&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Isabella Wilson,(555) 333-4444&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Michael Taylor,(555) 777-1111&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Em seguida, vamos criar o padrão para corresponder aos números de telefone:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;O padrão acima é um pouco mais complexo do que os que usamos anteriormente, mas ainda é simples. No entanto, há alguns elementos novos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;A barra invertida (\):&lt;/strong&gt; Precisamos dela aqui para escapar dos parênteses de abertura e fechamento, que é um caractere com significado em uma expressão regular. Nesse caso, queremos de fato corresponder a um caractere “(“, portanto, precisamos escapar dele.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;O caractere \s:&lt;/strong&gt; corresponde a um único espaço.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por fim, vamos percorrer essa matriz e, para cada item, usar o método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regex.Replace&lt;/code&gt; para gerar uma nova string na qual o número de telefone é substituído por todos os zeros:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;foreach&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;contact&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contacts&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;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;(000) 000-0000&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Usar o método estático &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Replace&lt;/code&gt; é fácil. Embora ele tenha várias sobrecargas, a que usamos recebe apenas três argumentos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a string de entrada&lt;/li&gt;
  &lt;li&gt;o padrão que você deseja corresponder&lt;/li&gt;
  &lt;li&gt;a string de substituição&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depois de executar o código, eis o resultado que obtemos:&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;Emily Johnson,(000) 000-0000
Benjamin Williams,(000) 000-0000
Olivia Davis,(000) 000-0000
Alexander Smith,(000) 000-0000
Sophia Brown,(000) 000-0000
William Anderson,(000) 000-0000
Ava Martinez,(000) 000-0000
James Thompson,(000) 000-0000
Isabella Wilson,(000) 000-0000
Michael Taylor,(000) 000-0000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;c-regex-um-exemplo-de-extração&quot;&gt;C# Regex: Um exemplo de extração&lt;/h3&gt;

&lt;p&gt;Para o nosso último exemplo, vamos extrair dados de uma string usando uma expressão regular. Vamos começar convertendo o array do exemplo anterior em uma única string:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contacts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Emily Johnson+(555) 123-4567&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nBenjamin Williams+(555) 987-6543&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nOlivia Davis+(555) 222-3333&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nAlexander Smith+(555) 444-5555&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nSophia Brown+(555) 777-8888&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nWilliam Anderson+(555) 111-2222&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nAva Martinez+(555) 666-7777&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nJames Thompson+(555) 888-9999&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nIsabella Wilson+(555) 333-4444&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nMichael Taylor+(555) 777-1111&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Em seguida, definimos o padrão novamente (o mesmo) e usamos o método estático &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Matches&lt;/code&gt; para obter todas as correspondências da string:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MatchCollection&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A classe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MatchCollection&lt;/code&gt; contém todas as cadeias de caracteres que corresponderam ao padrão que fornecemos ao método. Esse objeto é enumerável, portanto, podemos fazer um loop sobre ele com um foreach:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Aqui estão os números de telefone extraídos:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&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;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&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;/figure&gt;

&lt;p&gt;E, finalmente, nossos resultados:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;Aqui&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;est&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ã&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ú&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meros&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;de&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;telefone&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extra&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;í&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dos&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;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4567&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;987&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;6543&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;222&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3333&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;444&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5555&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;777&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;8888&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;111&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2222&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;666&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;7777&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;888&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;9999&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;333&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4444&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;777&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1111&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;c-regex-uma-ferramenta-indispensável&quot;&gt;C# Regex: Uma Ferramenta Indispensável&lt;/h2&gt;

&lt;p&gt;Como dissemos na introdução, a manipulação de texto é um elemento básico da programação, e as expressões regulares facilitam essa tarefa. Neste guia de regex em C#, você aprendeu o que são expressões regulares, seus cenários de uso mais comuns e como começar a usar expressões regulares em C#.&lt;/p&gt;

&lt;p&gt;Antes de ir embora, algumas dicas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Faça mais experimentos com a classe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regex&lt;/code&gt;. Ela oferece muitos recursos, e os métodos que usamos hoje têm muitas sobrecargas com recursos úteis.&lt;/li&gt;
  &lt;li&gt;Saiba mais e pratique a escrita de expressões regulares. &lt;a href=&quot;https://regexr.com/&quot;&gt;Aqui está um ótimo site&lt;/a&gt; que você pode usar.&lt;/li&gt;
  &lt;li&gt;Informe-se sobre as considerações de desempenho do C# regex. Por exemplo, leia este &lt;a href=&quot;https://learn.microsoft.com/pt-br/dotnet/standard/base-types/compilation-and-reuse-in-regular-expressions?redirectedfrom=MSDN&quot;&gt;artigo da Microsoft sobre a compilação e a reutilização de expressões regulares&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por fim, se quiser saber mais sobre o C# em geral, o blog da Stackify está repleto de recursos úteis. Como sugestão, dê uma olhada em &lt;a href=&quot;https://stackify.com/unit-test-frameworks-csharp/&quot;&gt;os prós e contras dos 3 principais frameworks de teste de unidade para C#&lt;/a&gt;, &lt;a href=&quot;https://stackify.com/csharp-catch-all-exceptions/&quot;&gt;como capturar exceções e localizar erros de aplicativos em C#&lt;/a&gt; e &lt;a href=&quot;https://stackify.com/what-is-c-reflection/&quot;&gt;como funciona a reflexão em C#&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Obrigado pela leitura!&lt;/p&gt;
</description>
        <pubDate>Tue, 07 May 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/pt/csharp-expressoes-regulares</link>
        <guid isPermaLink="true">https://carlosschults.net/pt/csharp-expressoes-regulares</guid>
        
        <category>csharp</category>
        
        <category>regex</category>
        
        <category>expressoes_regulares</category>
        
        <category>tutorial</category>
        
        
      </item>
    
  </channel>
</rss>
