<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yuri Peixinho</title>
    <description>The latest articles on DEV Community by Yuri Peixinho (@yuripeixinho).</description>
    <link>https://dev.to/yuripeixinho</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1647416%2Fcb24132f-cdc1-4080-8977-0786f79ceb26.png</url>
      <title>DEV Community: Yuri Peixinho</title>
      <link>https://dev.to/yuripeixinho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yuripeixinho"/>
    <language>en</language>
    <item>
      <title>Cluster 4: #10 testes rápidos e independentes, #13 simplicidade e refatoração contínua</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Sat, 01 Aug 2026 21:50:16 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/cluster-4-10-testes-rapidos-e-independentes-13-simplicidade-e-refatoracao-continua-2ka6</link>
      <guid>https://dev.to/yuripeixinho/cluster-4-10-testes-rapidos-e-independentes-13-simplicidade-e-refatoracao-continua-2ka6</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Esse&amp;nbsp;cluster&amp;nbsp;é&amp;nbsp;diferente&amp;nbsp;dos&amp;nbsp;outros&amp;nbsp;três:&amp;nbsp;ele&amp;nbsp;não&amp;nbsp;previne&amp;nbsp;um&amp;nbsp;tipo&amp;nbsp;de&amp;nbsp;bug,&amp;nbsp;ele&amp;nbsp;&lt;strong&gt;sustenta&amp;nbsp;a&amp;nbsp;capacidade&amp;nbsp;de&amp;nbsp;manter&amp;nbsp;os&amp;nbsp;outros&amp;nbsp;nove&amp;nbsp;princípios&amp;nbsp;ao&amp;nbsp;longo&amp;nbsp;do&amp;nbsp;tempo&lt;/strong&gt;.&amp;nbsp;A&amp;nbsp;segunda&amp;nbsp;lei&amp;nbsp;de&amp;nbsp;Lehman,&amp;nbsp;a&amp;nbsp;&lt;strong&gt;Lei&amp;nbsp;da&amp;nbsp;Complexidade&amp;nbsp;Crescente&lt;/strong&gt;,&amp;nbsp;diz&amp;nbsp;que&amp;nbsp;a&amp;nbsp;complexidade&amp;nbsp;de&amp;nbsp;um&amp;nbsp;sistema&amp;nbsp;aumenta&amp;nbsp;por&amp;nbsp;padrão&amp;nbsp;a&amp;nbsp;menos&amp;nbsp;que&amp;nbsp;alguém&amp;nbsp;trabalhe&amp;nbsp;ativamente&amp;nbsp;para&amp;nbsp;reduzir-la. Refatoração não é uma tarefa opcional de “polimento”, é a única força que contrabalança uma tendência que existe independente da sua vontade. Mas refatorar só é seguro se você consegue confirmar rapidamente que nada quebrou — e é aí que testes lentos ou dependentes de ordem matam a disciplina inteira: se rodar a suíte demora 20 minutos ou falha de forma inconsistente, o time para de rodar, para de confiar, e para de refatorar, e a lei da complexidade crescente passa a valer sem oposição. Esse não é um risco teórico: o relatório The Developer Coefficient (Stripe, 2018), baseado em pesquisa com centenas de desenvolvedores e executivos de engenharia, estimou que uma fração substancial da semana de trabalho — na casa de um terço a 40% — é perdida lidando com dívida técnica e código malfeito, com impacto econômico global estimado em centenas de bilhões de dólares por ano. Esse número é, em essência, o preço agregado de organizações que pararam de fazer #10 e #13 e deixaram a lei de Lehman correr sem freio.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;#10 Testes Rápidos e Independentes&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;A base conceitual mais direta aqui é o acrônimo &lt;strong&gt;FIRST&lt;/strong&gt;, documentado por Robert C. Martin em &lt;em&gt;Clean Code&lt;/em&gt; (2008) e creditado a Tim Ottinger e Jeff Langr: um teste de unidade deveria ser &lt;strong&gt;F&lt;/strong&gt;ast (rápido), &lt;strong&gt;I&lt;/strong&gt;ndependent (independente de outros testes), &lt;strong&gt;R&lt;/strong&gt;epeatable (repetível em qualquer ambiente), &lt;strong&gt;S&lt;/strong&gt;elf-Validating (retorna verdadeiro/falso, sem exigir inspeção manual de log) e &lt;strong&gt;T&lt;/strong&gt;imely (escrito no momento certo, perto do código que testa). O título desse princípio no artigo pega exatamente as duas primeiras letras — porque são, na prática, as duas que mais diretamente disparam a espiral de morte descrita na introdução: um teste lento drena paciência a cada execução; um teste dependente de ordem drena confiança a cada falha que não devia ter acontecido.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Exemplo — teste lento e acoplado vs. teste rápido e isolado:&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Lento e acoplado — bate no banco de dados real a cada execução&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RetificacaoServiceTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DeveRetificarMovimento_QuandoValorDivergente&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FiscalDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_connectionStringReal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// conexão real com SQL Server&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RetificacaoService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Retificar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;movimentoId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sucesso&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Cada execução: abre conexão de rede real, e depende de que a linha 123&lt;/span&gt;
        &lt;span class="c1"&gt;// já exista no banco com o estado "certo" — herdado de uma execução anterior&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Rápido e isolado — dependência trocada por um fake em memória&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RetificacaoServiceTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DeveRetificarMovimento_QuandoValorDivergente&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;repositorioFake&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RepositorioMovimentoFake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Movimento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;StatusMovimento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pendente&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RetificacaoService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repositorioFake&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Retificar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;movimentoId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sucesso&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Roda em memória, sem I/O — milissegundos. O estado de entrada é 100%&lt;/span&gt;
        &lt;span class="c1"&gt;// definido dentro do próprio teste, não herdado de nada externo&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Exemplo — teste dependente de ordem vs. independente:&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Frágil — os dois testes compartilham uma lista estática entre execuções&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NumeracaoNotaFiscalTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_numerosGerados&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PrimeiroNumero_DeveSerUm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GerarProximoNumero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_numerosGerados&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_numerosGerados&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SegundoNumero_DeveSerDois&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GerarProximoNumero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_numerosGerados&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Só passa se PrimeiroNumero_DeveSerUm já rodou antes, e nessa ordem.&lt;/span&gt;
        &lt;span class="c1"&gt;// Rodar sozinho, em paralelo, ou com a suíte embaralhada: falha.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Independente — cada teste monta seu próprio estado, do zero&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NumeracaoNotaFiscalTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PrimeiroNumero_DeveSerUm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GerarProximoNumero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;());&lt;/span&gt;
        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SegundoNumero_DeveSerDois&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GerarProximoNumero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// pré-condição explícita, não herdada&lt;/span&gt;
        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O segundo exemplo é o padrão mais comum de "flakiness" na prática: dois testes que passam perfeitamente na ordem em que foram escritos, e falham de forma aparentemente aleatória assim que uma pipeline de CI paraliza a execução, ou quando algum framework de teste decide randomizar a ordem deliberadamente — justamente pra expor esse tipo de acoplamento escondido antes que ele vire um problema em produção.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;#13 Simplicidade e Refatoração Contínua&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A base conceitual mais direta vem de Kent Beck, em &lt;em&gt;Extreme Programming Explained&lt;/em&gt; (1999): as &lt;strong&gt;Quatro Regras do Design Simples&lt;/strong&gt;, nessa ordem de prioridade — (1) passa em todos os testes, (2) revela a intenção, (3) sem duplicação, (4) menor número de elementos possível. A ordem importa: só faz sentido buscar "menos elementos" depois de garantir que a intenção está clara e que não há duplicação — simplicidade não é sinônimo de "menos código a qualquer custo", é a ausência de tudo que não precisa estar ali.&lt;/p&gt;

&lt;p&gt;A ligação com dívida técnica, que a introdução já traz pelo relatório da Stripe, vem de Ward Cunningham, num relato de experiência na OOPSLA de 1992: código que corta caminho pra entregar mais rápido hoje é, literalmente, um empréstimo — você recebe velocidade agora e paga juros (retrabalho, fricção, tempo de entendimento) em cada mudança futura, até que alguém pague o principal de volta via refatoração. Cunningham não estava fazendo uma crítica moral ao atalho — dívida técnica pode ser escolha racional e deliberada —, o ponto dele é que ela tem que ser paga de algum jeito, consciente ou não.&lt;/p&gt;

&lt;p&gt;A técnica pra pagar essa dívida com segurança é formalizada por Martin Fowler em &lt;em&gt;Refactoring: Improving the Design of Existing Code&lt;/em&gt; (1999): uma sequência de pequenas transformações, cada uma preservando o comportamento observável do sistema, verificada por testes a cada passo — nunca uma reescrita de uma vez só. Robert C. Martin resume o hábito do dia a dia nisso com a &lt;strong&gt;Regra do Escoteiro&lt;/strong&gt;: deixe o código um pouco mais limpo do que você encontrou, toda vez que mexer nele — não precisa de um projeto formal de refatoração, é disciplina contínua aplicada a cada Pull Request.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Exemplo — duplicação que se acumula em silêncio:&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Complexo — a mesma validação de CPF/CNPJ duplicada em dois lugares do sistema&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidadorNotaFiscal&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;Validar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotaFiscal&lt;/span&gt; &lt;span class="n"&gt;nota&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nota&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cliente&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Documento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ~20 linhas de validação de CPF */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ~25 linhas de validação de CNPJ */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidadorTransmissao&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;PodeTransmitir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ArquivoEFinanceira&lt;/span&gt; &lt;span class="n"&gt;arquivo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Titular&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Documento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* a mesma validação de CPF, copiada e colada */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// quem corrigir um bug aqui precisa lembrar de corrigir no outro lugar também&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Simples — a regra vive em um único lugar; os dois validadores delegam&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidadorDocumento&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;EhValido&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;documento&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;limpo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Limpar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documento&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;limpo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="m"&gt;11&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ValidarCpf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limpo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="m"&gt;14&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ValidarCnpj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limpo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Limpar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidadorNotaFiscal&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;Validar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotaFiscal&lt;/span&gt; &lt;span class="n"&gt;nota&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ValidadorDocumento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EhValido&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nota&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cliente&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Documento&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa é a Regra 3 de Beck (sem duplicação) na prática. O perigo da versão duplicada não é só o volume de código — é que um bug corrigido num lugar continua vivo no outro, esperando quieto até alguém notar a divergência, geralmente meses depois, geralmente em produção.&lt;/p&gt;

</description>
      <category>refactoring</category>
      <category>softwareengineering</category>
      <category>testing</category>
    </item>
    <item>
      <title>Cluster 3: #8 distância do framework, #11 organizar por ator, #9 constructs corretos</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Sat, 01 Aug 2026 21:49:33 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/cluster-3-8-distancia-do-framework-11-organizar-por-ator-9-constructs-corretos-29j</link>
      <guid>https://dev.to/yuripeixinho/cluster-3-8-distancia-do-framework-11-organizar-por-ator-9-constructs-corretos-29j</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;A restrição já está posta pelo artigo: a &lt;strong&gt;Lei da Mudança Contínua de Lehman (1974)&lt;/strong&gt; — todo sistema em uso real será solicitado a mudar, indefinidamente, e a única pergunta em aberto é se essa mudança sai barata (alteração localizada) ou cara (reescrita). Os três princípios desse cluster não impedem a mudança — não tem como impedir que ela chegue —, eles atacam a &lt;strong&gt;fonte&lt;/strong&gt; de onde ela vem, cada um numa direção diferente: #8 blinda contra mudança que vem de fora do sistema (o ecossistema de frameworks), #11 blinda contra mudança que vem das pessoas ao redor do sistema (atores com pedidos concorrentes), e #9 blinda contra mudança que vem do próprio domínio crescendo além do que foi validado como seguro. &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;#8 Distância do Framework&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;A base conceitual é o que Robert C. Martin ("Uncle Bob") formaliza em &lt;em&gt;Clean Architecture&lt;/em&gt; (2017): frameworks pertencem ao anel mais externo da arquitetura — são um &lt;strong&gt;detalhe de entrega&lt;/strong&gt;, não o centro do sistema. A regra de negócio não deveria importar nada do framework; é o framework que deveria se adaptar pra rodar a regra de negócio (a Inversão de Dependência aplicada em escala arquitetural, não só entre duas classes). Martin propõe um teste simples pra isso, conhecido como "screaming architecture": olhando só a estrutura de pastas de um projeto, ela deveria gritar o domínio do negócio — "isso é um sistema de compliance fiscal" — e não gritar o framework — "isso é um projeto ASP.NET" ou "isso é um projeto Angular".&lt;/p&gt;

&lt;p&gt;O caso do AngularJS, é essa falha na prática: equipes que escreveram regra de negócio usando construtos específicos do AngularJS (&lt;code&gt;$scope&lt;/code&gt;, watchers, diretivas com lógica de domínio embutida) não enfrentaram só um problema de "trocar de framework" quando o suporte acabou em 2022 — tiveram que reescrever a regra de negócio em si, porque ela nunca existiu separada do framework pra começo de conversa. A mudança que a Lei de Lehman garante chegou pela porta do ecossistema, não por um pedido de negócio, e o custo foi o de uma reescrita completa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ruim — regra de negócio vive dentro do Controller, acoplada ao ASP.NET&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PedidoController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;CriarPedido&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;PedidoDto&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pedido sem itens"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// regra de negócio dentro do framework web&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValorTotal&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cliente&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tipo&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"PF"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Limite excedido para pessoa física"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Bom — regra de negócio isolada, sem qualquer referência ao ASP.NET&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidadorPedido&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ResultadoValidacao&lt;/span&gt; &lt;span class="nf"&gt;Validar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ResultadoValidacao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Falha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pedido sem itens"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValorTotal&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cliente&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tipo&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;TipoCliente&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PessoaFisica&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ResultadoValidacao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Falha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Limite excedido para pessoa física"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ResultadoValidacao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sucesso&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// O Controller vira uma casca fina que só traduz HTTP &amp;lt;-&amp;gt; domínio&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PedidoController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ValidadorPedido&lt;/span&gt; &lt;span class="n"&gt;_validador&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PedidoController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ValidadorPedido&lt;/span&gt; &lt;span class="n"&gt;validador&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_validador&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validador&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;CriarPedido&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;PedidoDto&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_validador&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Validar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParaPedido&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Valido&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Erro&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o ASP.NET Core for substituído amanhã — por minimal APIs, por outro framework inteiro —, só a casca (&lt;code&gt;PedidoController&lt;/code&gt;) muda. &lt;code&gt;ValidadorPedido&lt;/code&gt; nunca soube que o ASP.NET existia.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;#11 Organizar por Ator&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Martin também reformula aqui o "S" do SOLID. A formulação clássica do Single Responsibility Principle — "uma classe deve ter só uma razão pra mudar" — é vaga: razão pra mudar, segundo quem? Em &lt;em&gt;Clean Architecture&lt;/em&gt;, ele resolve a ambiguidade com uma definição operacional: &lt;strong&gt;um módulo deve ser responsável perante um, e apenas um, ator&lt;/strong&gt; — sendo ator o grupo de pessoas (ou papel de negócio) que pode solicitar uma mudança naquele módulo especificamente. Se dois atores diferentes têm poder de pedir mudanças na mesma classe, essa classe tem duas razões concorrentes pra mudar — e uma mudança pedida por um ator arrisca quebrar, silenciosamente, o comportamento que o outro ator depende, sem que ninguém tenha pedido isso.&lt;/p&gt;

&lt;p&gt;O exemplo canônico é uma classe &lt;code&gt;Funcionario&lt;/code&gt; que atende três atores ao mesmo tempo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ruim — uma classe atende três atores diferentes: Financeiro, RH e o time de dados&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Funcionario&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;CalcularSalario&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* regra que só o Financeiro pode pedir pra mudar */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GerarRelatorioHoras&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* regra que só o RH pode pedir pra mudar */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Salvar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* regra que só o time de dados/infra pode pedir pra mudar */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se &lt;code&gt;CalcularSalario&lt;/code&gt; e &lt;code&gt;GerarRelatorioHoras&lt;/code&gt; compartilham um método privado auxiliar — por exemplo, um cálculo de dias trabalhados no mês —, uma mudança pedida pelo Financeiro na fórmula de hora extra pode alterar silenciosamente o número que aparece no relatório do RH. O RH nunca pediu nada, nunca revisou nada, só um dia percebe que o número mudou sem aviso.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bom — cada ator tem sua própria classe; a mudança de um nunca atravessa pro código do outro&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculadoraSalario&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;Calcular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Funcionario&lt;/span&gt; &lt;span class="n"&gt;funcionario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* só o Financeiro mexe aqui */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RelatorioHoras&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Gerar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Funcionario&lt;/span&gt; &lt;span class="n"&gt;funcionario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* só o RH mexe aqui */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FuncionarioRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Salvar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Funcionario&lt;/span&gt; &lt;span class="n"&gt;funcionario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* só o time de dados mexe aqui */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Segundo exemplo, pra mostrar que o princípio não vale só entre classes — vale entre pastas/módulos também:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ruim — organizado por camada técnica; atores diferentes convivem no mesmo diretório&lt;/span&gt;
&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;
  &lt;span class="n"&gt;FuncionarioService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;      &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;muda&lt;/span&gt; &lt;span class="n"&gt;quando&lt;/span&gt; &lt;span class="n"&gt;Financeiro&lt;/span&gt; &lt;span class="n"&gt;OU&lt;/span&gt; &lt;span class="n"&gt;RH&lt;/span&gt; &lt;span class="n"&gt;pedem&lt;/span&gt; &lt;span class="n"&gt;algo&lt;/span&gt;
  &lt;span class="n"&gt;RelatorioService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;        &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;muda&lt;/span&gt; &lt;span class="n"&gt;quando&lt;/span&gt; &lt;span class="n"&gt;RH&lt;/span&gt; &lt;span class="n"&gt;OU&lt;/span&gt; &lt;span class="n"&gt;Diretoria&lt;/span&gt; &lt;span class="n"&gt;pedem&lt;/span&gt; &lt;span class="n"&gt;algo&lt;/span&gt;
  &lt;span class="n"&gt;NotificacaoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;      &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;muda&lt;/span&gt; &lt;span class="n"&gt;por&lt;/span&gt; &lt;span class="n"&gt;qualquer&lt;/span&gt; &lt;span class="n"&gt;motivo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt; &lt;span class="n"&gt;qualquer&lt;/span&gt; &lt;span class="n"&gt;ator&lt;/span&gt;

&lt;span class="c1"&gt;// Bom — organizado por ator/domínio; a mudança de um ator fica fisicamente isolada&lt;/span&gt;
&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Financeiro&lt;/span&gt;
  &lt;span class="n"&gt;CalculadoraSalario&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;
&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;RH&lt;/span&gt;
  &lt;span class="n"&gt;RelatorioHoras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;
  &lt;span class="n"&gt;GestaoFerias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;
&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Diretoria&lt;/span&gt;
  &lt;span class="n"&gt;RelatorioExecutivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na versão "por camada técnica", um Pull Request do RH e um Pull Request do Financeiro competem pelo mesmo arquivo (&lt;code&gt;FuncionarioService.cs&lt;/code&gt;) sem relação nenhuma entre os dois pedidos — terreno fértil pra conflito de merge e, pior, pra mudança de um ator vazar pro comportamento que o outro depende, sem ninguém perceber no code review.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;#9 Constructs Corretos&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Structs são blocos fundamentais de controle de fluxo e organização de código: &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;if/else&lt;/code&gt;, &lt;code&gt;switch&lt;/code&gt;, funções, recursão, estruturas de dados (arrays, listas, dicionários, etc.). "Usar constructs corretos" significa escolher a ferramenta certa pra cada problema, em vez de forçar uma solução genérica ou "na moda" onde ela não se encaixa.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Escolha a ferramenta certa pro problema — não a que você "sabe usar melhor"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;O exemplo clássico: iterar um array com &lt;code&gt;for&lt;/code&gt; em vez de recursão.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Desnecessariamente complexo — recursão para algo simples&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;SomarValores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;valores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;valores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;SomarValores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Correto — for/LINQ é direto e sem risco de stack overflow&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;SomarValores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valores&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;valores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recursão tem seu lugar (árvores, backtracking, algoritmos naturalmente recursivos), mas usar recursão pra percorrer uma lista simples é usar o construct errado — mais difícil de ler, mais arriscado (stack overflow em listas grandes), sem ganho nenhum.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Evite variáveis globais — passe dados via parâmetros e retornos
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ruim — estado global, difícil de rastrear quem altera o quê&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContextoAtual&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;TenantId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;PeriodoReferencia&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessarArquivo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// usa ContextoAtual.TenantId direto — de onde veio? quem garante que está certo?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Bom — dependência explícita via parâmetro&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessarArquivo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;periodoReferencia&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// fica óbvio de onde vêm os dados, e é testável isoladamente&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;3. Evite complexidade desnecessária&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Complexo demais para o que faz&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;EhValido&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;cnpj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;!(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cnpj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cnpj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Direto&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;EhValido&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;cnpj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cnpj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cnpj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aninhamentos de &lt;code&gt;if&lt;/code&gt; desnecessários, negações duplas, ternários encadeados — tudo isso é "construct errado" mesmo quando funciona, porque exige esforço mental extra de quem lê.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Control flow lógico e intuitivo
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Cadeia de if — funciona, mas escala mal&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ObterDescricaoStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusArquivo&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;StatusArquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pendente&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Pendente"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;StatusArquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Processando&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Processando"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;StatusArquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Concluido&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Concluído"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;StatusArquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Erro&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Erro"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Desconhecido"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Switch expression — mais legível pra múltiplos casos fixos&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ObterDescricaoStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusArquivo&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;StatusArquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pendente&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Pendente"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;StatusArquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Processando&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Processando"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;StatusArquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Concluido&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Concluído"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;StatusArquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Erro&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Erro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Desconhecido"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>architecture</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Cluster 2: #5 funções puras, #7 evitar null/booleanos, #12 command query separation</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Sat, 01 Aug 2026 21:49:20 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/cluster-2-5-funcoes-puras-7-evitar-nullbooleanos-12-command-query-separation-4a8d</link>
      <guid>https://dev.to/yuripeixinho/cluster-2-5-funcoes-puras-7-evitar-nullbooleanos-12-command-query-separation-4a8d</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Como já dito anteriormente: A restrição: quando o comportamento de uma função depende de estado invisível no momento da leitura (uma variável global, um efeito colateral escondido atrás de uma "consulta", uma flag booleana cujo significado não está no call site), reproduzir um bug exige reconstruir todo esse contexto invisível — e é exatamente por isso que esses bugs consomem tempo desproporcional de debug comparado a bugs em código puro. O caso mais grave documentado na literatura de engenharia de software é o&amp;nbsp;&lt;strong&gt;Therac-25&lt;/strong&gt;&amp;nbsp;(1985-1987): uma máquina de radioterapia cujo software tinha uma condição de corrida (estado compartilhado mutável, dependente de timing) que, combinada com a remoção dos interlocks de segurança em hardware que existiam nas versões anteriores, liberou doses de radiação até 100x acima do previsto, matando ao menos três pacientes. O relatório de Nancy Leveson e Clark Turner (1993) aponta diretamente para o problema de confiar em estado compartilhado sem isolamento. Num registro bem menos trágico mas igualmente didático, o colapso da&amp;nbsp;&lt;strong&gt;Knight Capital&lt;/strong&gt;&amp;nbsp;em 2012 — perda de US$460 milhões em 45 minutos — aconteceu porque uma flag booleana reaproveitada (que ligava um código morto de 8 anos atrás, chamado "Power Peg") foi ativada acidentalmente&amp;nbsp;num deploy incompleto: ninguém mais conseguia dizer com certeza o que aquela flag realmente controlava. Isso é o princípio #7 na prática: booleanos e nulos acumulam significado ambíguo com o tempo até&amp;nbsp;que ninguém consegue mais raciocinar sobre o que eles realmente ligam&amp;nbsp;ou&amp;nbsp;desligam.&lt;/p&gt;

&lt;p&gt;O fio condutor continua o mesmo:&amp;nbsp;&lt;strong&gt;estado escondido é a causa raiz dos bugs mais caros de rastrear.&lt;/strong&gt;&amp;nbsp;A diferença de um bug em código limpo pra um bug em código com estado escondido é a diferença entre achar uma chave debaixo do tapete e achar uma chave que foi escondida em algum lugar aleatório da casa há três meses, por alguém que nem trabalha mais aqui. Vamos nos três princípios, cada um com mais de um exemplo.&lt;/p&gt;

&lt;h2&gt;
  
  
  #5 Funções Puras
&lt;/h2&gt;

&lt;p&gt;A base é a transparência referencial (Strachey, 1967): uma expressão só pode ser trocada pelo seu valor sem mudar o comportamento do programa se ela não depender de nem alterar nada fora dela. Backus, no discurso do Turing Award de 1977, chama o estilo oposto (mutação de estado compartilhado, ao estilo da arquitetura von Neumann) de gerador de uma distância conceitual enorme entre o problema e o código — cada função pura elimina essa distância porque pode ser entendida e testada isolada do resto do universo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que isso importa na prática:&lt;/strong&gt; uma função pura é testável sem mock, sem setup, sem ordem de execução. Você chama com os mesmos argumentos e sempre recebe o mesmo resultado. Uma função impura como &lt;code&gt;CreateOrder(items)&lt;/code&gt; do exemplo esconde duas fontes de variação (&lt;code&gt;Guid.NewGuid()&lt;/code&gt;, &lt;code&gt;DateTime.Now&lt;/code&gt;) dentro da regra de negócio — isso significa que testar essa função exige ou aceitar não-determinismo no teste, ou fazer wrapping/mocking de chamadas estáticas do sistema, o que é sinal de que a impureza vazou pra dentro de algo que deveria ser lógica pura.&lt;/p&gt;

&lt;p&gt;A correção não é só "passar como parâmetro" por estética — é sobre &lt;strong&gt;onde a decisão não-determinística deve morar&lt;/strong&gt;. &lt;code&gt;Guid.NewGuid()&lt;/code&gt; e &lt;code&gt;DateTime.Now&lt;/code&gt; são decisões de infraestrutura (que ID usar, que relógio consultar), não decisões de negócio. Empurrar isso pra borda (controller, handler, o que for) significa que a regra de negócio (&lt;code&gt;CreateOrder&lt;/code&gt;) fica livre de qualquer coisa que não seja lógica pura de domínio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Impura&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="nb"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt; &lt;span class="n"&gt;escondidos&lt;/span&gt; &lt;span class="n"&gt;dentro&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt; &lt;span class="n"&gt;regra&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt; &lt;span class="n"&gt;neg&lt;/span&gt;&lt;span class="err"&gt;ó&lt;/span&gt;&lt;span class="n"&gt;cio&lt;/span&gt;
&lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;CreateOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Pura&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="n"&gt;entram&lt;/span&gt; &lt;span class="n"&gt;como&lt;/span&gt; &lt;span class="n"&gt;par&lt;/span&gt;&lt;span class="err"&gt;â&lt;/span&gt;&lt;span class="n"&gt;metro&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;quem&lt;/span&gt; &lt;span class="n"&gt;gera&lt;/span&gt; &lt;span class="n"&gt;esses&lt;/span&gt; &lt;span class="n"&gt;valores&lt;/span&gt; &lt;span class="err"&gt;é&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;borda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;por&lt;/span&gt; &lt;span class="n"&gt;exemplo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;CreateOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;#7&amp;nbsp;Evitar&amp;nbsp;null/booleanos&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;O artigo conecta isso diretamente ao caso Knight Capital: uma flag booleana reaproveitada ativou um código morto de 8 anos, e ninguém mais sabia com certeza o que aquela flag controlava. Isso não é sobre "booleano é ruim". É sobre o seguinte: &lt;strong&gt;um booleano só carrega um bit de informação, mas o significado desse bit precisa ser reconstruído de cabeça por quem lê o código&lt;/strong&gt;, e esse significado tende a se degradar com o tempo — a flag original tinha um propósito claro, mas depois de anos de reaproveitamento, ninguém consegue mais dizer com certeza o que ligar/desligar aquele bit realmente faz no sistema como um todo hoje.&lt;/p&gt;

&lt;p&gt;Com &lt;code&gt;null&lt;/code&gt; o problema é análogo mas com uma variante a mais: &lt;code&gt;null&lt;/code&gt; costuma significar simultaneamente "ainda não temos esse valor", "esse valor não se aplica" e "erro ao buscar esse valor" — três situações completamente diferentes, comprimidas na mesma representação. Quem lê &lt;code&gt;if (cliente.Endereco == null)&lt;/code&gt; não sabe qual dos três casos está tratando, e o compilador não ajuda a diferenciar.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Exemplo — null com múltiplos significados:&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Amb&lt;/span&gt;&lt;span class="err"&gt;í&lt;/span&gt;&lt;span class="n"&gt;guo&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="n"&gt;pode&lt;/span&gt; &lt;span class="n"&gt;significar&lt;/span&gt; &lt;span class="nv"&gt;"não processado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"não se aplica"&lt;/span&gt; &lt;span class="n"&gt;ou&lt;/span&gt; &lt;span class="nv"&gt;"erro"&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nb"&gt;decimal&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;DesconTotalAplicado&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DesconTotalAplicado&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Ainda&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="err"&gt;ã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;calculado&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;sem&lt;/span&gt; &lt;span class="n"&gt;desconto&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Falha&lt;/span&gt; &lt;span class="k"&gt;no&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="err"&gt;á&lt;/span&gt;&lt;span class="n"&gt;lculo&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
    &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="n"&gt;leitura&lt;/span&gt; &lt;span class="n"&gt;desse&lt;/span&gt; &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="err"&gt;ã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;responde&lt;/span&gt; &lt;span class="n"&gt;isso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Expl&lt;/span&gt;&lt;span class="err"&gt;í&lt;/span&gt;&lt;span class="n"&gt;cito&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;cada&lt;/span&gt; &lt;span class="n"&gt;estado&lt;/span&gt; &lt;span class="err"&gt;é&lt;/span&gt; &lt;span class="n"&gt;um&lt;/span&gt; &lt;span class="n"&gt;caso&lt;/span&gt; &lt;span class="n"&gt;nomeado&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nb"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;StatusDesconto&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;NaoCalculado&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SemDesconto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ErroNoCalculo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Aplicado&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="n"&gt;ResultadoDesconto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusDesconto&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Valor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Desconto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;StatusDesconto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NaoCalculado&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Agora&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="err"&gt;ã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="err"&gt;á&lt;/span&gt; &lt;span class="n"&gt;ambiguidade&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="err"&gt;á&lt;/span&gt; &lt;span class="n"&gt;diz&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;que&lt;/span&gt; &lt;span class="n"&gt;est&lt;/span&gt;&lt;span class="err"&gt;á&lt;/span&gt; &lt;span class="n"&gt;acontecendo&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Exemplo — booleano que vira flag de reaproveitamento:&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Perigoso&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="err"&gt;é&lt;/span&gt;&lt;span class="n"&gt;rica&lt;/span&gt; &lt;span class="n"&gt;que&lt;/span&gt; &lt;span class="n"&gt;qualquer&lt;/span&gt; &lt;span class="n"&gt;feature&lt;/span&gt; &lt;span class="n"&gt;futura&lt;/span&gt; &lt;span class="n"&gt;pode&lt;/span&gt; &lt;span class="n"&gt;reaproveitar&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;ModoAlternativo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModoAlternativo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ExecutarFluxoLegado&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Daqui&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;anos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;algu&lt;/span&gt;&lt;span class="err"&gt;é&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;vai&lt;/span&gt; &lt;span class="n"&gt;reativar&lt;/span&gt; &lt;span class="n"&gt;isso&lt;/span&gt; &lt;span class="n"&gt;achando&lt;/span&gt; &lt;span class="n"&gt;que&lt;/span&gt; &lt;span class="err"&gt;é&lt;/span&gt; &lt;span class="n"&gt;outra&lt;/span&gt; &lt;span class="n"&gt;coisa&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Expl&lt;/span&gt;&lt;span class="err"&gt;í&lt;/span&gt;&lt;span class="n"&gt;cito&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;cada&lt;/span&gt; &lt;span class="n"&gt;modo&lt;/span&gt; &lt;span class="n"&gt;tem&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="err"&gt;ó&lt;/span&gt;&lt;span class="n"&gt;sito&lt;/span&gt; &lt;span class="n"&gt;documentado&lt;/span&gt; &lt;span class="k"&gt;no&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="err"&gt;ó&lt;/span&gt;&lt;span class="n"&gt;prio&lt;/span&gt; &lt;span class="n"&gt;tipo&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nb"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ModoExecucao&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Padrao&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ReprocessamentoLegado&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MigracaoDados&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Modo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ModoExecucao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReprocessamentoLegado&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ExecutarFluxoLegado&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O segundo exemplo é literalmente o padrão do "Power Peg" da Knight Capital — uma flag que ligava um caminho de código antigo, sem que o significado dela estivesse escrito em lugar nenhum além da cabeça de quem a criou originalmente (e essa pessoa provavelmente já não estava mais na empresa quando o incidente aconteceu).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regra prática:&lt;/strong&gt; se um booleano ou um &lt;code&gt;null&lt;/code&gt; pode significar mais de uma coisa dependendo do contexto, ele deveria ser um enum, ou um tipo de resultado explícito (tipo &lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt;/&lt;code&gt;Result&amp;lt;T,E&amp;gt;&lt;/code&gt;, ou um record com status nomeado). O custo de escrever o enum é uma linha; o custo de não escrever é alguém, meses depois, precisando reconstruir de memória o que aquele bit realmente significa — exatamente o tipo de reconstrução de contexto invisível que a introdução do artigo descreve como a razão desses bugs consumirem tempo desproporcional.&lt;/p&gt;

&lt;h2&gt;
  
  
  #12 Command Query Separation
&lt;/h2&gt;

&lt;p&gt;Um método deve ser um Comando (faz algo, muda estado, não retorna valor) ou uma Query (responde uma pergunta, retorna valor, não muda nada) — nunca as duas coisas ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;O motivo disso se conectar diretamente ao fio condutor da introdução: uma função que parece uma pergunta ("me diga X") mas na verdade também é uma ordem escondida ("e de paço muda Y") é o caso mais insidioso de estado escondido, porque &lt;strong&gt;o nome da função mente sobre o que ela faz&lt;/strong&gt;. Quem lê o call site vê uma leitura e não tem motivo nenhum pra suspeitar de um efeito colateral — e é exatamente essa lacuna entre o que o código aparenta fazer e o que ele realmente faz que faz um bug consumir horas de debug ao invés de minutos.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Exemplo clássico — método que parece query mas é comando:&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Viola CQS — o nome sugere consulta, mas o método também gera efeito colateral&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;ValidarEProcessarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Pagamento&lt;/span&gt; &lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valido&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Valor&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CartaoValido&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valido&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_repositorio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Salvar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Efeito colateral escondido atrás de um nome de "validação"&lt;/span&gt;
        &lt;span class="n"&gt;_servicoEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enviar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cliente&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Pagamento processado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;valido&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Chamada — parece inofensiva, mas dispara persistência e envio de e-mail&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ValidarEProcessarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quem escreve &lt;code&gt;if (ValidarEProcessarPagamento(pagamento))&lt;/code&gt; num teste, ou numa tentativa de debug, provavelmente só quer checar se o pagamento é válido — e sem querer dispara persistência no banco e envio de e-mail de verdade. Isso é o análogo direto do "Power Peg" da Knight Capital: uma chamada que parece uma coisa (checagem) mas na verdade também é outra (ativação de um fluxo real), e a discrepância só aparece quando já é tarde.&lt;/p&gt;

&lt;h2&gt;
  
  
  Correção:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Query — só responde, sem efeito colateral&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;ValidarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Pagamento&lt;/span&gt; &lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Valor&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CartaoValido&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Comando — só age, não retorna valor de decisão&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Pagamento&lt;/span&gt; &lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_repositorio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Salvar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;_servicoEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enviar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cliente&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Pagamento processado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Chamada — a intenção de cada linha é legível sem precisar abrir a implementação&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ValidarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;ProcessarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pagamento&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Segundo exemplo, um padrão bem comum em código com estado mutável em memória — método que "verifica e incrementa" ao mesmo tempo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Viola CQS — parece uma consulta ("ainda tem estoque?") mas decrementa o estoque&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;TemEstoqueDisponivel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;produtoId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_estoque&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Buscar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quantidade&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quantidade&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Mutação escondida dentro de uma pergunta&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Separado — a pergunta não muta nada; a ordem é explícita e separada&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;TemEstoqueDisponivel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;produtoId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_estoque&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Buscar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Quantidade&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ReservarEstoque&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;produtoId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_estoque&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Buscar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quantidade&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note que essa separação também resolve, de quebra, um problema de race condition: se dois lugares diferentes chamam &lt;code&gt;TemEstoqueDisponivel&lt;/code&gt; na versão original (achando que é só uma checagem), ambos podem decrementar o estoque sem saber que o outro também fez isso — o mesmo tipo de condição de corrida sobre estado compartilhado que o Therac-25 exibia, só que em domínio de negócio ao invés de hardware médico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regra prática:&lt;/strong&gt; antes de escrever um método, pergunte "esse método responde uma pergunta ou executa uma ordem?" Se a resposta for "as duas coisas", é sinal de que ele precisa ser dividido em dois. O teste rápido: consegue chamar o método várias vezes seguidas sem mudar o resultado do programa (fora o retorno em si)? Se sim, é query. Se não, é comando — e não deveria fingir ser outra coisa através de um nome que sugere só leitura&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Cluster 1 do Clean Code: #1 consistência, #2 nomes, #3 estilo, #4 métodos/classes/arquivos pequenos, #6 complexidade ciclomática</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Sat, 25 Jul 2026 19:36:04 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/cluster-1-do-clean-code-1-consistencia-2-nomes-3-estilo-4-metodosclassesarquivos-2328</link>
      <guid>https://dev.to/yuripeixinho/cluster-1-do-clean-code-1-consistencia-2-nomes-3-estilo-4-metodosclassesarquivos-2328</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/yuripeixinho/4-clusters-do-clean-code-principles-9cd"&gt;Esse é um material que depende de leitura anterior. Recomendo ler o artigo introdutório antes de prosseguir.&lt;br&gt;
&lt;/a&gt;&lt;br&gt;
Como já dito anteriormente: a restrição aqui não é de gosto, é de hardware. A memória humana de trabalho segura certca de 7±2 "pedaços" de informação simultâneos. O que isso significa de fato? Uma função com 8 variáveis e 6 caminhos de decisão ativos exige que quem lê segure mais estado na cabeça do que ela fisicamente comporta. O erro de interpretação não é falta de atenção, é o estouro da capacidade cognitiva. Isso tem confirmação empírica direta em revisão de código. O revisor humano simplesmente para de conseguir processar depois de certo volume. Consistência, nomes claros e funções pequenas não deixam o código "bonito" — elas mantêm o problema dentro do que um cérebro humano consegue segurar de uma vez.&lt;/p&gt;
&lt;h2&gt;
  
  
  #1 Be Consistent
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Teoria:&lt;/strong&gt;&amp;nbsp;o experimento de Chase &amp;amp; Simon (1973) com mestres de xadrez mostrou que expertise é reconhecimento de padrões recorrentes tratados como um chunk só, e essa vantagem desaparece quando o padrão&amp;nbsp;é quebrado (posição aleatória no tabuleiro). Consistência é o que permite ao leitor transferir o reconhecimento aprendido num arquivo para o próximo; inconsistência zera essa transferência e obriga reconstrução do zero a&amp;nbsp;cada&amp;nbsp;arquivo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prática:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ruim — três verbos para a mesma operação, em três arquivos diferentes&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;retrieveOrders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Bom — mesmo verbo, reconhecível instantaneamente em qualquer arquivo&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getOrders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;#2 Meaningful names over comments&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Teoria:&lt;/strong&gt;&amp;nbsp;um nome bem escolhido externaliza um chunk pronto; o leitor consome o significado já processado em vez de derivá-lo ao vivo a partir da lógica bruta. Comentário tenta fazer o mesmo trabalho, mas com uma falha estrutural: não é verificado por nada, então quando o código muda e o comentário não acompanha, ele entrega um chunk&amp;nbsp;&lt;strong&gt;errado&lt;/strong&gt;&amp;nbsp;— pior que não ter nome nenhum, porque agora o leitor gasta memória extra descobrindo que o comentário mentiu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ruim — comentário tentando compensar nome ruim, e pode ficar desatualizado&lt;/span&gt;
&lt;span class="c1"&gt;// verifica se pode aplicar desconto de fidelidade&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;===&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Bom — o nome já é o chunk, comentário vira desnecessário&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;isEligibleForLoyaltyDiscount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt; &lt;span class="p"&gt;===&lt;/span&gt; &lt;span class="n"&gt;Tier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Gold&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;daysSinceSignup&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isEligibleForLoyaltyDiscount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;#3&amp;nbsp;Indentation&amp;nbsp;and&amp;nbsp;Code&amp;nbsp;Style&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Teoria:&lt;/strong&gt;&amp;nbsp;Larkin &amp;amp; Simon (1987) mostram que representações espaciais bem construídas permitem inferência por reconhecimento visual (rápido, quase grátis) em vez de busca simbólica sequencial (lenta, consome working memory). Indentação consistente transforma aninhamento&amp;nbsp;— uma informação lógica abstrata — em informação espacial, processada em paralelo pelo sistema visual em vez de competir pelo mesmo gargalo cognitivo usado&amp;nbsp;para&amp;nbsp;entender&amp;nbsp;a&amp;nbsp;regra&amp;nbsp;de&amp;nbsp;negócio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ruim — indentação inconsistente esconde a estrutura de aninhamento&lt;/span&gt;
&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="c1"&gt;// Bom — indentação consistente revela a estrutura de graça&lt;/span&gt;
&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No projeto de vocês isso nem deveria ser decisão manual —&amp;nbsp;&lt;code&gt;oxfmt&lt;/code&gt;&amp;nbsp;rodando via&amp;nbsp;&lt;code&gt;husky&lt;/code&gt;/&lt;code&gt;lint-staged&lt;/code&gt;&amp;nbsp;já resolve&amp;nbsp;isso&amp;nbsp;no&amp;nbsp;commit,&amp;nbsp;antes&amp;nbsp;de&amp;nbsp;chegar&amp;nbsp;em&amp;nbsp;code&amp;nbsp;review.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;#4&amp;nbsp;Keep&amp;nbsp;methods&amp;nbsp;/&amp;nbsp;classes&amp;nbsp;/&amp;nbsp;files&amp;nbsp;small&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Teoria:&lt;/strong&gt;&amp;nbsp;o orçamento de working memory (4-7 chunks) é fixo por leitura. Uma função pequena cabe inteira dentro desse orçamento; uma função grande obriga o leitor a "paginar" informação — soltar um chunk&amp;nbsp;pra abrir espaço pra outro — e é exatamente aí que se esquece uma condição vista no início&amp;nbsp;enquanto&amp;nbsp;se&amp;nbsp;lê&amp;nbsp;o&amp;nbsp;fim.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prática:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Ruim&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;uma&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="err"&gt;çã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;fazendo&lt;/span&gt; &lt;span class="n"&gt;filtro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;soma&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;formata&lt;/span&gt;&lt;span class="err"&gt;çã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;juntos&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getOrderSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'cancelled'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;`${active.length} pedidos ativos, total de R$${total.toFixed(2).replace('.', ',')}`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Bom&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;cada&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="err"&gt;çã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;um&lt;/span&gt; &lt;span class="err"&gt;ú&lt;/span&gt;&lt;span class="n"&gt;nico&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="err"&gt;í&lt;/span&gt;&lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt; &lt;span class="n"&gt;abstra&lt;/span&gt;&lt;span class="err"&gt;çã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="err"&gt;á&lt;/span&gt;&lt;span class="n"&gt;vel&lt;/span&gt; &lt;span class="n"&gt;isoladamente&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getActiveOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'cancelled'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getTotalValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;formatCurrency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;`R$${value.toFixed(2).replace('.', ',')}`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getOrderSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getActiveOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;`${active.length} pedidos ativos, total de${formatCurrency(getTotalValue(active))}`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;#6&amp;nbsp;Minimize&amp;nbsp;cyclomatic&amp;nbsp;complexity&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Teoria:&lt;/strong&gt;&amp;nbsp;McCabe (1976) conta pontos de decisão (&lt;code&gt;if&lt;/code&gt;,&amp;nbsp;&lt;code&gt;case&lt;/code&gt;,&amp;nbsp;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;,&amp;nbsp;&lt;code&gt;||&lt;/code&gt;, laços) na fórmula V(G) = E − N + 2; o NIST (SP 500-235) classifica acima de 10 como risco moderado e acima de 50 como praticamente intestável. Vale uma ressalva importante: a fórmula original de McCabe&amp;nbsp;&lt;strong&gt;não pesa profundidade de aninhamento&lt;/strong&gt;&amp;nbsp;— um&amp;nbsp;&lt;code&gt;if&lt;/code&gt;&amp;nbsp;aninhado dentro de outro conta igual a um&amp;nbsp;&lt;code&gt;if&lt;/code&gt;&amp;nbsp;solto no mesmo nível, mesmo que o aninhado exija segurar mais chunks simultâneos na cabeça. Foi exatamente essa lacuna que motivou a SonarSource a propor, em 2017, a métrica de&amp;nbsp;&lt;strong&gt;Complexidade Cognitiva&lt;/strong&gt;, que penaliza aninhamento explicitamente — essa é, na prática, a métrica mais alinhada com o argumento do Cluster 1 (memória de trabalho), enquanto McCabe original mede melhor “quantos caminhos preciso testar” (o que cruza com o Cluster 4, de testes).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Complexidade&lt;/span&gt; &lt;span class="n"&gt;alta&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;decis&lt;/span&gt;&lt;span class="err"&gt;õ&lt;/span&gt;&lt;span class="n"&gt;es&lt;/span&gt; &lt;span class="n"&gt;aninhadas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todas&lt;/span&gt; &lt;span class="n"&gt;precisam&lt;/span&gt; &lt;span class="n"&gt;ficar&lt;/span&gt; &lt;span class="n"&gt;ativas&lt;/span&gt; &lt;span class="n"&gt;na&lt;/span&gt; &lt;span class="n"&gt;cabe&lt;/span&gt;&lt;span class="err"&gt;ç&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;canEditOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'draft'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ownerId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Complexidade&lt;/span&gt; &lt;span class="n"&gt;baixa&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cada&lt;/span&gt; &lt;span class="n"&gt;condi&lt;/span&gt;&lt;span class="err"&gt;çã&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;resolvida&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;descartada&lt;/span&gt; &lt;span class="n"&gt;da&lt;/span&gt; &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="err"&gt;ó&lt;/span&gt;&lt;span class="n"&gt;ria&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;canEditOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'draft'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ownerId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui&amp;nbsp;o&amp;nbsp;número&amp;nbsp;de&amp;nbsp;McCabe&amp;nbsp;é&amp;nbsp;quase&amp;nbsp;o&amp;nbsp;mesmo&amp;nbsp;nas&amp;nbsp;duas&amp;nbsp;versões&amp;nbsp;(mesmas&amp;nbsp;3&amp;nbsp;decisões)&amp;nbsp;—&amp;nbsp;a&amp;nbsp;diferença&amp;nbsp;real&amp;nbsp;é&amp;nbsp;a&amp;nbsp;complexidade&amp;nbsp;cognitiva:&amp;nbsp;na&amp;nbsp;primeira&amp;nbsp;versão&amp;nbsp;você&amp;nbsp;precisa&amp;nbsp;segurar&amp;nbsp;até&amp;nbsp;3&amp;nbsp;condições&amp;nbsp;aninhadas&amp;nbsp;ativas&amp;nbsp;ao&amp;nbsp;mesmo&amp;nbsp;tempo&amp;nbsp;pra&amp;nbsp;saber&amp;nbsp;qual&amp;nbsp;&lt;code&gt;return&lt;/code&gt;&amp;nbsp;está&amp;nbsp;sendo&amp;nbsp;executado,na&amp;nbsp;segunda,&amp;nbsp;cada&amp;nbsp;linha&amp;nbsp;resolve&amp;nbsp;e&amp;nbsp;descarta&amp;nbsp;uma&amp;nbsp;condição&amp;nbsp;antes&amp;nbsp;de&amp;nbsp;passar&amp;nbsp;pra&amp;nbsp;próxima.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>software</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>4 Clusters do Clean Code Principles</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Sat, 25 Jul 2026 19:18:44 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/4-clusters-do-clean-code-principles-9cd</link>
      <guid>https://dev.to/yuripeixinho/4-clusters-do-clean-code-principles-9cd</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;O termo virou disciplina formal com o livre de Robert C. Martin, conhecido por “Uncle Bob”, &lt;em&gt;Clean Code: A Handbook of Agile Software Craftsmanship&lt;/em&gt;&amp;nbsp;(2008), nascido do movimento ágil/XP no fim dos anos 90 como reação aos projetos que afundavam sobre o peso do próprio código, a motivação não é estética, é econômica.&lt;/p&gt;

&lt;p&gt;O próprio Martin cita que a proporção entre tempo lendo código e tempo escrevendo código é “bem acima de 10 para 1”, e Robert Glass, em Facts and Fallacies of Software Engineering (2002), mostra que a manutenção consome entre 40% e 80% (média ~60%).&lt;/p&gt;

&lt;h1&gt;
  
  
  Os 13 Princípios
&lt;/h1&gt;

&lt;p&gt;Muitos desenvolvedores acreditam que os princípios são recomendações independentes, portanto, faz mais sentido tratar como respostas a um punhado de restrições que existem quer que você as respeite ou quer não. Desse modo, podemos agrupar os 13 princípios em quatro necessidades reais, cada uma com um caso concreto que acontece quando ela é ignorada.&lt;/p&gt;

&lt;p&gt;Vamos dividir esses princípios em quatro clusters diferentes, cada um se refere a uma respectiva area. Eles não competem entre si, eles atacam, respectivamente, o limite do cérebro que lê o código, o custo de rastrear estado invisível, o custo de mudar algo estruturado do jeito errado, e o mecanismo que permite manter os três anteriores funcionando daqui a dois anos, não só no dia em que o código foi escrito.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cluster 1 — Limíte físico da memória de trabalho humanada.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Princípios:&lt;/strong&gt;&amp;nbsp;#1 consistência, #2 nomes, #3 estilo, #4 métodos/classes/arquivos pequenos, #6 complexidade ciclomática&lt;/p&gt;

&lt;p&gt;A restrição aqui não é de gosto, é de hardware. A memória humana de trabalho segura certca de 7±2 "pedaços" de informação simultâneos. O que isso significa de fato? Uma função com 8 variáveis e 6 caminhos de decisão ativos exige que quem lê segure mais estado na cabeça do que ela fisicamente comporta. O erro de interpretação não é falta de atenção, é o estouro da capacidade cognitiva. Isso tem confirmação empírica direta em revisão de código. O revisor humano simplesmente para de conseguir processar depois de certo volume. Consistência, nomes claros e funções pequenas não deixam o código "bonito" — elas mantêm o problema dentro do que um cérebro humano consegue segurar de uma vez.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cluster 2 — Estado escondido é a causa rais dos bugs mais caros de rastrear
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Princípios:&lt;/strong&gt;&amp;nbsp;#5 funções puras, #7 evitar null/booleanos, #12 command&amp;nbsp;query&amp;nbsp;separation&lt;/p&gt;

&lt;p&gt;A restrição: quando o comportamento de uma função depende de estado invisível no momento da leitura (uma variável global, um efeito colateral escondido atrás de uma "consulta", uma flag booleana cujo significado não está no call site), reproduzir um bug exige reconstruir todo esse contexto invisível — e é exatamente por isso que esses bugs consomem tempo desproporcional de debug comparado a bugs em código puro. O caso mais grave documentado na literatura de engenharia de software é o&amp;nbsp;&lt;strong&gt;Therac-25&lt;/strong&gt;&amp;nbsp;(1985-1987): uma máquina de radioterapia cujo software tinha uma condição de corrida (estado compartilhado mutável, dependente de timing) que, combinada com a remoção dos interlocks de segurança em hardware que existiam nas versões anteriores, liberou doses de radiação até 100x acima do previsto, matando ao menos três pacientes. O relatório de Nancy Leveson e Clark Turner (1993) aponta diretamente para o problema de confiar em estado compartilhado sem isolamento. Num registro bem menos trágico mas igualmente didático, o colapso da&amp;nbsp;&lt;strong&gt;Knight Capital&lt;/strong&gt;&amp;nbsp;em 2012 — perda de US$460 milhões em 45 minutos — aconteceu porque uma flag booleana reaproveitada (que ligava um código morto de 8 anos atrás, chamado "Power Peg") foi ativada acidentalmente&amp;nbsp;num deploy incompleto: ninguém mais conseguia dizer com certeza o que aquela flag realmente controlava. Isso é o princípio #7 na prática: booleanos e nulos acumulam significado ambíguo com o tempo até&amp;nbsp;que ninguém consegue mais raciocinar sobre o que eles realmente ligam&amp;nbsp;ou&amp;nbsp;desligam.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cluster 3 — Mudança é garantida; a estrutura decisde se ela sai barata ou cara
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Princípios:&lt;/strong&gt;&amp;nbsp;#8 distância do framework, #11 organizar por ator, #9 constructs corretos&lt;/p&gt;

&lt;p&gt;A restrição vem direto da&amp;nbsp;&lt;strong&gt;Lei da Mudança Contínua&lt;/strong&gt;&amp;nbsp;de Lehman (1974): todo sistema em uso real será solicitado a mudar, indefinidamente — a única variável em aberto é se sua arquitetura absorve essa mudança com uma alteração localizada ou exige reescrita. Frameworks front-end viraram e morreram várias vezes em poucas décadas (o próprio fim de vida do AngularJS em 2022 forçou reescritas inteiras em empresas que tinham misturado regra de negócio com APIs do framework). O caso mais caro já registrado de "reaproveitar construção sem revalidar o contexto" é o&amp;nbsp;&lt;strong&gt;Ariane 5&lt;/strong&gt;&amp;nbsp;(1996): a Agência Espacial Europeia reaproveitou o software de referência inercial do foguete Ariane 4 sem revalidar se os valores numéricos ainda cabiam nos mesmos limites — o Ariane 5 tinha velocidade horizontal maior, um valor estourou a conversão de 64 bits para 16 bits, a exceção não foi tratada, e o foguete se autodestruiu 37 segundos após o lançamento, um prejuízo de ~US$370 milhões. Não foi falta de teste no sentido abstrato — foi código correto&amp;nbsp;&lt;em&gt;no contexto errado&lt;/em&gt;, exatamente o risco que organizar por ator/domínio e manter regra de negócio&amp;nbsp;isolada&amp;nbsp;do&amp;nbsp;framework&amp;nbsp;existem&amp;nbsp;para&amp;nbsp;evitar.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Cluster&amp;nbsp;4&amp;nbsp;—&amp;nbsp;Sem&amp;nbsp;rede&amp;nbsp;de&amp;nbsp;segurança&amp;nbsp;rápida,&amp;nbsp;toda&amp;nbsp;a&amp;nbsp;disciplina&amp;nbsp;anterior&amp;nbsp;apodrece&amp;nbsp;sozinha&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Princípios:&lt;/strong&gt;&amp;nbsp;#10&amp;nbsp;testes&amp;nbsp;rápidos&amp;nbsp;e&amp;nbsp;independentes,&amp;nbsp;#13&amp;nbsp;simplicidade&amp;nbsp;e&amp;nbsp;refatoração&amp;nbsp;contínua&lt;/p&gt;

&lt;p&gt;Esse&amp;nbsp;cluster&amp;nbsp;é&amp;nbsp;diferente&amp;nbsp;dos&amp;nbsp;outros&amp;nbsp;três:&amp;nbsp;ele&amp;nbsp;não&amp;nbsp;previne&amp;nbsp;um&amp;nbsp;tipo&amp;nbsp;de&amp;nbsp;bug,&amp;nbsp;ele&amp;nbsp;&lt;strong&gt;sustenta&amp;nbsp;a&amp;nbsp;capacidade&amp;nbsp;de&amp;nbsp;manter&amp;nbsp;os&amp;nbsp;outros&amp;nbsp;nove&amp;nbsp;princípios&amp;nbsp;ao&amp;nbsp;longo&amp;nbsp;do&amp;nbsp;tempo&lt;/strong&gt;.&amp;nbsp;A&amp;nbsp;segunda&amp;nbsp;lei&amp;nbsp;de&amp;nbsp;Lehman,&amp;nbsp;a&amp;nbsp;&lt;strong&gt;Lei&amp;nbsp;da&amp;nbsp;Complexidade&amp;nbsp;Crescente&lt;/strong&gt;,&amp;nbsp;diz&amp;nbsp;que&amp;nbsp;a&amp;nbsp;complexidade&amp;nbsp;de&amp;nbsp;um&amp;nbsp;sistema&amp;nbsp;aumenta&amp;nbsp;por&amp;nbsp;padrão&amp;nbsp;a&amp;nbsp;menos&amp;nbsp;que&amp;nbsp;alguém&amp;nbsp;trabalhe&amp;nbsp;ativamente&amp;nbsp;para&amp;nbsp;reduzir-la. Refatoração não é uma tarefa opcional de “polimento”, é a única força que contrabalança uma tendência que existe independente da sua vontade. Mas refatorar só é seguro se você consegue confirmar rapidamente que nada quebrou — e é aí que testes lentos ou dependentes de ordem matam a disciplina inteira: se rodar a suíte demora 20 minutos ou falha de forma inconsistente, o time para de rodar, para de confiar, e para de refatorar, e a lei da complexidade crescente passa a valer sem oposição. Esse não é um risco teórico: o relatório The Developer Coefficient (Stripe, 2018), baseado em pesquisa com centenas de desenvolvedores e executivos de engenharia, estimou que uma fração substancial da semana de trabalho — na casa de um terço a 40% — é perdida lidando com dívida técnica e código malfeito, com impacto econômico global estimado em centenas de bilhões de dólares por ano. Esse número é, em essência, o preço agregado de organizações que pararam de fazer #10 e #13 e deixaram a lei de Lehman correr sem freio.&lt;/p&gt;

</description>
      <category>code</category>
      <category>software</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>SQL: Melhores Práticas de Segurança</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Wed, 22 Jul 2026 16:50:14 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/sql-melhores-praticas-de-seguranca-222n</link>
      <guid>https://dev.to/yuripeixinho/sql-melhores-praticas-de-seguranca-222n</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Os números que abrem este artigo não são abstratos: US$ 4,45 milhões é o custo médio de uma violação, e credenciais comprometidas ou uso indevido de privilégios estão entre as causas mais citadas ano após ano nos relatórios da Verizon. As práticas abaixo existem porque, historicamente, foi assim que as violações mais caras aconteceram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Princípio do menor privilégio
&lt;/h2&gt;

&lt;p&gt;Audite periodicamente quem tem acesso a quê. É comum um privilégio concedido "temporariamente" para resolver um problema pontual nunca ser revogado, isso se acumula ao longo de anos até que praticamente todo mundo tem acesso a tudo, o oposto do que Griffiths &amp;amp; Wade propuseram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nunca concatenar SQL, sempre parametrizar
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- PERIGOSO: concatenação direta permite SQL Injection&lt;/span&gt;
&lt;span class="nv"&gt;"SELECT * FROM usuarios WHERE email = '"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;email_do_usuario&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;"'"&lt;/span&gt;

&lt;span class="c1"&gt;-- SEGURO: query parametrizada&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;usuarios&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SQL Injection continua, décadas depois, sendo uma das vulnerabilidades mais exploradas do OWASP Top 10 — e a defesa é simples: nunca construir SQL por concatenação de string com input externo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criptografia em trânsito e em repouso
&lt;/h2&gt;

&lt;p&gt;Conexões com o banco devem usar TLS/SSL (em trânsito), e dados sensíveis (senhas, dados de pagamento, documentos) devem ser criptografados no armazenamento (em repouso) de forma que, mesmo se alguém acessar o disco fisicamente ou um backup vazar, os dados não sejam legíveis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auditoria e Logging
&lt;/h2&gt;

&lt;p&gt;Manter registro de quem executou o quê, e quando, especialmente para operações sensíveis (&lt;code&gt;DELETE&lt;/code&gt;, mudanças de permissão, acesso a tabelas com dados pessoais). Sem isso, uma violação pode passar meses sem ser percebida.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Separação de ambientes e contas de serviço&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A aplicação em produção não deveria conectar no banco com uma conta de administrador. Cada serviço deve ter sua própria conta, com privilégios mínimos e escopados exatamente ao que aquele serviço faz, se uma aplicação for comprometida, o estrago fica contido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backups testados
&lt;/h2&gt;

&lt;p&gt;Segurança não é só impedir acesso indevido, é também garantir recuperação. Um backup que nunca foi restaurado em teste é, na prática, um backup que você não sabe se funciona.&lt;/p&gt;

</description>
      <category>database</category>
      <category>security</category>
      <category>sql</category>
    </item>
    <item>
      <title>SQL: GRANT and REVOKE</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Wed, 22 Jul 2026 16:44:27 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/sql-grant-and-revoke-1383</link>
      <guid>https://dev.to/yuripeixinho/sql-grant-and-revoke-1383</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Em 1976, dois pesquisadores da IBM, Patricia Griffiths e Bradford Wade, publicaram&amp;nbsp;&lt;em&gt;"An Authorization Mechanism for a Relational Database System"&lt;/em&gt;&amp;nbsp;— o paper que descreveu o modelo de autorização construído para o System R, o protótipo que deu origem ao SQL. O problema que eles resolviam era muito concreto: pela primeira vez,&amp;nbsp;&lt;strong&gt;múltiplos departamentos e usuários compartilhavam o mesmo banco de dados físico&lt;/strong&gt;, em vez de cada aplicação ter seus próprios arquivos isolados. Alguém no financeiro não deveria conseguir apagar tabelas de RH só porque tinha acesso ao mesmo servidor. Esse paper é literalmente a origem do&amp;nbsp;&lt;code&gt;GRANT&lt;/code&gt;/&lt;code&gt;REVOKE&lt;/code&gt;&amp;nbsp;que você usa hoje.&lt;/p&gt;

&lt;h2&gt;
  
  
  GRANT, concedendo privilégios
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;usuario_vendas&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;admin_sistema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;transferir_saldo&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;app_usuario&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você concede ações específicas (&lt;code&gt;SELECT, INSERT, UPDATE, DELETE, EXECUTE...&lt;/code&gt;) sobre objetos específicos (tabelas, views, procedures) para usuários ou roles específicos.&lt;/p&gt;

&lt;h2&gt;
  
  
  REVOKE, retirando privilégios
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;REVOKE&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;usuario_vendas&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;REVOKE&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;ex_funcionario&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O oposto simétrico do&amp;nbsp;&lt;code&gt;GRANT&lt;/code&gt;&amp;nbsp;— remove exatamente o que foi concedido, sem afetar outros privilégios que a pessoa já tinha.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;WITH GRANT OPTION, repassando permissões&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Isso permite que&amp;nbsp;&lt;code&gt;gerente_vendas&lt;/code&gt;&amp;nbsp;&lt;strong&gt;também conceda&lt;/strong&gt;&amp;nbsp;esse mesmo privilégio para outras pessoas — útil para delegar administração de acesso sem te tornar um gargalo, mas usado com cautela (cada nível de repasse é um lugar a mais onde o controle pode escapar).&lt;/p&gt;

</description>
      <category>database</category>
      <category>security</category>
      <category>sql</category>
    </item>
    <item>
      <title>SQL: Data Integrity Constraints</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Wed, 22 Jul 2026 16:44:04 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/sql-data-integrity-constraints-3n09</link>
      <guid>https://dev.to/yuripeixinho/sql-data-integrity-constraints-3n09</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Em 1970, um matemático da IBM chamado Edgar F. Codd publicou um paper chamado "A Relational Model of Data for Large Shared Data Banks". Antes disso, os bancos de dados eram majoritariamente hierárquicos ou baseados em arquivos simples (como o IMS da própria IBM, de 1966) — e a garantia de que os dados faziam sentido era inteiramente responsabilidade da aplicação. Se um programador esquecesse de checar se um cliente existia antes de gravar um pedido, ou se duas aplicações diferentes escreviam no mesmo arquivo com regras diferentes, os dados simplesmente ficavam inconsistentes. Não existia rede de segurança dentro do banco.&lt;/p&gt;

&lt;p&gt;Quando Codd formalizou o modelo relacional, e depois, em 1985, publicou suas famosas "12 regras" para o que um banco verdadeiramente relacional deveria garantir, uma delas — a Regra 10, "Integrity Independence" — dizia algo radical para a época: as regras de integridade não podem depender da aplicação. Elas precisam viver dentro do banco, no catálogo, indissociáveis dos dados. É essa ideia, de quase 50 anos atrás, que sustenta tudo que vamos ver a seguir.&lt;/p&gt;

&lt;p&gt;E não é só sobre corrupção de dados por acidente. É também sobre quem pode tocar no quê. Segundo o&amp;nbsp;&lt;em&gt;Cost of a Data Breach Report&lt;/em&gt;&amp;nbsp;da IBM (2023), o custo médio global de uma violação de dados passou de&amp;nbsp;&lt;strong&gt;US$ 4,45 milhões&lt;/strong&gt;&amp;nbsp;— e o&amp;nbsp;&lt;em&gt;Data Breach Investigations Report&lt;/em&gt;&amp;nbsp;da Verizon, ano após ano, aponta credenciais comprometidas e uso indevido de privilégios como alguns dos vetores mais recorrentes de invasão. Integridade e segurança não são burocracia: são a diferença entre um&amp;nbsp;banco confiável e um acidente&amp;nbsp;esperando&amp;nbsp;para&amp;nbsp;acontecer.&lt;/p&gt;

&lt;h1&gt;
  
  
  Constraints
&lt;/h1&gt;

&lt;p&gt;Constraints são regras que você declara junto com a estrutura da tabela, e que o próprio banco passa a fiscalizar automaticamente, sem depender de nenhuma aplicação lembrar de validar nada. Se uma regra é violada, o banco simplesmente recusa a operação, não importa de onde ela veio (seu backend, um script de outro time, uma query manual de madrugada).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;code&gt;NOT&amp;nbsp;NULL&lt;/code&gt;, a&amp;nbsp;garantia&amp;nbsp;mais&amp;nbsp;básica&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Impede que um campo essencial fique vazio. Parece trivial, mas é a constraint que mais previne bugs silenciosos em relatórios (&lt;code&gt;COUNT&lt;/code&gt;,&amp;nbsp;&lt;code&gt;SUM&lt;/code&gt;&amp;nbsp;e&amp;nbsp;&lt;code&gt;JOIN&lt;/code&gt;&amp;nbsp;se&amp;nbsp;comportam&amp;nbsp;de&amp;nbsp;forma&amp;nbsp;traiçoeira&amp;nbsp;quando&amp;nbsp;encontram&amp;nbsp;&lt;code&gt;NULL&lt;/code&gt;&amp;nbsp;inesperado,&amp;nbsp;como&amp;nbsp;vimos&amp;nbsp;quando&amp;nbsp;falamos&amp;nbsp;de&amp;nbsp;&lt;code&gt;COALESCE&lt;/code&gt;&amp;nbsp;e&amp;nbsp;&lt;code&gt;NULLIF&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;code&gt;UNIQUE&lt;/code&gt;,&amp;nbsp;sem&amp;nbsp;duplicatas&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;cpf&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Garante que dois clientes nunca terão o mesmo CPF ou e-mail — o banco rejeita o segundo &lt;code&gt;INSERT&lt;/code&gt; antes mesmo dele acontecer.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;PRIMARY&amp;nbsp;KEY&lt;/code&gt;,&amp;nbsp;identidade&amp;nbsp;única&amp;nbsp;da&amp;nbsp;linha&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Combina &lt;code&gt;NOT NULL&lt;/code&gt; + &lt;code&gt;UNIQUE&lt;/code&gt;, e é o identificador que outras tabelas usam para apontar para essa linha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;FOREIGN&amp;nbsp;KEY&lt;/code&gt;,&amp;nbsp;integridade&amp;nbsp;referencial&amp;nbsp;(a&amp;nbsp;mais&amp;nbsp;importante&amp;nbsp;do&amp;nbsp;artigo)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Esta é, historicamente, a constraint que Codd mais insistiu em formalizar. Ela garante que uma linha não pode referenciar algo que não existe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;cliente_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sem isso, seria possível criar um pedido apontando para cliente_id = 9999, quando o cliente 9999 nunca existiu (ou foi deletado) — um registro órfão, que quebra relatórios e JOINs silenciosamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O&amp;nbsp;que&amp;nbsp;fazer&amp;nbsp;quando&amp;nbsp;o&amp;nbsp;"pai"&amp;nbsp;é&amp;nbsp;deletado?&lt;/strong&gt;&amp;nbsp;Isso&amp;nbsp;é&amp;nbsp;definido&amp;nbsp;em&amp;nbsp;&lt;code&gt;ON DELETE&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;    &lt;span class="c1"&gt;-- deleta os pedidos junto&lt;/span&gt;
&lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;   &lt;span class="c1"&gt;-- pedido fica "sem cliente"&lt;/span&gt;
&lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;RESTRICT&lt;/span&gt;&lt;span class="c1"&gt;-- impede deletar o cliente enquanto houver pedidos (padrão mais seguro)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;CHECK&lt;/code&gt;,&amp;nbsp;regras&amp;nbsp;de&amp;nbsp;negócio&amp;nbsp;arbitrárias&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;preco&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preco&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;desconto&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt; &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;desconto&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diferente das constraints anteriores (que são estruturais), CHECK valida regras de negócio arbitrárias — preço não pode ser negativo, desconto não pode passar de 100%. É a forma mais direta de embutir uma regra de domínio na própria estrutura da tabela.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;DEFAULT&lt;/code&gt;, preenchendo&amp;nbsp;lacunas&amp;nbsp;com&amp;nbsp;sensatez&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'pendente'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;criado_em&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não impede um valor inválido, mas garante que, na ausência de um valor explícito, o banco preenche algo sensato, evitando que &lt;code&gt;NULL&lt;/code&gt;s se espalhem por falta de atenção da aplicação.&lt;/p&gt;

&lt;p&gt;O fio condutor de tudo isso: a integridade sai da aplicação e vai para o banco. Exatamente a tese que Codd defendia em 1985, e que continua sendo a diferença entre um sistema que se autopolicia e um que depende da sorte de todo desenvolvedor lembrar de validar tudo, sempre, em todo lugar que escreve no banco.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>computerscience</category>
      <category>database</category>
      <category>sql</category>
    </item>
    <item>
      <title>SQL: Stored Procedures e Functions</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Wed, 22 Jul 2026 03:29:55 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/sql-stored-procedures-e-functions-24p4</link>
      <guid>https://dev.to/yuripeixinho/sql-stored-procedures-e-functions-24p4</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Quando você manda uma query SQL avulsa, o banco faz isso&amp;nbsp;&lt;strong&gt;toda vez&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parse&lt;/strong&gt;&amp;nbsp;— analisa a sintaxe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Otimização&lt;/strong&gt;&amp;nbsp;— decide o melhor plano de execução (quais índices usar, ordem dos JOINs, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execução&lt;/strong&gt;&amp;nbsp;— roda de fato.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Uma&amp;nbsp;&lt;strong&gt;stored procedure/function&lt;/strong&gt;&amp;nbsp;é salva no banco com nome próprio, e o banco guarda (ou reutiliza) o&amp;nbsp;&lt;strong&gt;plano de execução já otimizado&lt;/strong&gt;&amp;nbsp;para as próximas chamadas. Isso poupa o trabalho de reanalisar e replanejar a mesma lógica repetidamente — é isso que "precompilado" quer dizer na prática (não é bytecode compilado feito um&amp;nbsp;&lt;code&gt;.exe&lt;/code&gt;,&amp;nbsp;é&amp;nbsp;o&amp;nbsp;plano&amp;nbsp;de&amp;nbsp;execução&amp;nbsp;em&amp;nbsp;cache).&lt;/p&gt;

&lt;h1&gt;
  
  
  Stored Procedures
&lt;/h1&gt;

&lt;p&gt;Um bloco de código SQL + lógica procedural (variáveis,&amp;nbsp;&lt;code&gt;IF&lt;/code&gt;,&amp;nbsp;&lt;code&gt;WHILE&lt;/code&gt;, loops) salvo no banco, que você&amp;nbsp;&lt;strong&gt;executa/chama&lt;/strong&gt;&amp;nbsp;— não usa&amp;nbsp;dentro&amp;nbsp;de&amp;nbsp;um&amp;nbsp;&lt;code&gt;SELECT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sintaxe (varia bastante entre bancos)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQL&amp;nbsp;Server&amp;nbsp;(T-SQL):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;TransferirSaldo&lt;/span&gt;
  &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;conta_origem&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;conta_destino&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;conta_origem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;conta_destino&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Chamando:&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;TransferirSaldo&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;conta_origem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;conta_destino&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare que já conectamos com assunto de Transact e ACID: a procedure encapsula a&amp;nbsp;&lt;strong&gt;transação inteira&lt;/strong&gt;&amp;nbsp;(os dois&amp;nbsp;&lt;code&gt;UPDATE&lt;/code&gt;s) — isso é extremamente comum na prática. A lógica de negócio "transferência bancária" mora em um único lugar,&amp;nbsp;versionada&amp;nbsp;e&amp;nbsp;reutilizável.&lt;/p&gt;

&lt;h1&gt;
  
  
  Parâmetros: &lt;code&gt;IN&lt;/code&gt;, &lt;code&gt;OUT&lt;/code&gt; e &lt;code&gt;INOUT&lt;/code&gt;
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;code&gt;IN&lt;/code&gt;&amp;nbsp;(padrão)&lt;/th&gt;
&lt;th&gt;Recebe um valor de fora&amp;nbsp;para&amp;nbsp;dentro&amp;nbsp;da&amp;nbsp;procedure&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Devolve um valor calculado de dentro para fora,&amp;nbsp;para&amp;nbsp;a&amp;nbsp;variável&amp;nbsp;do&amp;nbsp;chamador&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;INOUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Funciona nos dois sentidos — entra com um valor,&amp;nbsp;sai&amp;nbsp;modificado&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Lógica procedural:&amp;nbsp;variáveis,&amp;nbsp;IF,&amp;nbsp;loops&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Isso é o que diferencia uma procedure de um&amp;nbsp;&lt;code&gt;SELECT&lt;/code&gt;&amp;nbsp;comum. Ela pode ter&amp;nbsp;&lt;strong&gt;controle de fluxo&lt;/strong&gt;, como uma linguagem&amp;nbsp;de&amp;nbsp;programação&amp;nbsp;de&amp;nbsp;verdade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PROCEDURE&lt;/span&gt; &lt;span class="n"&gt;processar_pedidos_pendentes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;DECLARE&lt;/span&gt;
  &lt;span class="n"&gt;pedido&lt;/span&gt; &lt;span class="n"&gt;RECORD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;contadorINT&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;pedidoIN&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'pendente'&lt;/span&gt; &lt;span class="n"&gt;LOOP&lt;/span&gt;
    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
      &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'em_analise'&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;ELSE&lt;/span&gt;
      &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'aprovado'&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;contador&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contador&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;LOOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;RAISE&lt;/span&gt; &lt;span class="n"&gt;NOTICE&lt;/span&gt;&lt;span class="s1"&gt;'% pedidos processados'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contador&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso é impossível de fazer em um&amp;nbsp;&lt;code&gt;SELECT&lt;/code&gt;&amp;nbsp;puro. É por isso que procedures existem: para lógica que precisa de&amp;nbsp;&lt;strong&gt;passos sequenciais, decisões e&amp;nbsp;repetição&lt;/strong&gt;,&amp;nbsp;não&amp;nbsp;só&amp;nbsp;"buscar&amp;nbsp;dados".&lt;/p&gt;

&lt;h1&gt;
  
  
  Functions
&lt;/h1&gt;

&lt;p&gt;Um bloco de código salvo no banco que obrigatoriamente retorna um valor, e pode ser usado dentro de outras queries — em &lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;ORDER BY&lt;/code&gt; — exatamente como ROUND() ou UPPER() (que são, na verdade, funções nativas do banco; as suas são "customizadas").&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sintaxe&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;CalcularIdade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;data_nascimento&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;DATEDIFF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;YEAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;data_nascimento&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GETDATE&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CalcularIdade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_nascimento&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Scalar Function&amp;nbsp;vs.&amp;nbsp;Table-Valued&amp;nbsp;Function&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Tipo&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Retorna&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Exemplo&amp;nbsp;de&amp;nbsp;uso&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalar&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Um único valor (número, texto, data)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;calcular_idade()&lt;/code&gt;&amp;nbsp;acima —&amp;nbsp;um&amp;nbsp;INT&amp;nbsp;por&amp;nbsp;linha&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Table-valued&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uma tabela inteira (linhas e colunas)&lt;/td&gt;
&lt;td&gt;Uma função que retorna "todos&amp;nbsp;os&amp;nbsp;pedidos&amp;nbsp;de&amp;nbsp;um&amp;nbsp;cliente"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Table-valued function (PostgreSQL):&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;pedidos_do_cliente&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;QUERY&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_pedido&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;cliente_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Usando como se fosse uma tabela:&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pedidos_do_cliente&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso conecta diretamente com&amp;nbsp;&lt;strong&gt;view.&lt;/strong&gt;  Uma table-valued function é como uma "view com parâmetros". A view&amp;nbsp;não&amp;nbsp;aceita&amp;nbsp;argumentos;&amp;nbsp;a&amp;nbsp;function&amp;nbsp;sim.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Diferenças&amp;nbsp;cruciais:&amp;nbsp;Procedure&amp;nbsp;vs.&amp;nbsp;Function&lt;/strong&gt;
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Stored&amp;nbsp;Procedure&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Function&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retorno&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Opcional (pode não retornar nada, ou retornar via&amp;nbsp;&lt;code&gt;OUT&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Obrigatório —&amp;nbsp;sempre&amp;nbsp;retorna&amp;nbsp;um&amp;nbsp;valor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Uso em SELECT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Não pode ser usada dentro de um&amp;nbsp;&lt;code&gt;SELECT&lt;/code&gt;/&lt;code&gt;WHERE&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅ Pode ser usada&amp;nbsp;como&amp;nbsp;se&amp;nbsp;fosse&amp;nbsp;uma&amp;nbsp;coluna/expressão&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Como se chama&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CALL procedure(...)&lt;/code&gt;&amp;nbsp;/&amp;nbsp;&lt;code&gt;EXEC procedure&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Dentro de&amp;nbsp;uma&amp;nbsp;query:&amp;nbsp;&lt;code&gt;SELECT function(...)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transações&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Pode conter&amp;nbsp;&lt;code&gt;COMMIT&lt;/code&gt;/&lt;code&gt;ROLLBACK&lt;/code&gt;&amp;nbsp;dentro dela&lt;/td&gt;
&lt;td&gt;❌ Geralmente&amp;nbsp;&lt;strong&gt;não pode&lt;/strong&gt;&amp;nbsp;controlar transação (roda&amp;nbsp;dentro&amp;nbsp;da&amp;nbsp;transação&amp;nbsp;de&amp;nbsp;quem&amp;nbsp;chamou)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Parâmetros de saída&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Suporta&amp;nbsp;&lt;code&gt;OUT&lt;/code&gt;/&lt;code&gt;INOUT&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Só retorno via&amp;nbsp;&lt;code&gt;RETURN&lt;/code&gt;&amp;nbsp;(sem&amp;nbsp;&lt;code&gt;OUT&lt;/code&gt;&amp;nbsp;na&amp;nbsp;maioria&amp;nbsp;dos&amp;nbsp;bancos)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Efeitos colaterais (side effects)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Esperado — fazer&amp;nbsp;&lt;code&gt;INSERT&lt;/code&gt;/&lt;code&gt;UPDATE&lt;/code&gt;/&lt;code&gt;DELETE&lt;/code&gt;&amp;nbsp;é o uso típico&lt;/td&gt;
&lt;td&gt;Deveria ser evitado — functions idealmente são "puras" (calculam e retornam, sem alterar dados), embora tecnicamente&amp;nbsp;algumas&amp;nbsp;linguagens&amp;nbsp;permitam&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Uso típico&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatizar processos, lotes, transações complexas&lt;/td&gt;
&lt;td&gt;Cálculos reutilizáveis, regras de negócio usadas&amp;nbsp;em&amp;nbsp;queries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Regra prática para decidir qual usar:&lt;/strong&gt;&amp;nbsp;se você precisa&amp;nbsp;&lt;strong&gt;buscar/calcular e devolver um valor para usar dentro de uma query&lt;/strong&gt;, use function. Se você precisa&amp;nbsp;&lt;strong&gt;executar uma sequência de ações&lt;/strong&gt;&amp;nbsp;(múltiplos&amp;nbsp;&lt;code&gt;UPDATE&lt;/code&gt;s, lógica de transação, processamento em&amp;nbsp;lote),&amp;nbsp;use&amp;nbsp;procedure.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>performance</category>
      <category>sql</category>
    </item>
    <item>
      <title>Transactions &amp; ACID</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Wed, 22 Jul 2026 02:41:43 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/transactions-acid-36jm</link>
      <guid>https://dev.to/yuripeixinho/transactions-acid-36jm</guid>
      <description>&lt;h1&gt;
  
  
  ACID
&lt;/h1&gt;

&lt;p&gt;Toda vez que você faz uma transferência bancária, finaliza uma compra online ou reserva um assento num voo, um banco de dados está tomando decisões em frações de segundo que determinam se aquela operação aconteceu de verdade, ou não aconteceu de jeito nenhum. O mecanismo que garante isso tem nome:&amp;nbsp;&lt;strong&gt;ACID&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O conceito foi formalizado pelo cientista Jim Gray no final dos anos 1970, numa época em que bancos de dados começavam a ser usados em sistemas críticos e os engenheiros precisavam de um vocabulário preciso para falar sobre confiabilidade. Décadas depois, as quatro propriedades que ele descreveu continuam sendo o padrão pelo qual julgamos a solidez de qualquer banco de dados transacional.&lt;/p&gt;

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

&lt;p&gt;Uma transação é atômica quando ela é&amp;nbsp;&lt;strong&gt;tudo ou nada&lt;/strong&gt;. Não existe estado intermediário.&lt;/p&gt;

&lt;p&gt;Imagine uma transferência de R$500 entre duas contas. A operação envolve dois passos: debitar da conta A e creditar na conta B. Se o sistema cair exatamente entre esses dois passos, o que acontece? Sem atomicidade, o dinheiro some — saiu de A, mas nunca chegou em B. Com atomicidade, o banco de dados garante que ou os dois passos acontecem juntos, ou nenhum deles é confirmado. A transação incompleta é desfeita automaticamente.&lt;/p&gt;

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

&lt;p&gt;Consistência garante que uma transação sempre leva o banco de dados de&amp;nbsp;um estado válido para outro estado válido, respeitando todas as regras definidas no esquema — chaves estrangeiras, restrições de unicidade, campos obrigatórios.&lt;/p&gt;

&lt;p&gt;Se uma regra diz que o saldo de uma conta não pode ser negativo, nenhuma transação pode violar isso. Mesmo que a transação seja atomicamente executada, ela será rejeitada se o resultado final quebrar uma restrição. O banco de dados nunca fica num estado que contradiz suas próprias regras.&lt;/p&gt;

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

&lt;p&gt;Bancos de dados reais lidam com milhares de transações simultâneas. O isolamento define o quanto uma transação em andamento é visível para as outras.&lt;/p&gt;

&lt;p&gt;Sem isolamento, dois usuários comprando o último ingresso disponível ao mesmo tempo poderiam ambos ver o ingresso como disponível, ambos confirmar a compra, e o sistema acabar com um ingresso vendido duas vezes. Com isolamento, as transações se comportam como se estivessem sendo executadas em série, uma após a outra — mesmo que na prática estejam rodando em paralelo.&lt;/p&gt;

&lt;p&gt;Na prática, isolamento total tem um custo de desempenho alto, então os SGBDRs oferecem&amp;nbsp;&lt;strong&gt;níveis de isolamento&lt;/strong&gt;&amp;nbsp;configuráveis — do mais permissivo (&lt;em&gt;Read Uncommitted&lt;/em&gt;) ao mais restritivo (&lt;em&gt;Serializable&lt;/em&gt;) — permitindo que cada sistema escolha o equilíbrio certo entre segurança e velocidade.&lt;/p&gt;

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

&lt;p&gt;Uma vez que o banco confirma uma transação — retornando um "commit" — aquele dado&amp;nbsp;&lt;strong&gt;persiste, independente do que aconteça a seguir&lt;/strong&gt;. Queda de energia, falha de hardware, reinicialização do servidor: nada desfaz uma transação já confirmada.&lt;/p&gt;

&lt;p&gt;Isso é garantido por mecanismos como o&amp;nbsp;&lt;em&gt;write-ahead log&lt;/em&gt;&amp;nbsp;(WAL): antes de qualquer dado ser modificado no disco, a intenção da modificação é registrada num log separado. Se o sistema cair no meio do processo, o banco consegue se recuperar relendo esse log e replicando as operações que ainda não haviam sido concluídas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por o ACID que importa?
&lt;/h2&gt;

&lt;p&gt;ACID não é um detalhe de implementação, é uma promessa. Quando um banco de dados diz que é ACID-compliant, ele está dizendo que você pode confiar nele para operações onde o custo de um erro é alto.&lt;/p&gt;

&lt;p&gt;É por isso que sistemas financeiros, hospitalares e de e-commerce continuam usando SGBDRs mesmo quando a escala poderia justificar uma alternativa. E é também por isso que, quando sistemas NoSQL precisam garantir transações confiáveis, eles acabam implementando suas próprias versões dessas propriedades — como o MongoDB fez ao adicionar transações multi-documento em 2018, décadas depois de o modelo relacional já oferecê-las por padrão.&lt;/p&gt;

&lt;h1&gt;
  
  
  Transactions
&lt;/h1&gt;

&lt;p&gt;Aprender o ACID é fundamental para entender os conceitos de &lt;code&gt;BEGIN&lt;/code&gt;, &lt;code&gt;COMMIT&lt;/code&gt;, &lt;code&gt;ROLLBACK&lt;/code&gt;, &lt;code&gt;SAVEPOINT&lt;/code&gt;. Vou supor que o você realizou a leitura anterior. Cada um desses comandos acima existem para entregar as 4 garantias do ACID na prática.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Letra&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Significa&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;O&amp;nbsp;que&amp;nbsp;garante&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;A&lt;/strong&gt;tomicity&lt;/td&gt;
&lt;td&gt;Atomicidade&lt;/td&gt;
&lt;td&gt;Tudo&amp;nbsp;ou&amp;nbsp;nada&amp;nbsp;—&amp;nbsp;a&amp;nbsp;transferência&amp;nbsp;bancária&amp;nbsp;inteira&amp;nbsp;acontece,&amp;nbsp;ou&amp;nbsp;nenhuma&amp;nbsp;parte&amp;nbsp;dela&amp;nbsp;acontece&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;C&lt;/strong&gt;onsistency&lt;/td&gt;
&lt;td&gt;Consistência&lt;/td&gt;
&lt;td&gt;O&amp;nbsp;banco&amp;nbsp;nunca&amp;nbsp;fica&amp;nbsp;num&amp;nbsp;estado&amp;nbsp;que&amp;nbsp;viole&amp;nbsp;regras&amp;nbsp;(ex:&amp;nbsp;saldo&amp;nbsp;negativo&amp;nbsp;se&amp;nbsp;houver&amp;nbsp;constraint&amp;nbsp;impedindo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;I&lt;/strong&gt;solation&lt;/td&gt;
&lt;td&gt;Isolamento&lt;/td&gt;
&lt;td&gt;Transações&amp;nbsp;simultâneas&amp;nbsp;não&amp;nbsp;"veem"&amp;nbsp;os&amp;nbsp;passos&amp;nbsp;intermediários&amp;nbsp;umas&amp;nbsp;das&amp;nbsp;outras&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;D&lt;/strong&gt;urability&lt;/td&gt;
&lt;td&gt;Durabilidade&lt;/td&gt;
&lt;td&gt;Uma&amp;nbsp;vez&amp;nbsp;confirmada&amp;nbsp;(&lt;code&gt;COMMIT&lt;/code&gt;),&amp;nbsp;a&amp;nbsp;mudança&amp;nbsp;sobrevive&amp;nbsp;mesmo&amp;nbsp;a&amp;nbsp;uma&amp;nbsp;queda&amp;nbsp;de&amp;nbsp;energia&amp;nbsp;logo&amp;nbsp;em&amp;nbsp;seguid&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Antes de entrar na sintaxe, entenda o&amp;nbsp;&lt;strong&gt;porquê&lt;/strong&gt;. Imagine uma transferência bancária: tirar R$100 da conta A e colocar na conta B. Isso são&amp;nbsp;&lt;strong&gt;duas operações&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'B'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o banco de dados executar a primeira linha, e&amp;nbsp;&lt;strong&gt;exatamente nesse momento&lt;/strong&gt;&amp;nbsp;o servidor cair (falta de energia, crash, rede caiu), o dinheiro&amp;nbsp;&lt;strong&gt;desaparece&lt;/strong&gt;: saiu da conta A, mas nunca&amp;nbsp;chegou&amp;nbsp;na&amp;nbsp;conta&amp;nbsp;B.&amp;nbsp;Isso&amp;nbsp;é&amp;nbsp;inaceitável.&lt;/p&gt;

&lt;p&gt;Uma&amp;nbsp;&lt;strong&gt;transação&lt;/strong&gt;&amp;nbsp;agrupa múltiplas operações em uma&amp;nbsp;&lt;strong&gt;unidade atômica&lt;/strong&gt;: ou todas acontecem, ou nenhuma acontece.&amp;nbsp;Não&amp;nbsp;existe&amp;nbsp;meio-termo. É o mecanismo que garante que o cenário acima nunca aconteça.&lt;/p&gt;

&lt;h2&gt;
  
  
  BEGIN
&lt;/h2&gt;

&lt;p&gt;Iniciando uma transação.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Sintaxe&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- ou, dependendo do banco:&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Banco&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Sintaxe&amp;nbsp;preferida&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BEGIN;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;START TRANSACTION;&lt;/code&gt;&amp;nbsp;(&lt;code&gt;BEGIN&lt;/code&gt;&amp;nbsp;também&amp;nbsp;funciona)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL&amp;nbsp;Server&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;BEGIN TRANSACTION;&lt;/code&gt;&amp;nbsp;(ou&amp;nbsp;&lt;code&gt;BEGIN TRAN&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle&lt;/td&gt;
&lt;td&gt;Não precisa de&amp;nbsp;&lt;code&gt;BEGIN&lt;/code&gt;&amp;nbsp;explícito — toda instrução DML já inicia uma transação&amp;nbsp;implicitamente&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;O que&amp;nbsp;acontece&amp;nbsp;de&amp;nbsp;fato&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;BEGIN&lt;/code&gt;&amp;nbsp;marca o ponto a partir do qual&amp;nbsp;&lt;strong&gt;todas as mudanças ficam "provisórias"&lt;/strong&gt;&amp;nbsp;— visíveis só dentro dessa mesma conexão/sessão, até que você dê&amp;nbsp;&lt;code&gt;COMMIT&lt;/code&gt;&amp;nbsp;(confirmar) ou&amp;nbsp;&lt;code&gt;ROLLBACK&lt;/code&gt;&amp;nbsp;(desfazer).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'B'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Neste ponto, se você abrir outra conexão e consultar a tabela "contas",&lt;/span&gt;
&lt;span class="c1"&gt;-- ainda vai ver os saldos ANTIGOS (a menos que o nível de isolamento seja diferente do padrão)&lt;/span&gt;

&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- SÓ AGORA a mudança se torna permanente e visível para todo mundo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Autocommit, o modo “padrão” que você não percebe
&lt;/h3&gt;

&lt;p&gt;Por padrão, a maioria dos bancos roda em modo autocommit: cada instrução SQL individual já é sua própria transação implícita, com &lt;code&gt;COMMIT&lt;/code&gt; automático logo depois. É por isso que um &lt;code&gt;UPDATE&lt;/code&gt; isolado "simplesmente funciona" sem você nunca ter digitado &lt;code&gt;BEGIN/COMMIT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BEGIN&lt;/code&gt; explícito serve exatamente para desligar esse comportamento automático e agrupar várias instruções manualmente em uma única unidade atômica.&lt;/p&gt;

&lt;h2&gt;
  
  
  COMMIT
&lt;/h2&gt;

&lt;p&gt;Confirmar a transação&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Sintaxe&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  O que acontece de fato
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;COMMIT&lt;/code&gt;&amp;nbsp;torna&amp;nbsp;&lt;strong&gt;permanentes&lt;/strong&gt;&amp;nbsp;todas as mudanças feitas desde o&amp;nbsp;&lt;code&gt;BEGIN&lt;/code&gt;. A partir desse momento:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As mudanças ficam visíveis para&amp;nbsp;&lt;strong&gt;todas as outras conexões/usuários&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;As mudanças são&amp;nbsp;&lt;strong&gt;duráveis&lt;/strong&gt;&amp;nbsp;— sobrevivem a uma queda de energia, restart do servidor, etc. (a letra&amp;nbsp;&lt;strong&gt;D&lt;/strong&gt;&amp;nbsp;do ACID).&lt;/li&gt;
&lt;li&gt;Não há mais como desfazer via&amp;nbsp;&lt;code&gt;ROLLBACK&lt;/code&gt;&amp;nbsp;— se você errou, precisa fazer uma&amp;nbsp;&lt;strong&gt;nova transação&lt;/strong&gt;&amp;nbsp;para corrigir (ex: um novo&amp;nbsp;&lt;code&gt;UPDATE&lt;/code&gt;&amp;nbsp;revertendo o valor).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'B'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;-- agora sim, a transferência está "selada"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ponto-chave:&lt;/strong&gt;&amp;nbsp;enquanto não há&amp;nbsp;&lt;code&gt;COMMIT&lt;/code&gt;, a transação pode ser desfeita a qualquer momento. Depois do&amp;nbsp;&lt;code&gt;COMMIT&lt;/code&gt;,&amp;nbsp;é&amp;nbsp;definitivo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ROLLBACK
&lt;/h2&gt;

&lt;p&gt;O padrão mais comum no código de uma aplicação (pseudo-código):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;
&lt;span class="n"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'A'&lt;/span&gt;
  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;contas&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'B'&lt;/span&gt;
  &lt;span class="k"&gt;COMMIT&lt;/span&gt;
&lt;span class="n"&gt;CATCH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;erro&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;ROLLBACK&lt;/span&gt;   &lt;span class="c1"&gt;-- qualquer erro no meio do caminho desfaz tudo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso garante que, se a segunda instrução falhar por qualquer motivo (conexão caiu, violação de constraint, timeout), a primeira instrução&amp;nbsp;&lt;strong&gt;também é desfeita&lt;/strong&gt;&amp;nbsp;— nunca fica um saldo debitado sem o&amp;nbsp;correspondente&amp;nbsp;crédito.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rollback&amp;nbsp;automático&amp;nbsp;em&amp;nbsp;caso&amp;nbsp;de&amp;nbsp;erro&amp;nbsp;grave&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Em muitos bancos (Postgres é rigoroso nisso), se uma instrução dentro da transação falhar com erro, a transação inteira entra em estado de "abortada" e&amp;nbsp;&lt;strong&gt;qualquer comando subsequente é rejeitado&lt;/strong&gt;&amp;nbsp;até você mandar&amp;nbsp;&lt;code&gt;ROLLBACK&lt;/code&gt;&amp;nbsp;explicitamente — o banco não deixa você simplesmente ignorar o&amp;nbsp;erro&amp;nbsp;e&amp;nbsp;continuar.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;SAVEPOINT — Pontos&amp;nbsp;de&amp;nbsp;Rollback&amp;nbsp;Parcial&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ROLLBACK&lt;/code&gt;&amp;nbsp;sozinho desfaz a transação&amp;nbsp;&lt;strong&gt;inteira&lt;/strong&gt;. Mas e se você tem uma transação longa, com vários passos, e só quer desfazer&amp;nbsp;&lt;strong&gt;uma parte&lt;/strong&gt;&amp;nbsp;dela,&amp;nbsp;mantendo&amp;nbsp;o&amp;nbsp;resto?&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Sintaxe&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;depois_do_pedido&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;itens_pedido&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;produto_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- Ops, produto 99 não existe ou regra de negócio falhou&lt;/span&gt;

&lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;depois_do_pedido&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Desfaz APENAS o insert de itens_pedido&lt;/span&gt;
&lt;span class="c1"&gt;-- O insert do pedido continua "de pé", esperando dentro da transação&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;itens_pedido&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;produto_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- Tenta de novo, com dado correto&lt;/span&gt;

&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;-- confirma tudo: o pedido + o item correto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Múltiplos&amp;nbsp;savepoints&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Você pode ter vários savepoints numa mesma transação, como&amp;nbsp;"checkpoints"&amp;nbsp;em&amp;nbsp;sequência:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'passo 1'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;sp1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'passo 2'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;sp2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'passo 3'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;sp1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;-- desfaz "passo 2" E "passo 3", mantém "passo 1"&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Liberando&amp;nbsp;um&amp;nbsp;savepoint&amp;nbsp;sem&amp;nbsp;fazer&amp;nbsp;rollback&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;RELEASE&lt;/span&gt; &lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;depois_do_pedido&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso remove o savepoint (você não pode mais voltar para ele), mas&amp;nbsp;&lt;strong&gt;não desfaz&lt;/strong&gt;&amp;nbsp;nada — as mudanças continuam lá, esperando o&amp;nbsp;&lt;code&gt;COMMIT&lt;/code&gt;&amp;nbsp;final.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Uso real: processamento em lote com itens que podem&amp;nbsp;falhar&amp;nbsp;individualmente&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Processar 100 pedidos de uma importação, um por um&lt;/span&gt;
&lt;span class="c1"&gt;-- Para cada pedido:&lt;/span&gt;
&lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;antes_do_item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="p"&gt;...;&lt;/span&gt;
  &lt;span class="c1"&gt;-- se der erro de validação específico desse pedido:&lt;/span&gt;
  &lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;antes_do_item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;-- continua para o próximo pedido, sem precisar desfazer os 99 anteriores&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;-- no final, confirma todos os que passaram&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️&amp;nbsp;&lt;strong&gt;Nota de compatibilidade:&lt;/strong&gt;&amp;nbsp;MySQL (InnoDB) e PostgreSQL suportam&amp;nbsp;&lt;code&gt;SAVEPOINT&lt;/code&gt;&amp;nbsp;bem. SQL Server também suporta, mas com sintaxe ligeiramente diferente:&amp;nbsp;&lt;code&gt;SAVE TRANSACTION nome_savepoint&lt;/code&gt;&amp;nbsp;em&amp;nbsp;vez&amp;nbsp;de&amp;nbsp;&lt;code&gt;SAVEPOINT nome&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>computerscience</category>
      <category>database</category>
    </item>
    <item>
      <title>SQL: Views</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Wed, 22 Jul 2026 01:57:27 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/sql-views-27fa</link>
      <guid>https://dev.to/yuripeixinho/sql-views-27fa</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Uma&amp;nbsp;&lt;strong&gt;view&lt;/strong&gt;&amp;nbsp;é uma&amp;nbsp;&lt;strong&gt;consulta salva com nome&lt;/strong&gt;&amp;nbsp;— ela não armazena dados fisicamente (na maioria dos casos), apenas guarda a definição de um&amp;nbsp;&lt;code&gt;SELECT&lt;/code&gt;. Toda vez que você consulta a view, o banco executa a query por trás dela&amp;nbsp;e&amp;nbsp;devolve&amp;nbsp;o&amp;nbsp;resultado&amp;nbsp;como&amp;nbsp;se&amp;nbsp;fosse&amp;nbsp;uma&amp;nbsp;tabela.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;clientes_ativos&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ativo'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Depois, você consulta como se fosse uma tabela normal:&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;clientes_ativos&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'A%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pense na view como um&amp;nbsp;&lt;strong&gt;"apelido inteligente"&lt;/strong&gt;&amp;nbsp;para uma query complexa. Em vez de reescrever um JOIN de 4 tabelas toda vez, você cria a view uma vez e reutiliza&amp;nbsp;&lt;code&gt;SELECT * FROM minha_view&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Por que usar&amp;nbsp;views&amp;nbsp;(motivação&amp;nbsp;real)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Simplificação:&lt;/strong&gt;&amp;nbsp;esconder a complexidade de JOINs/subqueries repetitivos atrás de um nome simples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segurança:&lt;/strong&gt;&amp;nbsp;dar acesso a uma view que expõe só algumas colunas (ex: sem salário, sem CPF), sem dar acesso à tabela real.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Abstração/desacoplamento:&lt;/strong&gt;&amp;nbsp;se a estrutura das tabelas mudar, você ajusta só a view, e as queries que a usam continuam funcionando sem alteração.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reuso:&lt;/strong&gt;&amp;nbsp;centralizar lógica de negócio (ex: "o que conta como pedido válido") em um único lugar, em vez de repetir o mesmo&amp;nbsp;&lt;code&gt;WHERE&lt;/code&gt;&amp;nbsp;em 10 queries diferentes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legibilidade:&lt;/strong&gt;&amp;nbsp;transformar um relatório complicado em algo que qualquer pessoa entende:&amp;nbsp;&lt;code&gt;SELECT * FROM vendas_por_mes&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Criando&amp;nbsp;Views&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Sintaxe básica&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;nome_da_view&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;coluna1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coluna2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tabela&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;condicao&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exemplo&amp;nbsp;simples&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;produtos_em_estoque&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, em vez de repetir&amp;nbsp;&lt;code&gt;WHERE quantidade &amp;gt; 0&lt;/code&gt; toda vez, qualquer pessoa faz:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;produtos_em_estoque&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Exemplo com JOIN (caso mais comum no mundo real)
&lt;/h2&gt;

&lt;p&gt;Views brilham quando escondem a complexidade de múltiplas tabelas relacionadas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;pedidos_detalhados&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
  &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;pedido_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quantidade&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preco&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_pedido&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cliente_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;produto_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sem a view, toda vez que alguém quisesse ver um pedido "completo" (com nome do cliente e do produto, não só os IDs), precisaria escrever esse JOIN triplo&amp;nbsp;de&amp;nbsp;novo.&amp;nbsp;Com&amp;nbsp;a&amp;nbsp;view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pedidos_detalhados&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Maria Silva'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Modificando Views
&lt;/h1&gt;

&lt;p&gt;Existem duas abordagens,&amp;nbsp;dependendo&amp;nbsp;do&amp;nbsp;banco:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Abordagem 1:&amp;nbsp;&lt;code&gt;CREATE OR REPLACE VIEW&lt;/code&gt;&amp;nbsp;(PostgreSQL,&amp;nbsp;MySQL,&amp;nbsp;Oracle)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Substitui a&amp;nbsp;definição&amp;nbsp;inteira&amp;nbsp;da&amp;nbsp;view&amp;nbsp;de&amp;nbsp;uma&amp;nbsp;vez:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;REPLACE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;produtos_em_estoque&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;categoria&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Regra importante:&lt;/strong&gt;&amp;nbsp;&lt;code&gt;CREATE OR REPLACE&lt;/code&gt;&amp;nbsp;normalmente só permite&amp;nbsp;&lt;strong&gt;adicionar colunas no final&lt;/strong&gt;, ou mudar a lógica do&amp;nbsp;&lt;code&gt;WHERE&lt;/code&gt;/&lt;code&gt;JOIN&lt;/code&gt;&amp;nbsp;— você não pode remover uma coluna ou mudar a ordem das colunas existentes sem dar&amp;nbsp;&lt;code&gt;DROP&lt;/code&gt;&amp;nbsp;na view primeiro. Se tentar, o banco geralmente&amp;nbsp;recusa&amp;nbsp;com&amp;nbsp;um&amp;nbsp;erro.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Abordagem 2:&amp;nbsp;&lt;code&gt;ALTER VIEW&lt;/code&gt;&amp;nbsp;(SQL Server,&amp;nbsp;também&amp;nbsp;existe&amp;nbsp;em&amp;nbsp;outros)&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;produtos_em_estoque&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;categoria&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Funciona de forma equivalente ao&amp;nbsp;&lt;code&gt;CREATE OR REPLACE&lt;/code&gt;, mas é a sintaxe usada no SQL Server (que não aceita&amp;nbsp;&lt;code&gt;CREATE OR REPLACE VIEW&lt;/code&gt;&amp;nbsp;— lá,&amp;nbsp;&lt;code&gt;CREATE VIEW&lt;/code&gt;&amp;nbsp;falha se a view já&amp;nbsp;existir,&amp;nbsp;e&amp;nbsp;você&amp;nbsp;precisa&amp;nbsp;usar&amp;nbsp;&lt;code&gt;ALTER VIEW&lt;/code&gt;&amp;nbsp;para&amp;nbsp;modificar&amp;nbsp;uma&amp;nbsp;existente).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Por que "substituir" em vez de “editar campo por campo”?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Views não têm um equivalente ao&amp;nbsp;&lt;code&gt;ALTER TABLE ADD COLUMN&lt;/code&gt;&amp;nbsp;— você não "adiciona uma coluna" a uma view incrementalmente. Você&amp;nbsp;&lt;strong&gt;reescreve a query inteira&lt;/strong&gt;&amp;nbsp;com&amp;nbsp;&lt;code&gt;CREATE OR REPLACE&lt;/code&gt;/&lt;code&gt;ALTER VIEW&lt;/code&gt;. Isso é diferente de tabelas, e costuma confundir&amp;nbsp;quem&amp;nbsp;vem&amp;nbsp;de&amp;nbsp;&lt;code&gt;ALTER TABLE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que acontece com permissões&amp;nbsp;e&amp;nbsp;dependências&amp;nbsp;ao&amp;nbsp;modificar&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modificar uma view&amp;nbsp;&lt;strong&gt;preserva as permissões (GRANT)&lt;/strong&gt;&amp;nbsp;já concedidas a ela na maioria dos bancos — não precisa re-conceder acesso.&lt;/li&gt;
&lt;li&gt;Se outras views dependem da view que você está alterando (lembra do exemplo&amp;nbsp;&lt;code&gt;vendas_por_mes&lt;/code&gt;&amp;nbsp;em cima de&amp;nbsp;&lt;code&gt;pedidos_detalhados&lt;/code&gt;?), mudar a view de baixo pode&amp;nbsp;&lt;strong&gt;quebrar&lt;/strong&gt;&amp;nbsp;as views de cima se você remover uma coluna que elas usam. Vale sempre mapear as dependências antes de alterar&amp;nbsp;uma&amp;nbsp;view&amp;nbsp;"de&amp;nbsp;base".&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Funções Avançadas em SQL</title>
      <dc:creator>Yuri Peixinho</dc:creator>
      <pubDate>Wed, 22 Jul 2026 01:24:28 +0000</pubDate>
      <link>https://dev.to/yuripeixinho/funcoes-avancadas-em-sql-10d1</link>
      <guid>https://dev.to/yuripeixinho/funcoes-avancadas-em-sql-10d1</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;As funções avançadas em SQL vão além de operações básicas, como selecionar e filtrar dados. Elas permitem realizar cálculos complexos, manipular strings, trabalhar com datas e analisar dados de maneiras mais sofisticadas. Essas funções ajudam a obter insights, transformar dados e criar relatórios mais significativos a partir do seu banco de dados.&lt;/p&gt;

&lt;p&gt;Essas funções são dividas em algumas categorias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Funções Numéricas&lt;/li&gt;
&lt;li&gt;Funções de String&lt;/li&gt;
&lt;li&gt;Funções Condicionais&lt;/li&gt;
&lt;li&gt;Funções de Data&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Funções Numéricas
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;FLOOR(x)&lt;/code&gt;&amp;nbsp;— arredonda para&amp;nbsp;baixo&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Sempre "empurra" o número para o inteiro&amp;nbsp;&lt;strong&gt;menor ou igual&lt;/strong&gt;, independente do&amp;nbsp;sinal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;FLOOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 4&lt;/span&gt;
&lt;span class="n"&gt;FLOOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 4&lt;/span&gt;
&lt;span class="n"&gt;FLOOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- -5  (atenção: vai para o lado mais negativo, não trunca!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Uso real:&lt;/strong&gt;&amp;nbsp;calcular quantas "páginas cheias" cabem em uma lista, ou converter minutos em horas completas:&amp;nbsp;&lt;code&gt;FLOOR(minutos / 60)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;CEILING(x)&lt;/code&gt;&amp;nbsp;—&amp;nbsp;arredonda&amp;nbsp;para&amp;nbsp;cima&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;O oposto do FLOOR: sempre vai para&amp;nbsp;o&amp;nbsp;inteiro&amp;nbsp;&lt;strong&gt;maior&amp;nbsp;ou&amp;nbsp;igual&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;CEILING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 5&lt;/span&gt;
&lt;span class="n"&gt;CEILING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- -4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Uso real:&lt;/strong&gt;&amp;nbsp;calcular quantos caminhões/caixas você precisa. Se cada caixa cabe 10 itens e você tem 23 itens, precisa de&amp;nbsp;&lt;code&gt;CEILING(23/10.0) = 3&lt;/code&gt;&amp;nbsp;caixas (não 2, que sobraria item&amp;nbsp;de&amp;nbsp;fora).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;ROUND(x, n)&lt;/code&gt;&amp;nbsp;— arredondamento matemático&amp;nbsp;padrão&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;n&lt;/code&gt;&amp;nbsp;é o número de casas decimais, pode ser negativo para arredondar dezenas/centenas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;567&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 4.57&lt;/span&gt;
&lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;565&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 4.56 ou 4.57 (depende do motor — arredondamento bancário vs. "meio para cima")&lt;/span&gt;
&lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 1200  (arredonda para centena mais próxima)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Cuidado: o comportamento no&amp;nbsp;&lt;code&gt;.5&lt;/code&gt;&amp;nbsp;exato (round half up vs. round half even/"banker's rounding")&amp;nbsp;&lt;strong&gt;varia entre bancos&lt;/strong&gt;&amp;nbsp;— SQL Server e PostgreSQL não tratam igual. Nunca confie em&amp;nbsp;&lt;code&gt;ROUND&lt;/code&gt;&amp;nbsp;para regras fiscais sem testar no seu&amp;nbsp;banco&amp;nbsp;específico.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;ABS(x)&lt;/code&gt;&amp;nbsp;—&amp;nbsp;valor&amp;nbsp;absoluto&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Remove&amp;nbsp;o&amp;nbsp;sinal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ABS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 15&lt;/span&gt;
&lt;span class="k"&gt;ABS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Uso real:&lt;/strong&gt;&amp;nbsp;calcular diferença entre duas datas/valores sem se importar com qual é maior:&amp;nbsp;&lt;code&gt;ABS(preco_atual - preco_anterior)&lt;/code&gt;&amp;nbsp;para medir variação, independente&amp;nbsp;de&amp;nbsp;subida&amp;nbsp;ou&amp;nbsp;queda.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;MOD(a, b)&lt;/code&gt;&amp;nbsp;— resto&amp;nbsp;da&amp;nbsp;divisão&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Equivalente ao operador&amp;nbsp;&lt;code&gt;%&lt;/code&gt;&amp;nbsp;em outras linguagens. Note que&amp;nbsp;&lt;code&gt;MOD&lt;/code&gt;&amp;nbsp;é uma&amp;nbsp;&lt;strong&gt;função&lt;/strong&gt;&amp;nbsp;em Oracle/MySQL; SQL Server usa o operador&amp;nbsp;&lt;code&gt;%&lt;/code&gt;&amp;nbsp;diretamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 1&lt;/span&gt;
&lt;span class="k"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 0&lt;/span&gt;
&lt;span class="k"&gt;MOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- -1 (sinal segue o dividendo `a`, na maioria dos bancos)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usos reais:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paridade:&amp;nbsp;&lt;code&gt;MOD(id, 2) = 0&lt;/code&gt;&amp;nbsp;→ linhas pares (útil para zebra striping em relatórios).&lt;/li&gt;
&lt;li&gt;Distribuir dados em N grupos/partições:&amp;nbsp;&lt;code&gt;MOD(id, 4)&lt;/code&gt;&amp;nbsp;gera 4 grupos (0,1,2,3).&lt;/li&gt;
&lt;li&gt;Ciclos: dia da semana, rodízio de&amp;nbsp;placas,&amp;nbsp;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Funções de String
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;LENGTH(s)&lt;/code&gt;&amp;nbsp;—&amp;nbsp;tamanho&amp;nbsp;da&amp;nbsp;string&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Conta caracteres (não bytes, na maioria dos bancos com&amp;nbsp;suporte&amp;nbsp;a&amp;nbsp;Unicode).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'abc'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 3&lt;/span&gt;
&lt;span class="k"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 0&lt;/span&gt;
&lt;span class="k"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- NULL (não é 0!)&lt;/span&gt;
&lt;span class="k"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'café'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 4 caracteres (mas pode variar em bytes se for UTF-8 e você usar OCTET_LENGTH)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ SQL Server usa&amp;nbsp;&lt;code&gt;LEN()&lt;/code&gt;&amp;nbsp;em vez de&amp;nbsp;&lt;code&gt;LENGTH()&lt;/code&gt;. Cuidado com espaços em branco à direita —&amp;nbsp;&lt;code&gt;LEN()&lt;/code&gt;&amp;nbsp;no SQL Server os ignora, mas&amp;nbsp;&lt;code&gt;LENGTH()&lt;/code&gt;&amp;nbsp;no&amp;nbsp;Postgres/MySQL&amp;nbsp;não.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;CONCAT(a, b, ...)&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Antes do&amp;nbsp;&lt;code&gt;CONCAT&lt;/code&gt;&amp;nbsp;existir como função padrão, cada banco usava um operador diferente para juntar strings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Banco&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Operador/Sintaxe&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL, Oracle&lt;/td&gt;
&lt;td&gt;`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Server (antigo)&lt;/td&gt;
&lt;td&gt;{% raw %}&lt;code&gt;+&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CONCAT()&lt;/code&gt;&amp;nbsp;(não suporta&amp;nbsp;`&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O&amp;nbsp;{% raw %}&lt;code&gt;CONCAT()&lt;/code&gt;&amp;nbsp;como função é a forma&amp;nbsp;&lt;strong&gt;padrão ANSI&lt;/strong&gt;, suportada por praticamente todos os bancos modernos — por isso é a escolha mais portável.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A diferença crucial: tratamento de NULL&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Essa é a parte mais importante e mais fonte de bugs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Com operador (Postgres, Oracle, SQL Server antigo)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'Rua '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;nome_rua&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;', '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Se numero for NULL → resultado inteiro é NULL!&lt;/span&gt;

&lt;span class="c1"&gt;-- Com CONCAT (padrão ANSI, MySQL, Postgres 9+, SQL Server 2012+)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Rua '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nome_rua&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- Se numero for NULL → NULL é tratado como '' (string vazia)&lt;/span&gt;
&lt;span class="c1"&gt;-- Resultado: 'Rua das Flores, '  (não quebra a linha inteira)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Por que isso importa na prática:&lt;/strong&gt;&amp;nbsp;imagine montar um endereço completo com 5 campos concatenados. Se você usar&amp;nbsp;&lt;code&gt;||&lt;/code&gt;&amp;nbsp;e&amp;nbsp;&lt;strong&gt;um único campo&lt;/strong&gt;&amp;nbsp;(tipo complemento, que é opcional) for&amp;nbsp;&lt;code&gt;NULL&lt;/code&gt;, o endereço inteiro vira&amp;nbsp;&lt;code&gt;NULL&lt;/code&gt;&amp;nbsp;— some da tela. Com&amp;nbsp;&lt;code&gt;CONCAT()&lt;/code&gt;, só aquele pedaço fica vazio, o resto aparece normalmente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Exemplo real: monte um endereço, onde "complemento" costuma ser NULL&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logradouro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;' - '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;complemento&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bairro&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;endereco_completo&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;clientes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;SUBSTRING(s, início, tamanho)&lt;/code&gt;&amp;nbsp;— extrai&amp;nbsp;parte&amp;nbsp;da&amp;nbsp;string&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Índice&amp;nbsp;&lt;strong&gt;começa em 1&lt;/strong&gt;&amp;nbsp;(não&amp;nbsp;em&amp;nbsp;0!).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'12345678900'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- '123'&lt;/span&gt;
&lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'12345678900'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- '456'&lt;/span&gt;
&lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'abcdef'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 'cdef' (sem tamanho, pega até o fim — funciona no Postgres, não em todos)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usos reais:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extrair parte de um documento: DDD do telefone, os 3 primeiros dígitos do CPF.&lt;/li&gt;
&lt;li&gt;Mascarar dados sensíveis: mostrar só os últimos 4 dígitos de&amp;nbsp;um&amp;nbsp;cartão.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'****'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cartao&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cartao&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;REPLACE(s, de, para)&lt;/code&gt;&amp;nbsp;— substitui todas&amp;nbsp;as&amp;nbsp;ocorrências&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Substitui&amp;nbsp;&lt;strong&gt;todas&lt;/strong&gt;&amp;nbsp;as ocorrências de&amp;nbsp;&lt;code&gt;de&lt;/code&gt;&amp;nbsp;por&amp;nbsp;&lt;code&gt;para&lt;/code&gt;&amp;nbsp;(não é case-sensitive de forma consistente — depende do collation&amp;nbsp;do&amp;nbsp;banco).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- '2026/07/21'&lt;/span&gt;
&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'aaa'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'bb'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 'bbbbbb'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Uso real:&lt;/strong&gt;&amp;nbsp;limpar formatação antes de salvar (remover pontos/traços de CPF/CNPJ), normalizar separadores decimais (&lt;code&gt;,&lt;/code&gt;&amp;nbsp;→&amp;nbsp;&lt;code&gt;.&lt;/code&gt;) vindos&amp;nbsp;de&amp;nbsp;importação&amp;nbsp;de&amp;nbsp;planilha.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;UPPER(s)&lt;/code&gt;&amp;nbsp;/&amp;nbsp;&lt;code&gt;LOWER(s)&lt;/code&gt;&amp;nbsp;—&amp;nbsp;maiúsculas/minúsculas&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPPER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sql'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 'SQL'&lt;/span&gt;
&lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SQL'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 'sql'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Uso real mais importante:&lt;/strong&gt;&amp;nbsp;comparações&amp;nbsp;&lt;strong&gt;case-insensitive&lt;/strong&gt;&amp;nbsp;sem depender do collation&amp;nbsp;da&amp;nbsp;coluna:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Usuario@Email.com'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso é comum quando o banco tem collation case-sensitive e você quer garantir que "&lt;a href="mailto:Joao@x.com"&gt;Joao@x.com&lt;/a&gt;" e "&lt;a href="mailto:JOAO@X.COM"&gt;JOAO@X.COM&lt;/a&gt;" sejam&amp;nbsp;tratados&amp;nbsp;como&amp;nbsp;iguais.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Funções&amp;nbsp;Condicionais&lt;/strong&gt;
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;CASE&lt;/code&gt;&amp;nbsp;— estrutura&amp;nbsp;condicional&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Duas&amp;nbsp;sintaxes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CASE simples&lt;/strong&gt;&amp;nbsp;(compara uma expressão contra&amp;nbsp;valores):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
  &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'A'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Ativo'&lt;/span&gt;
  &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'I'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Inativo'&lt;/span&gt;
  &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'Desconhecido'&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CASE com busca (searched CASE)&lt;/strong&gt;&amp;nbsp;— mais flexível, permite condições&amp;nbsp;complexas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CASE&lt;/span&gt;
  &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Menor'&lt;/span&gt;
  &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Adulto'&lt;/span&gt;
  &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Idoso'&lt;/span&gt;
  &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'Não informado'&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Regras importantes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avalia condições&amp;nbsp;&lt;strong&gt;em ordem&lt;/strong&gt;&amp;nbsp;e para na primeira verdadeira — a ordem importa.&lt;/li&gt;
&lt;li&gt;Se&amp;nbsp;&lt;code&gt;ELSE&lt;/code&gt;&amp;nbsp;for omitido e nada bater, retorna&amp;nbsp;&lt;code&gt;NULL&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pode ser usado em&amp;nbsp;&lt;code&gt;SELECT&lt;/code&gt;,&amp;nbsp;&lt;code&gt;WHERE&lt;/code&gt;,&amp;nbsp;&lt;code&gt;ORDER BY&lt;/code&gt;&amp;nbsp;e até dentro de&amp;nbsp;&lt;code&gt;SUM()&lt;/code&gt;/&lt;code&gt;COUNT()&lt;/code&gt;&amp;nbsp;para agregações condicionais:&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;code&gt;NULLIF(a, b)&lt;/code&gt;&amp;nbsp;— retorna&amp;nbsp;NULL&amp;nbsp;se&amp;nbsp;forem&amp;nbsp;iguais&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;-- NULL&lt;/span&gt;
&lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;-- 5 (retorna 'a' quando são diferentes)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É literalmente um atalho para &lt;code&gt;CASE WHEN a = b THEN NULL ELSE a END&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ou seja:&amp;nbsp;&lt;strong&gt;compara&amp;nbsp;&lt;code&gt;a&lt;/code&gt;&amp;nbsp;com&amp;nbsp;&lt;code&gt;b&lt;/code&gt;&lt;/strong&gt;. Se forem iguais, retorna&amp;nbsp;&lt;code&gt;NULL&lt;/code&gt;. Se forem diferentes, retorna&amp;nbsp;&lt;code&gt;a&lt;/code&gt;&amp;nbsp;(nunca&amp;nbsp;&lt;code&gt;b&lt;/code&gt;&amp;nbsp;— isso é importante, a função não é simétrica no retorno, mesmo que a comparação seja).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- NULL&lt;/span&gt;
&lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 10  (retorna 'a', não importa o valor de 'b')&lt;/span&gt;
&lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;COALESCE(a, b, c, ...)&lt;/code&gt;&amp;nbsp;—&amp;nbsp;primeiro&amp;nbsp;valor&amp;nbsp;não-nulo&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Percorre a lista da esquerda para a direita e retorna o&amp;nbsp;&lt;strong&gt;primeiro&lt;/strong&gt;&amp;nbsp;argumento&amp;nbsp;que&amp;nbsp;não&amp;nbsp;é&amp;nbsp;&lt;code&gt;NULL&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'terceiro'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'quarto'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 'terceiro'&lt;/span&gt;
&lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;telefone_celular&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;telefone_fixo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'sem contato'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;strong&gt;Funções&amp;nbsp;de&amp;nbsp;Data&amp;nbsp;e&amp;nbsp;Hora&lt;/strong&gt;
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;DATE&lt;/code&gt;,&amp;nbsp;&lt;code&gt;TIME&lt;/code&gt;,&amp;nbsp;&lt;code&gt;TIMESTAMP&lt;/code&gt;&amp;nbsp;—&amp;nbsp;tipos&amp;nbsp;e&amp;nbsp;extração&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Não são bem "funções" isoladas — são&amp;nbsp;&lt;strong&gt;tipos de dado&lt;/strong&gt;&amp;nbsp;(&lt;code&gt;DATE&lt;/code&gt;&amp;nbsp;= só data,&amp;nbsp;&lt;code&gt;TIME&lt;/code&gt;&amp;nbsp;= só hora,&amp;nbsp;&lt;code&gt;TIMESTAMP&lt;/code&gt;/&lt;code&gt;DATETIME&lt;/code&gt;&amp;nbsp;= ambos), mas também aparecem como funções&amp;nbsp;de&amp;nbsp;conversão/cast:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coluna_timestampAS&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- extrai só a data, descarta a hora&lt;/span&gt;
&lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coluna_timestampAS&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- extrai só a hora&lt;/span&gt;
&lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class="c1"&gt;-- data+hora atual (padrão ANSI)&lt;/span&gt;
&lt;span class="k"&gt;CURRENT_DATE&lt;/span&gt;&lt;span class="c1"&gt;-- só a data atual&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Uso real:&lt;/strong&gt;&amp;nbsp;você tem uma coluna&amp;nbsp;&lt;code&gt;created_at TIMESTAMP&lt;/code&gt;&amp;nbsp;e quer agrupar&amp;nbsp;por&amp;nbsp;dia,&amp;nbsp;ignorando&amp;nbsp;a&amp;nbsp;hora:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;dia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sem esse cast, cada&amp;nbsp;&lt;code&gt;created_at&lt;/code&gt;&amp;nbsp;com hora diferente formaria&amp;nbsp;um&amp;nbsp;grupo&amp;nbsp;distinto.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;DATEPART(parte, data)&lt;/code&gt;&amp;nbsp;—&amp;nbsp;extrai&amp;nbsp;um&amp;nbsp;componente&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Sintaxe do&amp;nbsp;&lt;strong&gt;SQL Server&lt;/strong&gt;. Extrai um pedaço específico da data&amp;nbsp;como&amp;nbsp;número.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;YEAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 2026&lt;/span&gt;
&lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MONTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 7&lt;/span&gt;
&lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;DAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 21&lt;/span&gt;
&lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WEEKDAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- dia da semana (numérico)&lt;/span&gt;
&lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QUARTER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 3 (terceiro trimestre)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Equivalentes em outros bancos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL:&lt;/strong&gt;&amp;nbsp;&lt;code&gt;EXTRACT(YEAR FROM data)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MySQL:&lt;/strong&gt;&amp;nbsp;&lt;code&gt;YEAR(data)&lt;/code&gt;,&amp;nbsp;&lt;code&gt;MONTH(data)&lt;/code&gt;,&amp;nbsp;&lt;code&gt;DAY(data)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Uso real:&lt;/strong&gt;&amp;nbsp;relatórios agrupados por período — vendas por mês, por trimestre,&amp;nbsp;por&amp;nbsp;ano:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;YEAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_pedido&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;ano&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MONTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_pedido&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;YEAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_pedido&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;DATEPART&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MONTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_pedido&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;DATEADD(parte, n, data)&lt;/code&gt;&amp;nbsp;—&amp;nbsp;soma/subtrai&amp;nbsp;intervalo&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;DAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 2026-08-20&lt;/span&gt;
&lt;span class="n"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MONTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 2026-06-21&lt;/span&gt;
&lt;span class="n"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;YEAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'2026-07-21'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="c1"&gt;-- 2027-07-21&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;n&lt;/code&gt;&amp;nbsp;negativo subtrai. Equivalentes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL:&lt;/strong&gt;&amp;nbsp;&lt;code&gt;data + INTERVAL '30 days'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MySQL:&lt;/strong&gt;&amp;nbsp;&lt;code&gt;DATE_ADD(data, INTERVAL 30 DAY)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Usos reais:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data de vencimento:&amp;nbsp;&lt;code&gt;DATEADD(DAY, 30, data_pedido)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Janela de tempo relativa a hoje:&amp;nbsp;&lt;code&gt;WHERE data_pedido &amp;gt;= DATEADD(DAY, -7, GETDATE())&lt;/code&gt;&amp;nbsp;→ últimos 7 dias.&lt;/li&gt;
&lt;li&gt;Calcular idade:&amp;nbsp;&lt;code&gt;DATEDIFF(YEAR, data_nascimento, GETDATE())&lt;/code&gt;&amp;nbsp;(função irmã&amp;nbsp;do&amp;nbsp;&lt;code&gt;DATEADD&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>programming</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
