<?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: Diego de Sousa Brandão</title>
    <description>The latest articles on DEV Community by Diego de Sousa Brandão (@diegobrandao).</description>
    <link>https://dev.to/diegobrandao</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%2F877145%2F70792ea6-0aa3-48b9-9ca2-e59d9d20a0b4.jpg</url>
      <title>DEV Community: Diego de Sousa Brandão</title>
      <link>https://dev.to/diegobrandao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/diegobrandao"/>
    <language>en</language>
    <item>
      <title>Custo de tokens em LLMs: onde pesa e como evitar desperdício</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Mon, 21 Sep 2026 16:02:55 +0000</pubDate>
      <link>https://dev.to/diegobrandao/custo-de-tokens-em-llms-onde-pesa-e-como-evitar-desperdicio-530c</link>
      <guid>https://dev.to/diegobrandao/custo-de-tokens-em-llms-onde-pesa-e-como-evitar-desperdicio-530c</guid>
      <description>&lt;h2&gt;
  
  
  Resumo executivo
&lt;/h2&gt;

&lt;p&gt;Em agentes de código o input domina o volume e o custo; em respostas pontuais e com raciocínio o output pesa mais por token. O desperdício evitável vem de contexto acumulado, modelo e esforço acima do necessário, cache quebrado e modos caros ligados sem necessidade, não da indentação.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Preço por token.&lt;/strong&gt; O output custa 5x a 6x o input em todos os modelos de topo: Claude Opus 5 US$5/25, GPT-5.6 Sol US$4/20 (promoção), Gemini 3.1 Pro US$2/12, e US$10/50 no Fable 5.1 e no GPT-6 Astra.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volume em agentes.&lt;/strong&gt; Agentes gastam ~1.000x mais tokens que chat, com o input puxando o custo (&lt;a href="https://arxiv.org/abs/2604.22750" rel="noopener noreferrer"&gt;arXiv 2604.22750&lt;/a&gt;). Num trace de PR da Sonar, 98% dos ~156 milhões de tokens foram leituras de cache e o output foi 0,19%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raciocínio.&lt;/strong&gt; Thinking tokens são cobrados como output, vêm ligados por padrão e podem chegar a dezenas de milhares por requisição. O esforço é a maior alavanca.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokenizer.&lt;/strong&gt; O do Claude a partir do 4.7 gera ~30% mais tokens que o anterior (Anthropic) e 1,4x a 1,7x mais que o do GPT em texto e código (Playcode). Compare custo por tarefa, não preço por token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache e modos.&lt;/strong&gt; A leitura de cache custa 10% do input (2,5% no Fable 5.1) e reescrever custa 12,5x mais (50x no Fable 5.1). Fast e Priority custam 1,8x a 2x, e o Batch corta 50%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Erros de uso mais bem documentados.&lt;/strong&gt; Sessão longa sem limpar, modelo caro como padrão, esforço alto sem necessidade, cache invalidado, leituras largas e agentes paralelos esquecidos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arquivos de contexto.&lt;/strong&gt; CLAUDE.md, AGENTS.md e GEMINI.md entram em toda sessão e os agentes seguem o que eles dizem. No estudo da ETH Zurich, arquivos gerados por LLM elevaram o custo por tarefa em 20% a 23% sem ganho significativo de acerto. O custo vem do comportamento induzido, não do tamanho do texto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estratégias com ganho medido.&lt;/strong&gt; Mascarar observações antigas (~50% menos custo, JetBrains), estabilizar o prefixo do cache (acerto de 7% para 84% e 59% a 70% de economia num agente em produção), carregar ferramentas sob demanda (de ~77 mil para ~8,7 mil tokens, Anthropic) e cortar instruções de teste de arquivos gerados (−16% a −21% de custo). Os números vêm de contextos diferentes e não se somam.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formatação.&lt;/strong&gt; Indentação, espaços e quebras de linha custam 13% a 15% dos tokens de arquivos reais de Java, C# e C++ e 4% dos de Python; a indentação sozinha vale ~8% a 10% nos exercícios de completar código. O modelo tende a repetir a formatação na saída. É real, mas secundário.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Recomendação:&lt;/strong&gt; limpar contexto a cada tarefa, escolher modelo e esforço por tarefa, estabilizar o prefixo para cache, reduzir leituras e definições de ferramentas, impor tetos de gasto e medir custo por tarefa com o campo &lt;code&gt;usage&lt;/code&gt; de cada resposta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Escopo e qualidade das fontes
&lt;/h2&gt;

&lt;p&gt;O estudo responde quatro perguntas: onde o custo de tokens se concentra (input ou output), quais erros de uso mais o geram, como evitá-los e quais estratégias de redução têm ganho medido em fonte primária ou caso de produção. Cobre Claude (Fable 5.1, Opus 5, Sonnet 5, Haiku 4.5), OpenAI (GPT-6 Astra e GPT-5.6 Sol, Terra e Luna) e Google (Gemini 3.1 Pro e 3.8 Flash), além dos arquivos de contexto do Claude Code, do Codex, do Gemini CLI, do Kimi Code CLI e do GLM. Data-base: 20/09/2026.&lt;/p&gt;

&lt;p&gt;Método: cada número vem de página aberta em 20/09/2026, com prioridade para documentação oficial e papers. Onde a fonte é de um fornecedor que vende a solução ou de terceiros, isso está marcado. Cálculos próprios estão marcados como tais.&lt;/p&gt;

&lt;p&gt;Cada fonte recebe uma nota de força:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A:&lt;/strong&gt; paper, documentação ou página oficial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B:&lt;/strong&gt; medição de terceiro ou de fornecedor, com método descrito.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C:&lt;/strong&gt; análise secundária.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Onde o custo se concentra: input em agentes, output em geração e raciocínio
&lt;/h2&gt;

&lt;p&gt;O ponto de maior custo depende do padrão de uso.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Padrão de uso&lt;/th&gt;
&lt;th&gt;Onde o custo pesa&lt;/th&gt;
&lt;th&gt;Evidência&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chat e geração pontual&lt;/td&gt;
&lt;td&gt;Output, 5x a 6x mais caro por token&lt;/td&gt;
&lt;td&gt;Tabela de preços abaixo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agente de código&lt;/td&gt;
&lt;td&gt;Input, por releitura do contexto a cada passo&lt;/td&gt;
&lt;td&gt;arXiv 2604.22750; trace de um PR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modelo de raciocínio&lt;/td&gt;
&lt;td&gt;Output invisível (thinking tokens)&lt;/td&gt;
&lt;td&gt;Documentação da OpenAI e da Anthropic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Uso real em escala.&lt;/strong&gt; O relatório OpenRouter/a16z (&lt;a href="https://openrouter.ai/state-of-ai" rel="noopener noreferrer"&gt;State of AI&lt;/a&gt;, 100 trilhões de tokens até nov/2025) mostra o prompt médio subindo de ~1,5 mil para mais de 6 mil tokens e a resposta de ~150 para ~400, uma razão de ~15 para 1 (cálculo nosso). Prompts de programação são 3 a 4x mais longos que os gerais e passam de 20 mil tokens de input, e mais de 50% dos tokens já passam por modelos de raciocínio. Com output 5x mais caro, o input ainda responde por ~75% do custo a preço cheio e sem cache (cálculo ilustrativo nosso). O dado vem de uma só plataforma e usa proxies para uso agêntico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agentes.&lt;/strong&gt; Bai et al. (&lt;a href="https://arxiv.org/abs/2604.22750" rel="noopener noreferrer"&gt;arXiv 2604.22750&lt;/a&gt;, abr/2026) analisaram trajetórias de 8 modelos de 2025 no SWE-bench Verified, com o agente OpenHands. Em média, uma tarefa agêntica usou 4,17 milhões de tokens (US$1,86), contra 1,19 mil (US$0,016) em raciocínio de código e 3,39 mil (US$0,023) em chat de código: de 1.200x a 3.500x mais tokens. A razão input/output é de ~154 para 1 em agentes, contra 0,16 e 1,33 nos outros dois, e o input puxa o custo mesmo com cache. Num estudo de caso com o Sonnet 4.5, a leitura de cache dominou volume e custo em todas as fases, embora o output custe muito mais por token.&lt;/p&gt;

&lt;p&gt;A mesma tarefa varia: a run mais cara custa em média ~2x a mais barata, com extremos de até 30x. Mais tokens não garantem mais acerto (a acurácia sobe pouco e satura), e os modelos preveem o próprio gasto com correlação de no máximo 0,39, subestimando-o. Um loop ingênuo relê o histórico a cada passo: 20 passos de 1.000 tokens somam 210.000 tokens de input, não 20.000 (cálculo nosso).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caso: um PR de 800 linhas (Sonar, 1/09/2026).&lt;/strong&gt; O &lt;a href="https://www.sonarsource.com/blog/stop-the-context-tax/" rel="noopener noreferrer"&gt;post da Sonar&lt;/a&gt; mede 512 idas e voltas, janela com pico de 458.700 tokens e ~156 milhões de tokens faturados por ~US$41: 152,8 milhões de leitura de cache, 3,1 milhões de escrita, 106 mil de input novo e 289 mil de output. Um arquivo de 618 linhas (6.472 tokens), lido para usar uma função de ~67 linhas, ficou no contexto por ~470 turnos: ~2,7 milhões de tokens relidos, cerca de US$0,54 à tarifa de cache citada (~US$0,20 por milhão). Em 18 PRs comparáveis, a média foi de ~234 milhões de tokens de contexto, ~700 idas e voltas e ~US$65 por PR (mediana ~US$52). Com essa tarifa, as 152,8 milhões de leituras custam ~US$30,6, cerca de 75% do total (cálculo nosso). Ressalvas: o post não nomeia o modelo nem o agente, mede um repositório e a Sonar vende a solução (&lt;a href="https://www.beri.net/article/coding-agent-cache-read-context-tax-tokens-per-pr-turn-budget" rel="noopener noreferrer"&gt;análise crítica&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentação oficial: o custo cresce com a sessão.&lt;/strong&gt; O Claude Code envia a conversa inteira a cada requisição, e cada uso de ferramenta gera outra requisição. Com cache, o histórico é relido à tarifa de cache, então uma pergunta de uma linha numa sessão aberta o dia todo consome o histórico inteiro. A primeira mensagem após uma pausa maior que o TTL reprocessa o contexto inteiro, e &lt;code&gt;/compact&lt;/code&gt; é ele próprio uma requisição grande (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;docs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Leitura: com agentes, otimizar input (contexto, cache, leituras) rende mais que otimizar output. Em geração direta e modelos de raciocínio, ocorre o inverso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidência por modelo: o preço por token é parecido, o custo por tarefa não
&lt;/h2&gt;

&lt;p&gt;Os modelos de topo custam de US$4 a US$10 por milhão de tokens de input, e o output custa 5x a 6x mais em todos; tokenizer, raciocínio e cache é que fazem o custo por tarefa divergir. A tabela traz US$ por milhão de tokens, contexto curto, tarifa padrão, lida nas páginas oficiais em 20/09/2026.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Modelo&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Output/Input&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Claude Fable 5.1&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;GPT-6 Astra&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Claude Opus 5&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developers.openai.com/api/docs/models/gpt-5.6-sol" rel="noopener noreferrer"&gt;GPT-5.6 Sol&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;4 (promo)&lt;/td&gt;
&lt;td&gt;20 (promo)&lt;/td&gt;
&lt;td&gt;5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Claude Sonnet 5&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;GPT-5.6 Terra&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;6x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/pricing" rel="noopener noreferrer"&gt;Gemini 3.1 Pro Preview&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;6x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Claude Haiku 4.5&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/pricing" rel="noopener noreferrer"&gt;Gemini 3.8 Flash&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0,75 (promo)&lt;/td&gt;
&lt;td&gt;3,75 (promo)&lt;/td&gt;
&lt;td&gt;5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;GPT-5.6 Luna&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0,20&lt;/td&gt;
&lt;td&gt;1,20&lt;/td&gt;
&lt;td&gt;6x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O GPT-5.6 Sol está em promoção: a OpenAI garante US$4/20 pelo menos até 21/11/2026, e o preço anterior era US$5/30 (&lt;a href="https://developers.openai.com/api/docs/models/gpt-5.6-sol" rel="noopener noreferrer"&gt;página oficial&lt;/a&gt;). Na Anthropic, o Sonnet 5 a US$2/10 é agora o preço padrão, e o aumento previsto para US$3/15 em 1/09/2026 não vai ocorrer. DeepSeek V4, Grok e Mistral ficaram fora da tabela porque não foram verificados em página oficial nesta revisão.&lt;/p&gt;

&lt;p&gt;Fontes: páginas de preços da &lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Anthropic&lt;/a&gt;, da &lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt; e do &lt;a href="https://ai.google.dev/gemini-api/docs/pricing" rel="noopener noreferrer"&gt;Google&lt;/a&gt;. O Gemini 3.8 Flash custa US$0,75/3,75 até 31/12/2026 e US$1,50/7,50 depois. GPT-6 Astra (OpenAI) e Claude Fable 5.1 (Anthropic) custam ambos US$10/50.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache, contexto longo e modos especiais: regras oficiais por fornecedor
&lt;/h3&gt;

&lt;p&gt;Anthropic, OpenAI e Google cobram a leitura de cache a 10% do input (2,5% no Fable 5.1). A escrita, o prazo, o contexto longo e o que invalida o cache variam.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fornecedor&lt;/th&gt;
&lt;th&gt;Leitura de cache&lt;/th&gt;
&lt;th&gt;Escrita ou armazenamento&lt;/th&gt;
&lt;th&gt;Contexto longo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;Anthropic&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0,1x o input (0,025x no Fable 5.1)&lt;/td&gt;
&lt;td&gt;Escrita 1,25x (5 min) ou 2x (1 h)&lt;/td&gt;
&lt;td&gt;Janela de 1 milhão a preço padrão, sem sobretaxa (&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;preços&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0,1x (Sol US$0,40; Astra US$1,00)&lt;/td&gt;
&lt;td&gt;Escrita 1,25x (Sol US$5,00)&lt;/td&gt;
&lt;td&gt;Acima de 272 mil tokens: 2x no input e 1,5x no output da requisição inteira (Sol)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/pricing" rel="noopener noreferrer"&gt;Google&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;0,1x (3.1 Pro US$0,20; 3.8 Flash US$0,075)&lt;/td&gt;
&lt;td&gt;Armazenamento por hora: US$4,50 por milhão (3.1 Pro), US$0,50 (3.8 Flash até 31/12/2026)&lt;/td&gt;
&lt;td&gt;Acima de 200 mil tokens: US$4/18 no 3.1 Pro&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lote e prioridade.&lt;/strong&gt; O Batch corta 50% do input e do output nos três fornecedores (Sol a US$2/10 no Batch). Os modos rápidos custam mais: fast mode do Opus 5 e do Opus 4.8 a US$10/50 (2x, indisponível no Batch), Fast mode da OpenAI 2x (Sol a US$8/40) e Priority do Gemini 3.1 Pro 1,8x (US$3,60/21,60).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prazo.&lt;/strong&gt; O TTL padrão é de 5 minutos, renova a cada uso e conta desde o início da requisição, inclusive o tempo de geração. No Claude Code o cache dura 1 h em assinatura e 5 min em API key ou com créditos de uso (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;docs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O que invalida (Anthropic).&lt;/strong&gt; O acerto exige prompt 100% idêntico até o breakpoint. Mudar definições de ferramentas invalida tudo. Ligar ou desligar web search ou citações e trocar o modo rápido invalidam sistema e mensagens. Mudar &lt;code&gt;tool_choice&lt;/code&gt;, imagens, parâmetros de thinking ou &lt;code&gt;output_config.effort&lt;/code&gt; invalida as mensagens. Em modelos com esforço por mensagem, mudar o esforço numa mensagem &lt;code&gt;system&lt;/code&gt; preserva o prefixo (&lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;docs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Erro clássico.&lt;/strong&gt; Breakpoint num bloco que muda a cada requisição, como um timestamp: o cache é escrito toda vez e nunca lido. O ponto certo é o último bloco estável.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mínimo.&lt;/strong&gt; Abaixo de 512 tokens (Opus 5, Fable 5.1), 1.024 (Sonnet 5) ou 4.096 (Haiku 4.5) o prompt não entra em cache, sem erro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custo do erro.&lt;/strong&gt; Reescrever o cache custa 12,5x mais que lê-lo (1,25x contra 0,1x) e 50x no Fable 5.1 (1,25x contra 0,025x); cálculo a partir das tarifas oficiais.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Residência de dados.&lt;/strong&gt; &lt;code&gt;inference_geo: "us"&lt;/code&gt; multiplica todos os tipos de token por 1,1x nos Claude 4.6 e posteriores; a OpenAI cobra +10% em endpoints regionais.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tokenizer: o mesmo código vira 1,5x a 1,7x mais tokens no Claude atual que no GPT
&lt;/h3&gt;

&lt;p&gt;A Anthropic informa que os modelos a partir do Claude 4.7 geram cerca de 30% mais tokens para o mesmo texto que o tokenizer anterior (&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;preços&lt;/a&gt;). A &lt;a href="https://playcode.io/blog/real-price-of-frontier-models" rel="noopener noreferrer"&gt;Playcode&lt;/a&gt; comparou fornecedores com o &lt;code&gt;count_tokens&lt;/code&gt; da Anthropic e conferiu contra requisições pagas. A tabela usa o o200k do GPT como 1,00x.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Conteúdo&lt;/th&gt;
&lt;th&gt;Claude (novo)&lt;/th&gt;
&lt;th&gt;Claude (antigo)&lt;/th&gt;
&lt;th&gt;Gemini 3.x Flash&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript (2.888 caracteres)&lt;/td&gt;
&lt;td&gt;1,73x&lt;/td&gt;
&lt;td&gt;1,32x&lt;/td&gt;
&lt;td&gt;1,16x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;1,58x&lt;/td&gt;
&lt;td&gt;1,22x&lt;/td&gt;
&lt;td&gt;1,19x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;1,52x&lt;/td&gt;
&lt;td&gt;1,26x&lt;/td&gt;
&lt;td&gt;1,23x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;1,50x&lt;/td&gt;
&lt;td&gt;1,22x&lt;/td&gt;
&lt;td&gt;1,20x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prosa em inglês&lt;/td&gt;
&lt;td&gt;1,40x&lt;/td&gt;
&lt;td&gt;1,05x&lt;/td&gt;
&lt;td&gt;1,01x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prosa em chinês&lt;/td&gt;
&lt;td&gt;1,44x&lt;/td&gt;
&lt;td&gt;1,45x&lt;/td&gt;
&lt;td&gt;0,85x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quem usa qual.&lt;/strong&gt; Sonnet 5, Opus 4.8, Opus 5, Fable 5 e Fable 5.1 usam o tokenizer novo; Sonnet 4.6 e Opus 4.6 usam o antigo. O Fable 5.1 conta o input igual ao Fable 5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preço efetivo.&lt;/strong&gt; Com a divergência média de 1,50x em pedidos típicos de código, a Playcode calcula que os US$5/25 do Opus 5 se comportam como US$7,50/37,50 na base do GPT, e os US$10/50 do Fable 5.1 como US$15/75. É estimativa de terceiro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache também.&lt;/strong&gt; Leituras e escritas de cache cobram por token, então a inflação as encarece na mesma proporção.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output varia mais que input.&lt;/strong&gt; Numa tarefa única (o mesmo SVG, esforço máximo, thinking incluído), os tokens de output foram: Sonnet 5 121.713; Fable 5.1 99.072; Opus 5 74.061; GPT-6 Astra 45.836; Fable 5 42.560; GPT-5.6 Terra 29.834; Gemini 3.7 Flash 13.863. É um prompt só: serve de indício, não de regra.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentes (modelos de 2025).&lt;/strong&gt; No estudo de Bai et al., Claude Sonnet 4.5 e Kimi K2 consumiram em média mais de 1,5 milhão de tokens a mais que o GPT-5 nas mesmas tarefas (&lt;a href="https://arxiv.org/abs/2604.22750" rel="noopener noreferrer"&gt;arXiv 2604.22750&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare por custo por tarefa, não por preço por token: rode o mesmo trabalho em cada modelo e leia o campo &lt;code&gt;usage&lt;/code&gt; das respostas. O estudo de formatação da seção seguinte usou tokenizers de 2024–25 (GPT-4o, Claude 3.7, Gemini 1.5); não encontramos medição do efeito no tokenizer novo do Claude.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reasoning tokens: cobrados como output, ligados por padrão e quase invisíveis
&lt;/h3&gt;

&lt;p&gt;OpenAI e Anthropic documentam que tokens de raciocínio saem à tarifa de output, e a página de preços do Google rotula o output do Gemini como incluindo os tokens de thinking.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI.&lt;/strong&gt; Os tokens de raciocínio não aparecem na API, ocupam a janela de contexto e são cobrados como output. Podem ir de algumas centenas a dezenas de milhares por resposta, e a OpenAI recomenda reservar ao menos 25.000 tokens para raciocínio e saída (&lt;a href="https://developers.openai.com/api/docs/guides/reasoning" rel="noopener noreferrer"&gt;guia&lt;/a&gt;). Se &lt;code&gt;max_output_tokens&lt;/code&gt; se esgota durante o raciocínio, você paga input e raciocínio sem receber resposta visível.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anthropic.&lt;/strong&gt; No Claude Code o extended thinking vem ligado por padrão, é cobrado como output e seu orçamento padrão pode chegar a dezenas de milhares de tokens por requisição. Nos modelos Fable não dá para desligá-lo. &lt;code&gt;MAX_THINKING_TOKENS&lt;/code&gt; só vale em modelos de orçamento fixo; os de raciocínio adaptativo ignoram orçamentos não nulos, então o controle é o esforço (&lt;code&gt;/effort&lt;/code&gt;) (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;docs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Padrões e modos (OpenAI).&lt;/strong&gt; O GPT-5.6 usa esforço &lt;code&gt;medium&lt;/code&gt; por padrão. O modo &lt;code&gt;pro&lt;/code&gt; agrega mais trabalho do modelo e cobra pelas tarifas normais, então gasta mais tokens. O GPT-6 Astra não aceita &lt;code&gt;none&lt;/code&gt;. O GPT-5.6 também renderiza por padrão o raciocínio de turnos anteriores (&lt;code&gt;all_turns&lt;/code&gt;); &lt;code&gt;current_turn&lt;/code&gt; reduz o contexto renderizado em fluxos longos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trocar o esforço e o cache.&lt;/strong&gt; Na Anthropic, mudar o esforço invalida o cache de mensagens, salvo em modelos com esforço por mensagem. Na OpenAI, o item &lt;code&gt;configuration_update&lt;/code&gt; (só no GPT-6 Astra) muda o esforço preservando o prefixo do prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordem de grandeza.&lt;/strong&gt; 4.000 tokens de thinking mais uma resposta de 500 somam 9x os tokens de output da resposta sozinha (cálculo nosso).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mais raciocínio não é mais acerto.&lt;/strong&gt; No estudo de agentes, a acurácia costuma atingir o pico em custo intermediário e satura depois (&lt;a href="https://arxiv.org/abs/2604.22750" rel="noopener noreferrer"&gt;arXiv 2604.22750&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Formatação custa de 4% a 15% dos tokens em arquivos reais e ~25% em trechos de exercício
&lt;/h2&gt;

&lt;p&gt;O estudo de Pan et al. (&lt;a href="https://arxiv.org/html/2508.13666v1" rel="noopener noreferrer"&gt;arXiv 2508.13666&lt;/a&gt;, lido na íntegra) mede o custo da formatação em duas etapas: uma amostra do Stack v2 (100 mil arquivos por linguagem em Java, C# e C++, tokenizer do GPT-4o) e um experimento principal com 10 modelos. Ambas removem só o que não altera a sintaxe. O paper cita o Python (4,0%) no mesmo estudo preliminar, sem repetir a amostra para ele.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Linguagem&lt;/th&gt;
&lt;th&gt;Arquivos reais (GPT-4o)&lt;/th&gt;
&lt;th&gt;Exercícios de completar código (média de 10 modelos)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;14,7%&lt;/td&gt;
&lt;td&gt;34,9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C++&lt;/td&gt;
&lt;td&gt;13,2%&lt;/td&gt;
&lt;td&gt;31,1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C#&lt;/td&gt;
&lt;td&gt;13,2%&lt;/td&gt;
&lt;td&gt;25,3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;4,0%&lt;/td&gt;
&lt;td&gt;6,5%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No experimento principal, os modelos completam um trecho de código em Java, Python, C++ e C#, com cinco modelos comerciais (entre eles GPT-4o, Claude 3.7 e Gemini 1.5) e cinco de pesos abertos. Remover indentação, espaços e quebras de linha cortou em média 24,5% dos tokens de input (o texto do paper também cita 24,6% e 25,8%). Nenhum modelo perdeu mais de 4,2 pontos de Pass@1, e nenhuma queda foi significativa. No Claude 3.7 a redução média foi de 23,0%. Python cai menos porque a indentação é sintaxe.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cada elemento (C++, Java, C#).&lt;/strong&gt; A indentação sozinha responde por 7,9% dos tokens de input no Claude 3.7, 8,9% no Gemini 1.5 e 9,6% no GPT-4o. As quebras de linha pesam mais nos dois primeiros (14,6% e 17,5%); no GPT-4o, os espaços (10,7%) pesam mais que as quebras (7,5%). A diferença vem dos tokenizers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saída.&lt;/strong&gt; O modelo repete a formatação mesmo com entrada sem ela: a redução média de output foi de só 2,5%. Pedir código sem formatação cortou 27,2% do output no GPT-4o sem perder acerto (Java, C++ e C#), mas o Gemini 1.5 quebrou a sintaxe e o Pass@1 em C++ caiu de 67,2% para 11,1%. Ajuste fino com 50 exemplos de Java reduziu o output em 24,8% (GPT-4o) e 35,9% (Gemini 1.5).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limites.&lt;/strong&gt; A tarefa é completar código, em quatro linguagens e com modelos de 2024–25. Os autores citam limites de generalização e a opacidade dos modelos comerciais. Nenhum modelo atual foi testado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leitura: a formatação é de 13% a 15% dos tokens em arquivos reais de Java, C# e C++, e a indentação sozinha vale cerca de 8% a 10% nos exercícios de completar código (Claude 3.7, Gemini 1.5 e GPT-4o). Como o output custa 5x a 6x o input, a formatação que o modelo gera pesa mais que a que você envia, mas ele tende a mantê-la. Pedir "sem formatação" exige teste, porque pode quebrar a sintaxe. A alternativa dos autores é uma ferramenta que remove a formatação na entrada e a restaura na saída.&lt;/p&gt;

&lt;h2&gt;
  
  
  Arquivos de contexto (CLAUDE.md, AGENTS.md, GEMINI.md): o que custam e quando compensam
&lt;/h2&gt;

&lt;p&gt;Esses arquivos entram no contexto de toda sessão. O texto em si custa pouco com cache; o custo relevante vem do que ele faz o agente fazer. A medição mais rigorosa é a de Gloaguen et al. (&lt;a href="https://arxiv.org/abs/2602.11988" rel="noopener noreferrer"&gt;arXiv 2602.11988&lt;/a&gt;, v2 de jun/2026, lido na íntegra): quatro agentes (Claude Code com Sonnet 4.5, Codex com GPT-5.2 e GPT-5.1 Mini, Qwen Code com Qwen3-30B), 300 tarefas do SWE-bench Lite e 138 tarefas de 12 repositórios com arquivos escrit&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
      <category>performance</category>
    </item>
    <item>
      <title>Métricas de efetividade de uso de IA — Spark Monitor</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Fri, 18 Sep 2026 13:00:57 +0000</pubDate>
      <link>https://dev.to/diegobrandao/metricas-de-efetividade-de-uso-de-ia-spark-monitor-531g</link>
      <guid>https://dev.to/diegobrandao/metricas-de-efetividade-de-uso-de-ia-spark-monitor-531g</guid>
      <description>&lt;h1&gt;
  
  
  Métricas de efetividade de uso de IA — Spark Monitor
&lt;/h1&gt;

&lt;p&gt;Resumo da pesquisa sobre como medir se uma sessão de IA (Claude Code) foi produtiva, e como ranquear uso entre várias pessoas de forma fidedigna.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problema-base
&lt;/h2&gt;

&lt;p&gt;Token bruto (input/output/cache) mede &lt;strong&gt;atividade&lt;/strong&gt;, não &lt;strong&gt;resultado&lt;/strong&gt;. Ranquear pessoas só por isso vira Goodhart's law: o comportamento se otimiza para o número, não para a entrega.&lt;/p&gt;

&lt;h2&gt;
  
  
  Métricas para somar ao que o Spark Monitor já captura
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache hit ratio&lt;/strong&gt; = &lt;code&gt;cache_read / (cache_read + input)&lt;/code&gt; — sinal de reuso eficiente de contexto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output por task fechada&lt;/strong&gt;, não por sessão — normaliza por dificuldade da tarefa.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sessões por task&lt;/strong&gt; — muitas sessões para fechar 1 task indica retrabalho ou task mal escopada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rework rate real&lt;/strong&gt; — % de código gerado por IA que é revertido ou reescrito em N dias. É a 5ª métrica oficial do DORA desde 2025. Sem esse dado, as métricas acima medem atividade, não qualidade.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Base acadêmica
&lt;/h2&gt;

&lt;p&gt;Paper: Chen et al., &lt;em&gt;"Beyond the Commit: Developer Perspectives on Productivity with AI Coding Assistants"&lt;/em&gt; — ICSE-SEIP 2026 (CMU + BNY Mellon). Survey com 2989 devs + 11 entrevistas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correlação entre satisfação percebida e tempo economizado auto-reportado: &lt;strong&gt;r = 0,34&lt;/strong&gt; (fraca). Confirma que métrica única não captura produtividade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 fatores identificados&lt;/strong&gt;, agrupados em desenvolvimento / deploy / longo prazo:

&lt;ol&gt;
&lt;li&gt;Autossuficiência&lt;/li&gt;
&lt;li&gt;Fricção e carga cognitiva&lt;/li&gt;
&lt;li&gt;Taxa e qualidade de conclusão de tarefa&lt;/li&gt;
&lt;li&gt;Facilidade de peer review&lt;/li&gt;
&lt;li&gt;Expertise técnica (longo prazo)&lt;/li&gt;
&lt;li&gt;Ownership do código (longo prazo)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Achado direto ao caso: commit frequency e taxa de aceite de sugestão (o que o Spark Monitor já capta) cobrem apenas o fator de deployment — não medem tempo real gasto nem qualidade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risco documentado&lt;/strong&gt;: ranking competitivo por atividade tende a empurrar devs júnior a confiar demais na IA, corroendo aprendizado e senso de ownership.&lt;/li&gt;
&lt;li&gt;Meta usa métrica própria, &lt;strong&gt;Diff Authoring Time (DAT)&lt;/strong&gt; — tempo real de autoria de um diff, sinal mais fino que token bruto (Beller et al. 2025).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Gate de avaliação por LLM (se for implementado)
&lt;/h2&gt;

&lt;p&gt;Riscos documentados de usar um LLM como juiz de código:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Viés de verbosidade&lt;/strong&gt; — o juiz tende a preferir código/resposta mais longa, mesmo sem ganho real de conteúdo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autopreferência&lt;/strong&gt; — o modelo tende a preferir a própria saída/estilo (efeito de menor "perplexidade").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boa notícia&lt;/strong&gt;: em tarefas verificáveis (código com teste/build), a autopreferência tende a refletir qualidade real — diferente de tarefas subjetivas como chat/resumo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Desenho recomendado — gate em 2 camadas:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Camada objetiva (sem viés): testes automatizados passam, build ok, lint/análise estática.&lt;/li&gt;
&lt;li&gt;Camada LLM-juiz: só para o que a camada objetiva não pega — legibilidade, aderência a padrão. Rubrica fixa, temperatura baixa, modelo juiz logado (idealmente diferente do modelo gerador). Calibrar periodicamente contra o rework rate real.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Mercado — não existe score pronto, mas existe a categoria
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitClear&lt;/strong&gt; — mede churn, duplicação, idade do código, atribuição IA vs. humano. ~US$15/contribuidor/mês.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DX&lt;/strong&gt; — feito pelos autores do SPACE e do DORA; lançou framework de IA dedicado em 2026 (utilização, impacto, custo).&lt;/li&gt;
&lt;li&gt;Nenhuma resolve o problema sozinha. A própria DX publicou (mar/2026) que DORA isolado não é suficiente para times usando IA.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dados já disponíveis para implementação
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Projeto&lt;/strong&gt;: campo &lt;code&gt;cwd&lt;/code&gt; presente em cada linha do JSONL de sessão do Claude Code (&lt;code&gt;~/.claude/projects/&amp;lt;cwd-codificado&amp;gt;/&amp;lt;uuid&amp;gt;.jsonl&lt;/code&gt; — no Windows, &lt;code&gt;%USERPROFILE%\.claude\projects\&lt;/code&gt;), mais &lt;code&gt;gitBranch&lt;/code&gt;. Já está no dado que o Spark Monitor lê.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push feito pela própria IA&lt;/strong&gt;: já registrado no mesmo JSONL, como &lt;code&gt;tool_use&lt;/code&gt;/&lt;code&gt;tool_result&lt;/code&gt; do Bash rodando &lt;code&gt;git push&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push manual do humano&lt;/strong&gt; (fora do Claude Code): não está no log do Claude Code. Requer hook git global (&lt;code&gt;git config --global core.hooksPath &amp;lt;pasta&amp;gt;&lt;/code&gt;, hook &lt;code&gt;pre-push&lt;/code&gt;) — cobre todos os repositórios de uma vez. Atenção: &lt;code&gt;pre-push&lt;/code&gt; confirma a intenção do push, não garante que a transferência de rede terminou com sucesso.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atenção&lt;/strong&gt;: "subiu pro remoto" ≠ "foi pra produção". Confirmar deploy real exige integração com CI/CD.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Fontes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Acadêmico
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Chen et al., &lt;em&gt;"Beyond the Commit: Developer Perspectives on Productivity with AI Coding Assistants"&lt;/em&gt;, ICSE-SEIP 2026 — &lt;a href="https://arxiv.org/abs/2602.03593" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2602.03593&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Wataoka et al., &lt;em&gt;"Self-Preference Bias in LLM-as-a-Judge"&lt;/em&gt; — &lt;a href="https://arxiv.org/html/2410.21819v1" rel="noopener noreferrer"&gt;https://arxiv.org/html/2410.21819v1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"Judging the Judges: A Systematic Evaluation of Bias Mitigation Strategies in LLM-as-a-Judge Pipelines"&lt;/em&gt; — &lt;a href="https://arxiv.org/pdf/2604.23178" rel="noopener noreferrer"&gt;https://arxiv.org/pdf/2604.23178&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"Do LLM Evaluators Prefer Themselves for a Reason?"&lt;/em&gt; (Univ. of Virginia, 2025) — &lt;a href="https://papers.lunadong.com/paper/6021" rel="noopener noreferrer"&gt;https://papers.lunadong.com/paper/6021&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DORA Research, &lt;em&gt;AI Capabilities Model&lt;/em&gt; — &lt;a href="https://dora.dev/research/ai/ai-capabilities-model" rel="noopener noreferrer"&gt;https://dora.dev/research/ai/ai-capabilities-model&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Indústria / mercado
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GetDX, &lt;em&gt;"How to Implement the AI Measurement Framework"&lt;/em&gt; — &lt;a href="https://getdx.com/blog/how-to-implement-ai-measurement-framework/" rel="noopener noreferrer"&gt;https://getdx.com/blog/how-to-implement-ai-measurement-framework/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitClear, estudo de churn/duplicação em código gerado por IA — via &lt;a href="https://arc.dev/talent-blog" rel="noopener noreferrer"&gt;https://arc.dev/talent-blog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Faros AI, &lt;em&gt;"AI Engineering Report 2026"&lt;/em&gt; — &lt;a href="https://www.faros.ai" rel="noopener noreferrer"&gt;https://www.faros.ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Documentação técnica Claude Code
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Formato JSONL de sessão — &lt;a href="https://claude-dev.tools/docs/jsonl-format"&gt;https://claude-dev.tools/docs/jsonl-format&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Local dos logs (&lt;code&gt;~/.claude/&lt;/code&gt;) — &lt;a href="https://claude-dev.tools/docs/log-locations"&gt;https://claude-dev.tools/docs/log-locations&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Template de Avaliação de IAs de Coding</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Wed, 01 Jul 2026 18:01:36 +0000</pubDate>
      <link>https://dev.to/diegobrandao/template-de-avaliacao-de-ias-de-coding-49fc</link>
      <guid>https://dev.to/diegobrandao/template-de-avaliacao-de-ias-de-coding-49fc</guid>
      <description>&lt;h2&gt;
  
  
  Resumo Executivo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;O que é este documento:&lt;/strong&gt; um modelo padronizado para avaliar, de forma comparável e replicável, a capacidade real de ferramentas de IA aplicadas a desenvolvimento (Codex, Devin, Claude e demais), identificando com precisão o que cada uma faz bem, faz mal, ou não faz.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por que essa metodologia:&lt;/strong&gt; hoje o mercado divulga números de benchmarks públicos (como SWE-bench e Terminal-Bench) que servem como referência de capacidade geral, mas apresentam duas limitações relevantes para decisão de negócio:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Medem desempenho em projetos abertos de terceiros (majoritariamente Python), não refletem o comportamento em codebases proprietários, legados e no stack específico da empresa.&lt;/li&gt;
&lt;li&gt;O resultado divulgado depende fortemente da ferramenta usada em torno do modelo (a forma como a IA é operacionalizada), não só do modelo em si — comparações "cruas" entre fornecedores tendem a ser enganosas.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Por isso, este template combina três referências reconhecidas no mercado — benchmarks públicos como ponto de partida, uma métrica de escala de dificuldade usada por institutos de avaliação de IA (METR) para medir até onde a ferramenta aguenta, e uma estrutura de avaliação usada em processos de seleção corporativa de ferramentas de IA (dimensões como confiabilidade, rastreabilidade, segurança e custo real) — com um piloto controlado, executado sobre código real da nossa operação, com critério e revisor únicos para todas as ferramentas testadas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resultado esperado:&lt;/strong&gt; uma matriz objetiva, com evidência documentada, que sustenta a recomendação de qual ferramenta adotar, para qual finalidade, e com quais limitações conhecidas.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Princípio metodológico:&lt;/strong&gt; o teste deve ser conduzido sobre uma tarefa real do backlog, nunca sobre um projeto de demonstração simplificado. A avaliação deve ser conduzida pelo mesmo revisor, com os mesmos critérios, para todas as ferramentas — garantindo comparabilidade.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. Preparação do teste
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repositório real&lt;/strong&gt;, com código legado, particularidades e convenções próprias — não um projeto novo e simplificado. É diante da complexidade real que se evidenciam os limites de cada ferramenta.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linha de base humana:&lt;/strong&gt; cronometrar quanto tempo um desenvolvedor Pleno leva para executar a mesma tarefa, como referência de comparação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revisor único:&lt;/strong&gt; mesma pessoa e mesmo critério de avaliação (checklist de PR) para todas as ferramentas testadas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repetição:&lt;/strong&gt; executar cada tarefa 2 a 3 vezes por ferramenta. O resultado de uma IA generativa varia entre execuções, mesmo para o mesmo pedido — uma única tentativa pode distorcer a avaliação.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Matriz de Capacidade por Ferramenta
&lt;/h2&gt;

&lt;p&gt;Escala: &lt;strong&gt;0&lt;/strong&gt; = não realiza | &lt;strong&gt;1&lt;/strong&gt; = realiza com baixa qualidade, exige reescrita | &lt;strong&gt;2&lt;/strong&gt; = realiza de forma razoável, exige ajustes | &lt;strong&gt;3&lt;/strong&gt; = realiza em nível pronto para PR&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capacidade avaliada&lt;/th&gt;
&lt;th&gt;Codex&lt;/th&gt;
&lt;th&gt;Devin&lt;/th&gt;
&lt;th&gt;Claude&lt;/th&gt;
&lt;th&gt;Outra&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Corrigir um bug simples em um único arquivo&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Corrigir um bug que envolve múltiplos serviços simultaneamente&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alterar a assinatura de uma função e ajustar todos os pontos que a utilizam&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Criar um novo endpoint seguindo o padrão já existente no projeto&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reter contexto de uma decisão do projeto após reabertura de sessão&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responder "se eu alterar isso, o que mais é impactado?" apenas com análise, sem executar mudanças&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Escrever testes que cobrem cenários relevantes, não apenas o caminho principal&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compreender uma dependência de um projeto que não está aberto no contexto atual&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seguir os padrões de arquitetura do time sem instrução repetida&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reconhecer limitação de conhecimento e solicitar mais contexto, em vez de gerar resposta incorreta com aparência de correta&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  3. Teste de Limite de Capacidade
&lt;/h2&gt;

&lt;p&gt;A dificuldade da tarefa deve ser escalonada progressivamente até que a ferramenta apresente falha — o objetivo é documentar em qual estágio cada uma deixa de performar de forma confiável:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tarefa de 1 arquivo, equivalente a menos de 30 min de trabalho humano&lt;/li&gt;
&lt;li&gt;Tarefa de 2 a 3 arquivos, equivalente a 1-2h de trabalho humano&lt;/li&gt;
&lt;li&gt;Tarefa que atravessa múltiplos serviços/repositórios, equivalente a meio dia de trabalho humano&lt;/li&gt;
&lt;li&gt;Tarefa sem especificação clara, que exige tomada de decisão de design, equivalente a um dia de trabalho humano&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Esta abordagem é baseada no conceito de &lt;strong&gt;Time Horizon&lt;/strong&gt;, métrica usada pelo instituto de pesquisa&lt;br&gt;
METR para medir não "se a IA acerta", mas até qual complexidade/duração de tarefa humana a ferramenta&lt;br&gt;
ainda mantém taxa de sucesso aceitável. Identificar o estágio em que cada ferramenta falha fornece&lt;br&gt;
mais informação para decisão do que uma nota única.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  4. Critérios Corporativos Complementares
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimensão&lt;/th&gt;
&lt;th&gt;Critério de avaliação&lt;/th&gt;
&lt;th&gt;Codex&lt;/th&gt;
&lt;th&gt;Devin&lt;/th&gt;
&lt;th&gt;Claude&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Consistência&lt;/td&gt;
&lt;td&gt;O resultado varia significativamente entre execuções para o mesmo pedido?&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rastreabilidade&lt;/td&gt;
&lt;td&gt;É possível identificar posteriormente qual ferramenta/versão gerou cada alteração?&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retenção de contexto&lt;/td&gt;
&lt;td&gt;A ferramenta compreende o projeto como um todo ou apenas o que está aberto no momento?&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reversibilidade&lt;/td&gt;
&lt;td&gt;Em caso de erro, é possível reverter apenas a alteração específica, ou o impacto se espalha por múltiplos arquivos?&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Segurança da informação&lt;/td&gt;
&lt;td&gt;Onde o código é processado/armazenado? Há uso do código para treinamento de modelo?&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custo real&lt;/td&gt;
&lt;td&gt;Qual o tempo de revisão humana efetivamente economizado, descontado o tempo gasto em correções?&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Ressalvas Metodológicas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A camada de operacionalização (produto) tem tanto peso quanto o modelo em si.&lt;/strong&gt; O mesmo modelo (ex.: Claude) executado por diferentes produtos pode apresentar resultados distintos. Recomenda-se registrar não apenas "qual IA", mas "qual IA, em qual produto".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmarks públicos não são preditivos do caso de uso específico.&lt;/strong&gt; Os benchmarks de mercado avaliam majoritariamente projetos abertos em Python; não refletem o comportamento em ambiente Java de fintech legado, com Kafka e IBM MQ. Devem ser tratados como referência geral, não como critério de decisão.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Números divulgados por fornecedores devem ser tratados com cautela&lt;/strong&gt;, especialmente quando não há metodologia reprodutível associada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demonstração de fornecedor não equivale a piloto controlado.&lt;/strong&gt; O cenário apresentado em demonstrações tende a ser favorável (projeto simples e recente). A avaliação deve ocorrer sobre código real da operação, incluindo débito técnico.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O custo oculto deve ser mensurado.&lt;/strong&gt; Tempo adicional de revisão sênior para correção do que foi gerado pela IA é custo, não apenas o tempo nominal economizado — deve compor o cálculo final de ganho de produtividade.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Prompts Padronizados para Execução dos Testes
&lt;/h2&gt;

&lt;p&gt;Recomenda-se aplicar os mesmos prompts (ajustando apenas nome de arquivo/função) em Codex, Devin e Claude, garantindo comparabilidade entre os testes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correção de bug simples (1 arquivo)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"No arquivo &lt;code&gt;[caminho]&lt;/code&gt;, o teste &lt;code&gt;[nome do teste]&lt;/code&gt; está falhando. Investigue a causa e corrija, sem alterar o comportamento esperado do teste."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Correção de bug cross-service&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"O serviço &lt;code&gt;[A]&lt;/code&gt; está retornando erro quando chama &lt;code&gt;[B]&lt;/code&gt;. Rastreie o fluxo completo entre os dois serviços, identifique a origem do problema e proponha a correção. Antes de editar, indique quais arquivos pretende alterar."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Análise de impacto de mudança de assinatura&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Quero alterar a assinatura do método &lt;code&gt;[nome]&lt;/code&gt; de &lt;code&gt;[assinatura atual]&lt;/code&gt; para &lt;code&gt;[nova assinatura]&lt;/code&gt;. Antes de qualquer alteração, liste todos os pontos do projeto que chamam esse método e o que será impactado."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Aderência a padrão existente&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Crie um novo endpoint &lt;code&gt;[descrição]&lt;/code&gt; seguindo exatamente o mesmo padrão de arquitetura, nomenclatura e tratamento de erro já utilizado nos demais endpoints deste projeto. Não introduza um padrão novo."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Retenção de contexto (executar em sessão nova)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Sem que eu forneça o contexto novamente: qual é a convenção que este projeto utiliza para tratamento de exceções? E para nomenclatura de branches?"&lt;br&gt;
&lt;em&gt;(aplica-se quando a ferramenta possui memória entre sessões — caso ela solicite o contexto de volta, esse já é um dado relevante sobre sua limitação)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Reconhecimento de limitação de conhecimento&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Implemente &lt;code&gt;[funcionalidade dependente de uma biblioteca ou API que você sabe que não existe ou mudou recentemente]&lt;/code&gt;."&lt;br&gt;
&lt;em&gt;Objetivo: verificar se a ferramenta sinaliza incerteza, ou gera código plausível porém incorreto.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Análise sem execução&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Não realize nenhuma alteração ainda. Apenas explique: se eu alterar o tipo de retorno de &lt;code&gt;[função]&lt;/code&gt; de &lt;code&gt;X&lt;/code&gt; para &lt;code&gt;Y&lt;/code&gt;, o que é impactado no projeto?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Cobertura de teste&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Escreva testes unitários para &lt;code&gt;[classe/função]&lt;/code&gt;. Inclua ao menos um cenário de borda não óbvio — entrada nula, lista vazia, concorrência ou timeout."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Teste de limite de complexidade (estágio 4 da seção 3)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Preciso de &lt;code&gt;[funcionalidade nova, sem especificação detalhada, que exige decisão de design]&lt;/code&gt;. Propositalmente não fornecerei todos os detalhes — faça as perguntas que considerar necessárias antes de iniciar a implementação."&lt;br&gt;
&lt;em&gt;Objetivo: verificar se a ferramenta solicita esclarecimento antes de agir, ou avança sobre premissas não validadas.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. Fontes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SWE-bench / SWE-bench Verified / Pro — arxiv.org/pdf/2509.16941, swebench.com&lt;/li&gt;
&lt;li&gt;Terminal-Bench 2.1 — tbench.ai, arxiv.org/html/2601.11868v1&lt;/li&gt;
&lt;li&gt;METR Time Horizon — metr.org/time-horizons, arxiv.org/html/2503.14499v1&lt;/li&gt;
&lt;li&gt;Checklist enterprise 6 dimensões (adaptado) — augmentcode.com/guides/cto-ai-coding-checklist&lt;/li&gt;
&lt;li&gt;Pilot enterprise (metodologia de rollout) — lumenalta.com/insights/how-to-evaluate-ai-coding-tools-for-enterprise-teams&lt;/li&gt;
&lt;li&gt;Governança de benchmarks / harness effect — digitalapplied.com/blog/swe-bench-terminal-bench-benchmark-guide-2026&lt;/li&gt;
&lt;li&gt;Devin SWE-bench technical report — cognition.ai/blog/swe-bench-technical-report&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>softwaredevelopment</category>
      <category>testing</category>
    </item>
    <item>
      <title>JIT Compilation — Guia Didático</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Tue, 09 Jun 2026 01:55:42 +0000</pubDate>
      <link>https://dev.to/diegobrandao/jit-compilation-guia-didatico-54h4</link>
      <guid>https://dev.to/diegobrandao/jit-compilation-guia-didatico-54h4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;O que você vai aprender:&lt;/strong&gt;&lt;br&gt;
Como a JVM decide o que compilar e quando · A diferença real entre C1 e C2 · O que é o Code Cache e por que ele pode derrubar sua performance · GraalVM: JIT vs Native Image · Project Leyden: como o Java 25 resolve o warmup de vez&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
1. O Problema Original

&lt;ul&gt;
&lt;li&gt;A cena que todo dev Java já viveu&lt;/li&gt;
&lt;li&gt;Comparativo das abordagens&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
2. Just-In-Time Compilation

&lt;ul&gt;
&lt;li&gt;O processo completo de um método na JVM&lt;/li&gt;
&lt;li&gt;Fluxo visual&lt;/li&gt;
&lt;li&gt;Por que a compilação não trava a aplicação&lt;/li&gt;
&lt;li&gt;Deoptimização — o que o curso não menciona&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
3. Os Dois Compiladores: C1 e C2

&lt;ul&gt;
&lt;li&gt;Otimizações que o C2 aplica e o C1 não consegue&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
4. Code Cache

&lt;ul&gt;
&lt;li&gt;Tamanhos padrão por versão&lt;/li&gt;
&lt;li&gt;O aviso mais temido em produção&lt;/li&gt;
&lt;li&gt;Flags essenciais para diagnóstico e tuning&lt;/li&gt;
&lt;li&gt;Detalhe importante sobre o CompileThreshold&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
5. GraalVM

&lt;ul&gt;
&lt;li&gt;5.1 Graal JIT — substituto do C2&lt;/li&gt;
&lt;li&gt;5.2 Native Image — AOT total&lt;/li&gt;
&lt;li&gt;Comparativo: JIT clássico vs GraalVM Native Image&lt;/li&gt;
&lt;li&gt;Por que Native Image tem peak performance menor&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
6. Project Leyden

&lt;ul&gt;
&lt;li&gt;Como funciona — em dois passos&lt;/li&gt;
&lt;li&gt;Linha do tempo dos JEPs do Leyden&lt;/li&gt;
&lt;li&gt;Comparativo final: os três mundos&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
7. Quando Parar de se Preocupar com Warmup

&lt;ul&gt;
&lt;li&gt;Resposta direta: Java 25+&lt;/li&gt;
&lt;li&gt;Contexto prático para Kubernetes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
8. Linha do Tempo e Resumo Executivo

&lt;ul&gt;
&lt;li&gt;Evolução completa da performance JVM&lt;/li&gt;
&lt;li&gt;Resumo executivo — referência rápida&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
9. GraalVM vs sem GraalVM — análise com dados reais

&lt;ul&gt;
&lt;li&gt;O que os dados dizem sobre adoção em produção&lt;/li&gt;
&lt;li&gt;Cenário 1 — Sem GraalVM: HotSpot JIT puro&lt;/li&gt;
&lt;li&gt;Cenário 2 — GraalVM modo JIT&lt;/li&gt;
&lt;li&gt;Cenário 3 — GraalVM Native Image&lt;/li&gt;
&lt;li&gt;Decisão rápida&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Referências Bibliográficas&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Seção 1 — O Problema Original
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Por que o Java era lento e, como ele resolveu isso&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  A cena que todo dev Java já viveu
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Você mede a performance de um método logo que a aplicação sobe: &lt;strong&gt;200ms&lt;/strong&gt;.&lt;br&gt;
Mede de novo 30 segundos depois: &lt;strong&gt;8ms&lt;/strong&gt;.&lt;br&gt;
O que aconteceu? A aplicação estava "esquentando".&lt;br&gt;
Isso tem nome, tem mecanismo e, a partir do Java 25, tem solução definitiva.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Java compila código-fonte (&lt;code&gt;.java&lt;/code&gt;) para &lt;strong&gt;bytecode&lt;/strong&gt; (&lt;code&gt;.class&lt;/code&gt;) — um formato intermediário, agnóstico de plataforma. A JVM interpreta esse bytecode em qualquer máquina. Isso é o famoso &lt;em&gt;write once, run anywhere&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O custo: interpretação instrução por instrução é lenta. Em 1996, Java rodava &lt;strong&gt;10 a 20× mais lento&lt;/strong&gt; que C.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparativo das abordagens
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Abordagem&lt;/th&gt;
&lt;th&gt;Portabilidade&lt;/th&gt;
&lt;th&gt;Performance&lt;/th&gt;
&lt;th&gt;Exemplo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compilado nativo&lt;/td&gt;
&lt;td&gt;❌ Binário por SO&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐ Máxima&lt;/td&gt;
&lt;td&gt;C / C++&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interpretado puro&lt;/td&gt;
&lt;td&gt;✅ Bytecode universal&lt;/td&gt;
&lt;td&gt;⭐ Baixa&lt;/td&gt;
&lt;td&gt;Java 1.0 (1996)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JIT — híbrido&lt;/td&gt;
&lt;td&gt;✅ Bytecode universal&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐ Alta&lt;/td&gt;
&lt;td&gt;Java 1.3+ (2000)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AOT Cache (Leyden)&lt;/td&gt;
&lt;td&gt;✅ Bytecode universal&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐ Alta + startup rápido&lt;/td&gt;
&lt;td&gt;Java 24+ (2024)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;💬 &lt;strong&gt;A pergunta que originou o JIT:&lt;/strong&gt; e se a JVM pudesse &lt;strong&gt;aprender enquanto roda&lt;/strong&gt; quais partes merecem ser compiladas para código nativo — sem abrir mão da portabilidade?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Seção 2 — Just-In-Time Compilation
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Como a JVM observa, decide e compila em tempo real&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O JIT é o mecanismo pelo qual a HotSpot JVM &lt;strong&gt;observa o código em execução&lt;/strong&gt; e, quando identifica trechos chamados com frequência (&lt;em&gt;hot spots&lt;/em&gt;), os compila para código de máquina nativo — em uma thread separada, sem parar a aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  O processo completo de um método na JVM
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Passo 1 — Execução interpretada (Tier 0)
&lt;/h4&gt;

&lt;p&gt;A JVM começa interpretando o bytecode linha a linha. Lento, mas funciona imediatamente. Ao mesmo tempo, dois contadores são incrementados por método:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method invocation count&lt;/strong&gt; — quantas vezes o método foi chamado&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loop back-edge count&lt;/strong&gt; — quantas vezes os loops do método executaram&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Passo 2 — Compilação pelo C1, rápida e com profiling (Tiers 1–3)
&lt;/h4&gt;

&lt;p&gt;Quando os contadores cruzam o &lt;code&gt;Tier3CompileThreshold&lt;/code&gt; (padrão: &lt;strong&gt;2.000 invocações&lt;/strong&gt;), o método entra na fila JIT. O compilador C1 gera código nativo rapidamente e continua coletando dados de comportamento (profiling). A aplicação já roda mais rápido, mas ainda não no máximo.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 3 — Compilação pelo C2, otimização agressiva (Tier 4)
&lt;/h4&gt;

&lt;p&gt;Quando o método atinge o &lt;code&gt;Tier4CompileThreshold&lt;/code&gt; (padrão: &lt;strong&gt;15.000 invocações&lt;/strong&gt;), o C2 entra em ação. Ele usa os dados de profiling do C1 para aplicar otimizações impossíveis de fazer sem observar o comportamento real: inlining, devirtualization, escape analysis e muito mais.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 4 — Armazenamento no Code Cache
&lt;/h4&gt;

&lt;p&gt;O código nativo compilado pelo C2 vai para o &lt;strong&gt;Code Cache&lt;/strong&gt; — uma região especial da memória fora do heap. A partir daí, o método roda na velocidade máxima possível, sem interpretação, sem compilação, sem overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fluxo visual
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────┐     ┌──────────────────┐     ┌─────────────────┐     ┌──────────────┐
│   TIER 0    │ ──► │   TIERS 1 – 3    │ ──► │    TIER 4       │ ──► │  CODE CACHE  │
│             │     │                  │     │                 │     │              │
│ Interpretado│     │ C1 compila       │     │ C2 otimiza      │     │ Nativo em    │
│ puro        │     │ + coleta         │     │ agressivamente  │     │ memória      │
│             │     │ profiling        │     │                 │     │ especial     │
└─────────────┘     └──────────────────┘     └─────────────────┘     └──────────────┘
    Lento               Rápido                   Máximo                Ultra-rápido
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;O símbolo &lt;code&gt;%&lt;/code&gt; no output de &lt;code&gt;-XX:+PrintCompilation&lt;/code&gt; indica que o método está no Code Cache — o estado mais otimizado possível.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Por que a compilação não trava a aplicação?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ A fila JIT e os compiladores rodam em &lt;strong&gt;threads separadas&lt;/strong&gt;. Enquanto um método está sendo compilado pelo C2, a JVM continua usando a versão C1 (ou interpretada) para atender requests. Quando a versão C2 fica pronta, a JVM faz o swap automaticamente — transparente para você.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ⚠️ Deoptimização — o que o curso não menciona
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;❌ O C2 faz otimizações &lt;strong&gt;especulativas&lt;/strong&gt; baseadas no que observou até agora. Se o comportamento mudar (ex: um método que era sempre chamado com &lt;code&gt;Integer&lt;/code&gt; agora recebe &lt;code&gt;String&lt;/code&gt;), a JVM pode &lt;strong&gt;deoptimizar&lt;/strong&gt; o método — jogar fora a versão C2 e voltar para o C1 ou interpretado. Esse ciclo pode se repetir. Em produção, deoptimizações frequentes aparecem nos logs JIT como &lt;code&gt;made not entrant&lt;/code&gt; e são sinais de código com comportamento inconsistente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Seção 3 — Os Dois Compiladores: C1 e C2
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Filosofias opostas, usadas na ordem certa&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;C1 — Client Compiler&lt;/th&gt;
&lt;th&gt;C2 — Server Compiler&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tiers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1, 2, 3&lt;/td&gt;
&lt;td&gt;4 exclusivamente&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filosofia&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compila RÁPIDO, otimiza POUCO&lt;/td&gt;
&lt;td&gt;Compila DEVAGAR, otimiza MUITO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tempo de startup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excelente&lt;/td&gt;
&lt;td&gt;Ruim isolado&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Peak performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Boa&lt;/td&gt;
&lt;td&gt;Máxima&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Coleta profiling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sim (tier 3)&lt;/td&gt;
&lt;td&gt;Usa o que o C1 coletou&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Escrito em&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C++&lt;/td&gt;
&lt;td&gt;C++ (HotSpot) / Java (Graal)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Caso ideal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apps curta duração, CLIs&lt;/td&gt;
&lt;td&gt;APIs, servidores, microsserviços&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;💬 &lt;strong&gt;Analogia:&lt;/strong&gt; C1 é o mecânico que faz uma regulagem rápida para você sair logo. C2 é o engenheiro de F1 que passa a noite otimizando cada componente. A &lt;strong&gt;Tiered Compilation&lt;/strong&gt; usa os dois na ordem certa, sem que você precise decidir.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Otimizações que o C2 aplica e o C1 não consegue
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Method Inlining
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes — chamada separada com overhead&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Depois — C2 inlina o corpo diretamente&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// chamada eliminada&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Elimina o overhead de chamada de método em hot paths. É a otimização mais impactante do C2.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  2. Escape Analysis
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes — parece precisar de alocação no heap&lt;/span&gt;
&lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Depois — C2 detecta que p não escapa do método&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// objeto eliminado, zero alocação&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Se o objeto não sai do método, C2 pode alocar na stack ou eliminar completamente. Reduz pressão no GC.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  3. Devirtualization
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes — polimórfico: qual método chamar?&lt;/span&gt;
&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sound&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Dog? Cat? Bird?&lt;/span&gt;

&lt;span class="c1"&gt;// Depois — C2 observou: 99% das vezes é Dog&lt;/span&gt;
&lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sound&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// chamada direta + inlining&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Se 99% das chamadas são para o mesmo tipo concreto, C2 inlina esse tipo e adiciona um guard raro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  4. Loop Unrolling
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes — loop com overhead de controle&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt;
    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Depois — C2 desenrola o loop&lt;/span&gt;
&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Reduz iterações, habilita vetorização SIMD e elimina o custo do contador de loop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  5. Dead Code Elimination
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="no"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DEBUG&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"calculando..."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// nunca vai rodar&lt;/span&gt;
&lt;span class="o"&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Depois — C2 remove o bloco morto completamente&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6. Range Check Elimination
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes — Java verifica bounds a cada acesso&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt;
    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;  &lt;span class="c1"&gt;// arr[i] verifica bounds toda vez&lt;/span&gt;

&lt;span class="c1"&gt;// Depois — C2 prova que o índice é sempre válido&lt;/span&gt;
&lt;span class="c1"&gt;// verificação eliminada no loop quente&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Seção 4 — Code Cache
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A região de memória que faz tudo isso funcionar e, que pode te trair&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Após compilação pelo C2, o código nativo vai para o &lt;strong&gt;Code Cache&lt;/strong&gt; — uma região de memória fora do heap Java, gerenciada separadamente. Métodos no Code Cache são executados diretamente pelo processador, sem qualquer overhead de interpretação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tamanhos padrão por versão
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Versão Java&lt;/th&gt;
&lt;th&gt;Tamanho padrão&lt;/th&gt;
&lt;th&gt;Observação&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Java ≤ 7 (32-bit)&lt;/td&gt;
&lt;td&gt;32 MB&lt;/td&gt;
&lt;td&gt;JVM 32-bit — removida no JDK 24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java ≤ 7 (64-bit)&lt;/td&gt;
&lt;td&gt;48 MB&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 8+ (64-bit)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;240 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Padrão atual — adequado para a maioria&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  ❌ O aviso mais temido em produção
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CodeCache is full. Compiler has been disabled.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A aplicação &lt;strong&gt;não cai&lt;/strong&gt;. Mas o JIT para. Novos métodos não são compilados. Métodos podem ser desalojados e recompilados em loop. Performance degrada silenciosamente e, sem esse aviso nos logs, você não vai saber por quê.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flags essenciais para diagnóstico e tuning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ver o que está sendo compilado em tempo real&lt;/span&gt;
&lt;span class="nt"&gt;-XX&lt;/span&gt;:+PrintCompilation

&lt;span class="c"&gt;# Inspecionar tamanho atual do Code Cache&lt;/span&gt;
&lt;span class="nt"&gt;-XX&lt;/span&gt;:+PrintCodeCache

&lt;span class="c"&gt;# Log completo para arquivo (útil em servidores remotos)&lt;/span&gt;
&lt;span class="nt"&gt;-XX&lt;/span&gt;:+UnlockDiagnosticVMOptions &lt;span class="nt"&gt;-XX&lt;/span&gt;:+LogCompilation

&lt;span class="c"&gt;# Ajustar tamanho máximo do Code Cache&lt;/span&gt;
&lt;span class="nt"&gt;-XX&lt;/span&gt;:ReservedCodeCacheSize&lt;span class="o"&gt;=&lt;/span&gt;256m

&lt;span class="c"&gt;# Threads de compilação (1/3 para C1, 2/3 para C2)&lt;/span&gt;
&lt;span class="nt"&gt;-XX&lt;/span&gt;:CICompilerCount&lt;span class="o"&gt;=&lt;/span&gt;6

&lt;span class="c"&gt;# Threshold de invocações (só funciona sem Tiered Compilation)&lt;/span&gt;
&lt;span class="nt"&gt;-XX&lt;/span&gt;:CompileThreshold&lt;span class="o"&gt;=&lt;/span&gt;10000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⚠️ Detalhe importante sobre o CompileThreshold
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;O &lt;code&gt;-XX:CompileThreshold=10000&lt;/code&gt; é amplamente citado mas &lt;strong&gt;quase nunca é o que a JVM usa&lt;/strong&gt;. Com Tiered Compilation ativa (padrão desde o Java 8), a JVM usa thresholds por tier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Tier3CompileThreshold = 2.000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Tier4CompileThreshold = 15.000&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O &lt;code&gt;CompileThreshold&lt;/code&gt; genérico só é relevante quando você &lt;strong&gt;desativa&lt;/strong&gt; a Tiered Compilation com &lt;code&gt;-XX:-TieredCompilation&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Seção 5 — GraalVM
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Um terceiro compilador e, uma alternativa radical ao JIT&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O GraalVM não é "só uma JVM mais rápida". É uma plataforma com &lt;strong&gt;duas abordagens fundamentalmente diferentes&lt;/strong&gt; — que você precisa entender separadamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Graal JIT — substituto do C2, mesmo modelo JIT
&lt;/h3&gt;

&lt;p&gt;O compilador Graal pode substituir o C2 dentro da HotSpot JVM usando a interface &lt;strong&gt;JVMCI&lt;/strong&gt; (disponível desde o Java 9). Nesse modo, tudo continua igual: Tiered Compilation, Code Cache, profiling só o compilador do tier 4 muda.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-XX&lt;/span&gt;:+UseJVMCICompiler    &lt;span class="c"&gt;# ativa o Graal JIT no lugar do C2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Graal JIT é escrito em &lt;strong&gt;Java&lt;/strong&gt; (não em C++ como o C2), o que permite otimizações mais sofisticadas e facilita evolução. Em benchmarks específicos, ele supera o C2 em throughput de pico.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Native Image — AOT total, sem JVM em runtime
&lt;/h3&gt;

&lt;p&gt;A opção mais radical do GraalVM: compilação &lt;strong&gt;AOT (Ahead-Of-Time) completa&lt;/strong&gt;. O bytecode vira um executável nativo antes da execução. Não há JVM em runtime. Não há JIT. Não há warmup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Gerar executável nativo&lt;/span&gt;
native-image &lt;span class="nt"&gt;-jar&lt;/span&gt; minha-aplicacao.jar

&lt;span class="c"&gt;# Resultado: binário nativo (~50ms startup, memória mínima)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparativo: JIT clássico vs GraalVM Native Image
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Característica&lt;/th&gt;
&lt;th&gt;JIT (HotSpot padrão)&lt;/th&gt;
&lt;th&gt;GraalVM Native Image&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Segundos (warmup necessário)&lt;/td&gt;
&lt;td&gt;~50ms (instantâneo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak performance&lt;/td&gt;
&lt;td&gt;Máxima — C2 adaptativo&lt;/td&gt;
&lt;td&gt;Inferior — sem JIT em runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uso de memória&lt;/td&gt;
&lt;td&gt;Maior (JVM + heap)&lt;/td&gt;
&lt;td&gt;Muito menor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reflexão dinâmica&lt;/td&gt;
&lt;td&gt;✅ Suportada nativamente&lt;/td&gt;
&lt;td&gt;⚠️ Requer &lt;code&gt;reflect-config.json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spring Boot simples&lt;/td&gt;
&lt;td&gt;✅ Funciona out of the box&lt;/td&gt;
&lt;td&gt;✅ Funciona (GraalVM plugin)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spring Boot complexo&lt;/td&gt;
&lt;td&gt;✅ Funciona sempre&lt;/td&gt;
&lt;td&gt;⚠️ Pode precisar de ajustes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caso ideal&lt;/td&gt;
&lt;td&gt;APIs, microsserviços com estado&lt;/td&gt;
&lt;td&gt;Serverless, CLIs, functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build time&lt;/td&gt;
&lt;td&gt;Padrão&lt;/td&gt;
&lt;td&gt;Muito mais longa (5–15 min)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  ❌ Por que Native Image tem peak performance menor?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;O JIT é &lt;strong&gt;adaptativo&lt;/strong&gt;: ele observa o comportamento real em runtime e aplica otimizações especulativas baseadas nesse comportamento. O Native Image compila tudo &lt;strong&gt;antes&lt;/strong&gt;, sem dados de runtime. Otimizações como devirtualization especulativa e inlining agressivo de chamadas polimórficas ficam comprometidas. Para cargas variáveis e código polimórfico, o C2 vence no longo prazo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Seção 6 — Project Leyden
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A solução definitiva para o warmup — sem abrir mão do JIT&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O warmup do JIT sempre foi o calcanhar de Aquiles do Java em ambientes cloud-native. Containers que sobem a cada scale-out, funções serverless, pods Kubernetes, todos começam do zero, sem cache JIT. O Project Leyden resolve isso.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como funciona — em dois passos
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Passo 1 — Training Run (executado uma única vez)
&lt;/h4&gt;

&lt;p&gt;A JVM roda a aplicação normalmente e salva em um arquivo &lt;code&gt;.aot&lt;/code&gt; tudo que normalmente faria no startup e warmup: classes carregadas e linkadas, perfis de invocação, código JIT compilado para os hot spots identificados.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 2 — Execuções de Produção (usam o cache)
&lt;/h4&gt;

&lt;p&gt;Todos os starts subsequentes carregam o cache. Classes já linkadas, hot spots já identificados, código C2 já compilado para os métodos críticos. A aplicação começa com &lt;strong&gt;performance de pico desde o primeiro request&lt;/strong&gt; — sem warmup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Passo 1: Training run (uma vez, fora de produção)&lt;/span&gt;
java &lt;span class="nt"&gt;-XX&lt;/span&gt;:AOTCacheOutput&lt;span class="o"&gt;=&lt;/span&gt;app.aot &lt;span class="nt"&gt;-jar&lt;/span&gt; app.jar

&lt;span class="c"&gt;# Passo 2: Todas as execuções em produção&lt;/span&gt;
java &lt;span class="nt"&gt;-XX&lt;/span&gt;:AOTCache&lt;span class="o"&gt;=&lt;/span&gt;app.aot &lt;span class="nt"&gt;-jar&lt;/span&gt; app.jar

&lt;span class="c"&gt;# Spring Boot 3.3+ já integra esse workflow nativamente&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Linha do tempo dos JEPs do Leyden
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Versão&lt;/th&gt;
&lt;th&gt;Ano&lt;/th&gt;
&lt;th&gt;JEP&lt;/th&gt;
&lt;th&gt;O que entrega&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JDK 24&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;JEP 483&lt;/td&gt;
&lt;td&gt;AOT Class Loading &amp;amp; Linking — classes pre-carregadas. Spring PetClinic &lt;strong&gt;42% mais rápido&lt;/strong&gt; no startup.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JDK 25&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2025&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;JEP 515&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AOT Method Profiling — perfis JIT no cache. Warmup praticamente eliminado.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JDK 26&lt;/td&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;JEP 516&lt;/td&gt;
&lt;td&gt;Cache universal, agnóstico de GC. Suporte a ZGC e Shenandoah. Cache baseline incluído no JDK — zero config.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Comparativo final: os três mundos
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────┬────────────────────────────┬──────────────────────────┐
│    JIT CLÁSSICO          │   GRAALVM NATIVE IMAGE     │   PROJECT LEYDEN         │
│    (HotSpot)             │                            │   (JDK 25+)              │
├──────────────────────────┼────────────────────────────┼──────────────────────────┤
│ ✓ Portabilidade total    │ ✓ Startup instantâneo      │ ✓ Startup ~42% mais      │
│ ✓ Peak performance max   │ ✓ Memória mínima           │   rápido                 │
│ ✓ Reflexão dinâmica      │ ✓ Ideal para serverless    │ ✓ Warmup eliminado       │
│ ✓ Sem mudanças no código │                            │ ✓ Peak performance max   │
│                          │ ✗ Sem JIT em runtime       │ ✓ Reflexão dinâmica      │
│ ✗ Startup lento          │ ✗ Peak performance menor   │ ✓ Sem mudanças no código │
│ ✗ Warmup (código frio)   │ ✗ Reflexão = config manual │                          │
│                          │ ✗ Build demorada           │ ✗ Requer training run    │
└──────────────────────────┴────────────────────────────┴──────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ A frase que resume tudo
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;GraalVM Native Image &lt;strong&gt;substitui&lt;/strong&gt; o JIT — você abre mão de otimizações adaptativas em troca de startup instantâneo.&lt;/p&gt;

&lt;p&gt;Project Leyden &lt;strong&gt;preserva&lt;/strong&gt; o JIT — você tem startup rápido &lt;strong&gt;e&lt;/strong&gt; peak performance máxima, sem abrir mão de nada.&lt;/p&gt;

&lt;p&gt;Para sistemas bancários com Spring Boot, Hibernate e cargas variáveis, &lt;strong&gt;Leyden é a resposta certa&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Seção 7 — Quando Parar de se Preocupar com Warmup
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A resposta direta, versão por versão&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Versão&lt;/th&gt;
&lt;th&gt;O que muda&lt;/th&gt;
&lt;th&gt;Impacto real no warmup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Java 8&lt;/td&gt;
&lt;td&gt;Tiered Compilation padrão&lt;/td&gt;
&lt;td&gt;JIT mais inteligente. Warmup ainda existe, mas bem gerenciado.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 11&lt;/td&gt;
&lt;td&gt;AppCDS estável&lt;/td&gt;
&lt;td&gt;Startup ~10–20% mais rápido. Warmup JIT inalterado.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 17&lt;/td&gt;
&lt;td&gt;AppCDS aprimorado + ZGC estável&lt;/td&gt;
&lt;td&gt;Startup melhorado. Warmup JIT inalterado.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 21&lt;/td&gt;
&lt;td&gt;Virtual Threads estáveis&lt;/td&gt;
&lt;td&gt;⚠️ NÃO resolve warmup. Resolve throughput I/O-bound. São problemas diferentes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 24&lt;/td&gt;
&lt;td&gt;Leyden: AOT Class Loading&lt;/td&gt;
&lt;td&gt;Startup 40%+ mais rápido. Warmup parcialmente melhorado.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Java 25&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Leyden: AOT Method Profiling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;✅ WARMUP PRATICAMENTE ELIMINADO.&lt;/strong&gt; JIT começa otimizando do primeiro request.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 26&lt;/td&gt;
&lt;td&gt;AOT Cache universal + ZGC&lt;/td&gt;
&lt;td&gt;Zero configuração extra. Cache baseline no JDK. Solução madura e completa.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  ✅ Resposta direta: Java 25+ com AOT Method Profiling (JEP 515)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A partir do &lt;strong&gt;Java 25&lt;/strong&gt;, o warmup do JIT deixa de ser uma preocupação para a grande maioria das aplicações. O AOT Cache armazena os perfis de execução dos métodos quentes, permitindo que o C2 compile os hot spots imediatamente no startup, sem precisar observar execuções repetidas. Para quem usa Spring Boot 3.3+, o suporte já está integrado com configuração mínima.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Contexto prático para Kubernetes e auto-scaling
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sem Leyden:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cada novo pod sobe sem cache JIT&lt;/li&gt;
&lt;li&gt;Os primeiros requests recebem latências elevadas&lt;/li&gt;
&lt;li&gt;Em ambientes com escala horizontal frequente, isso impacta diretamente o p95 e p99 de latência&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Com Leyden (JDK 25+):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O pod sobe com o AOT Cache&lt;/li&gt;
&lt;li&gt;Hot spots já identificados, código C2 já compilado&lt;/li&gt;
&lt;li&gt;Performance de pico desde o primeiro request&lt;/li&gt;
&lt;li&gt;O AOT Cache pode ser incluído na imagem Docker — sem step extra em runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Para ambientes bancários com Spring Boot + Kubernetes:&lt;/strong&gt; JDK 25 com AOT Method Profiling é o caminho. Não exige mudanças no código, preserva todo o ecossistema Spring, mantém a performance máxima do C2 e elimina o problema de cold start que existe hoje.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Seção 8 — Linha do Tempo e Resumo Executivo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Evolução completa da performance JVM
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Versão&lt;/th&gt;
&lt;th&gt;Ano&lt;/th&gt;
&lt;th&gt;Marco&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Java 1.0&lt;/td&gt;
&lt;td&gt;1996&lt;/td&gt;
&lt;td&gt;Interpretado puro — 10–20× mais lento que C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 1.1&lt;/td&gt;
&lt;td&gt;1997&lt;/td&gt;
&lt;td&gt;Primeiro JIT experimental — ainda muito básico&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 1.3&lt;/td&gt;
&lt;td&gt;2000&lt;/td&gt;
&lt;td&gt;HotSpot JVM como padrão — JIT adaptativo com C1 e C2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 7&lt;/td&gt;
&lt;td&gt;2011&lt;/td&gt;
&lt;td&gt;Tiered Compilation disponível como opção&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 8&lt;/td&gt;
&lt;td&gt;2014&lt;/td&gt;
&lt;td&gt;Tiered Compilation &lt;strong&gt;padrão&lt;/strong&gt; — C1+C2 automático&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 9&lt;/td&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;JVMCI: suporte ao Graal JIT como alternativa ao C2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 11&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;AppCDS estável — startup melhorado&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 21&lt;/td&gt;
&lt;td&gt;2023&lt;/td&gt;
&lt;td&gt;Virtual Threads estáveis — throughput I/O-bound resolvido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 24&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;Project Leyden: AOT Class Loading — startup 42% mais rápido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Java 25&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2025&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Project Leyden: AOT Method Profiling — warmup eliminado na prática&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java 26&lt;/td&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;AOT Cache universal + ZGC — solução madura e completa&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Resumo executivo — referência rápida
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Conceito&lt;/th&gt;
&lt;th&gt;O que você precisa saber&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JIT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A JVM compila hot spots para código nativo em runtime, em thread separada, sem parar a aplicação.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hot spot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Método com alto número de invocações ou iterações de loop — candidato à compilação JIT.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C1 (tiers 1–3)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compila rápido com otimizações básicas. Coleta profiling para o C2.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C2 (tier 4)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compila profundo com otimizações agressivas: inlining, escape analysis, devirtualization, loop unrolling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tiered Compilation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Estratégia padrão desde Java 8: usa C1 primeiro (startup rápido) e C2 depois (peak performance).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Cache&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Região de memória onde vive o código nativo compilado. 240 MB padrão no Java 8+. Cheio = problema grave.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deoptimização&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JVM joga fora a versão C2 se o comportamento mudar. Normal, mas frequência alta indica código inconsistente.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graal JIT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Substituto do C2 escrito em Java. Mesmo modelo JIT, otimizações diferentes. Ativo via &lt;code&gt;-XX:+UseJVMCICompiler&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GraalVM Native Image&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AOT total: sem JVM em runtime, sem warmup, mas sem JIT adaptativo. Ideal para serverless/CLIs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Project Leyden&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AOT Cache: treina uma vez, usa sempre. JDK 25 elimina warmup sem abrir mão do JIT ou do código atual.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Quando resolver&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Java 25+ para enterprise/Spring. GraalVM Native Image para serverless/CLIs simples.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  GraalVM vs sem GraalVM — análise com dados reais
&lt;/h2&gt;

&lt;h3&gt;
  
  
  O que os dados dizem sobre adoção em produção
&lt;/h3&gt;

&lt;p&gt;Antes de entrar nos cenários, é importante calibrar as expectativas com números verificados.&lt;/p&gt;

&lt;p&gt;O relatório &lt;strong&gt;New Relic State of the Java Ecosystem 2024&lt;/strong&gt; — baseado em dados de observabilidade de centenas de milhares de aplicações em produção — não registrou GraalVM Native Image como uma categoria de uso relevante entre as aplicações monitoradas. O relatório rastreia versões de JDK, vendors e GCs, mas o Native Image sequer aparece como item mensurável, o que por si só indica adoção marginal no universo enterprise geral. ¹&lt;/p&gt;

&lt;p&gt;O relatório &lt;strong&gt;Azul State of Java 2025&lt;/strong&gt; — com mais de 2.000 profissionais Java respondentes globalmente, confirma que 99% das organizações pesquisadas utilizam Java ativamente, com quase 70% delas tendo mais da metade de suas aplicações rodando na JVM. O foco absoluto das empresas continua sendo JVM clássica com HotSpot. ²&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;InfoQ Java Trends Report 2024&lt;/strong&gt; classifica o GraalVM Native Image para startup rápido na categoria "Early Majority" o que significa que a tecnologia existe e funciona, mas ainda não é mainstream. Para contexto, "Early Majority" no modelo de adoção de tecnologia representa algo entre 16% e 50% do mercado potencial, mas isso descreve o estágio de maturidade da tecnologia, não sua penetração real em produção. ³&lt;/p&gt;

&lt;p&gt;Um dado de produção concreto vem do blog &lt;strong&gt;BackendBytes&lt;/strong&gt; (fevereiro de 2026), que documentou migrações reais de equipes Spring Boot para Native Image: startup caindo de 7 segundos para 80ms, memória de 480 MB para 130 MB, mas com throughput em steady state &lt;strong&gt;10 a 25% menor&lt;/strong&gt; em comparação ao JIT. Esse número de queda de throughput é consistente entre múltiplas equipes migradas. ⁴&lt;/p&gt;

&lt;p&gt;Um dado importante de contexto estratégico: em setembro de 2025, a &lt;strong&gt;Oracle anunciou o desacoplamento do GraalVM do Java SE&lt;/strong&gt;, descontinuando o GraalVM Native Image para clientes do Java SE Product (Oracle JDK pago). O argumento oficial é que os objetivos de startup rápido e menor footprint serão perseguidos pelo Project Leyden como parte padrão do OpenJDK. Clientes usando o Graal JIT foram orientados a migrar de volta ao HotSpot JIT padrão. ⁵&lt;/p&gt;

&lt;p&gt;O GraalVM Native Image continua disponível pela GraalVM Community Edition (mantida pela Oracle Labs e pela comunidade), mas o sinal estratégico é claro: a Oracle apostou no Leyden como caminho padrão, não no Native Image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Os três cenários com benefícios e trade-offs reais
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Cenário 1 — Sem GraalVM: HotSpot JIT puro
&lt;/h4&gt;

&lt;p&gt;É o padrão atual de produção da grande maioria das aplicações Java no mundo. Você usa o C1 e o C2 da HotSpot, com Tiered Compilation ativa desde o Java 8.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefícios:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Peak performance máxima no longo prazo, o C2 faz otimizações adaptativas impossíveis de reproduzir em AOT&lt;/li&gt;
&lt;li&gt;Funciona com qualquer biblioteca, framework ou padrão de reflexão sem configuração extra&lt;/li&gt;
&lt;li&gt;Todo o ecossistema Spring, Hibernate, Jackson, Kafka funciona sem ressalvas&lt;/li&gt;
&lt;li&gt;Deoptimização e recompilação automáticas quando o comportamento do código muda&lt;/li&gt;
&lt;li&gt;Suporte e documentação amplíssimos, é a JVM que todos conhecem&lt;/li&gt;
&lt;li&gt;Build time idêntico ao padrão, nenhuma etapa adicional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Trade-offs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Startup lento: aplicações Spring Boot complexas levam de 4 a 11 segundos para estar prontas&lt;/li&gt;
&lt;li&gt;Warmup necessário: os primeiros requests são mais lentos enquanto o JIT "aprende"&lt;/li&gt;
&lt;li&gt;Em Kubernetes com auto-scaling, cada novo pod começa do zero sem cache JIT&lt;/li&gt;
&lt;li&gt;Uso de memória maior, a JVM, o heap e o Code Cache consomem mais RAM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quando usar:&lt;/strong&gt; APIs enterprise, microsserviços com Spring Boot complexo, sistemas com Hibernate ou qualquer uso intenso de reflexão, cargas variáveis onde o C2 adaptativo faz diferença. Ou seja: a maioria das aplicações bancárias em produção hoje.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cenário 2 — GraalVM modo JIT (Graal no lugar do C2)
&lt;/h4&gt;

&lt;p&gt;A JVM continua sendo a HotSpot. Tiered Compilation, Code Cache, profiling,  tudo igual. Só o compilador do tier 4 muda: o C2 é substituído pelo Graal, ativado com &lt;code&gt;-XX:+UseJVMCICompiler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefícios:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comportamento idêntico para o desenvolvedor, nenhuma mudança no código ou no processo de build&lt;/li&gt;
&lt;li&gt;O compilador Graal é escrito em Java (não em C++), o que permite algoritmos de otimização mais sofisticados&lt;/li&gt;
&lt;li&gt;Em workloads específicos com código muito regular e previsível, pode superar o C2 em throughput de pico&lt;/li&gt;
&lt;li&gt;Mantém todas as vantagens do JIT: deoptimização, profiling adaptativo, reflexão dinâmica&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Trade-offs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Em setembro de 2025, a Oracle orientou explicitamente que clientes do Oracle JDK migrem &lt;strong&gt;de volta&lt;/strong&gt; ao HotSpot JIT padrão, sinalizando que esse caminho não é o futuro ⁵&lt;/li&gt;
&lt;li&gt;Benefício de performance não é garantido, em muitos workloads o desempenho é equivalente ou ligeiramente inferior ao C2&lt;/li&gt;
&lt;li&gt;Menos testado em produção que o C2, ecossistema de suporte mais restrito&lt;/li&gt;
&lt;li&gt;O Graal JIT continua disponível na GraalVM CE, mas fora do mainstream Oracle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quando usar:&lt;/strong&gt; experimentos de performance em workloads muito específicos, pesquisa, ou contextos onde você já usa GraalVM CE e quer avaliar. Não recomendado como estratégia padrão de produção após o desacoplamento anunciado pela Oracle.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cenário 3 — GraalVM Native Image (AOT total)
&lt;/h4&gt;

&lt;p&gt;O bytecode vira um executável nativo antes de rodar. Não há JVM em runtime. Não há JIT. Não há warmup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefícios:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Startup instantâneo: de 4–11 segundos para 40–120ms em migrações documentadas ⁴&lt;/li&gt;
&lt;li&gt;Uso de memória drasticamente menor: redução de 60–70% em casos reais (480 MB → 130 MB) ⁴&lt;/li&gt;
&lt;li&gt;Ideal para ambientes com SLA de startup agressivo no Kubernetes, resolve o problema de pods perdendo a janela de readiness&lt;/li&gt;
&lt;li&gt;Binário auto-contido: não depende de JVM instalada no ambiente de execução&lt;/li&gt;
&lt;li&gt;Superfície de ataque reduzida: código morto removido na análise estática de build time&lt;/li&gt;
&lt;li&gt;Menor custo em funções serverless cobradas por tempo de execução e memória&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Trade-offs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Throughput em steady state &lt;strong&gt;10–25% menor&lt;/strong&gt; que o JIT em produção real, dado documentado em múltiplas migrações ⁴&lt;/li&gt;
&lt;li&gt;A "closed-world assumption" exige que todo o código acessível seja conhecido em build time, reflexão dinâmica, proxies e carregamento dinâmico de classes precisam de configuração explícita&lt;/li&gt;
&lt;li&gt;Spring Boot, Hibernate, Jackson e similares funcionam, mas exigem hints de reflexão no &lt;code&gt;reflect-config.json&lt;/code&gt; ou anotações específicas, o Spring Native/GraalVM plugin automatiza parte disso, mas não tudo&lt;/li&gt;
&lt;li&gt;Build time muito mais longa: de 5 a 15 minutos para aplicações médias, dependendo do tamanho do classpath&lt;/li&gt;
&lt;li&gt;Debugging em produção é mais limitado, sem JVM, sem JVMTI, ferramentas como JFR e Async Profiler têm suporte parcial&lt;/li&gt;
&lt;li&gt;Sem deoptimização: se o comportamento mudar, não há mecanismo de correção automática em runtime&lt;/li&gt;
&lt;li&gt;A descontinuação para clientes Oracle JDK cria incerteza sobre o suporte de longo prazo fora da GraalVM CE ⁵&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quando usar:&lt;/strong&gt; serviços serverless (AWS Lambda, Google Cloud Run), CLIs distribuídas como executável, microsserviços muito simples sem reflexão complexa, ambientes com SLA de startup impossível de cumprir com JVM clássica.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decisão rápida
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sua aplicação é...

  API enterprise / Spring Boot complexo / reflexão / carga variável?
  └─► HotSpot JIT puro  (+ Leyden no JDK 25+ para resolver o warmup)

  Serverless / CLI / startup crítico / memória muito restrita?
  └─► GraalVM Native Image  (com validação cuidadosa de reflexão)

  Quero experimentar Graal JIT sem mudar nada?
  └─► -XX:+UseJVMCICompiler  (mas avalie o desacoplamento Oracle antes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Referências Bibliográficas
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;[1]&lt;/strong&gt; NEW RELIC. &lt;em&gt;2024 State of the Java Ecosystem Report&lt;/em&gt;. San Francisco: New Relic, 2024. Disponível em: &lt;a href="https://newrelic.com/resources/report/2024-state-of-the-java-ecosystem" rel="noopener noreferrer"&gt;https://newrelic.com/resources/report/2024-state-of-the-java-ecosystem&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[2]&lt;/strong&gt; AZUL SYSTEMS. &lt;em&gt;Azul 2025 State of Java Survey &amp;amp; Report&lt;/em&gt;. Sunnyvale: Azul, jan. 2025. Disponível em: &lt;a href="https://www.azul.com/newsroom/azul-2025-state-of-java-survey-report/" rel="noopener noreferrer"&gt;https://www.azul.com/newsroom/azul-2025-state-of-java-survey-report/&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[3]&lt;/strong&gt; INFOQ EDITORIAL TEAM. &lt;em&gt;InfoQ Java Trends Report — December 2024&lt;/em&gt;. InfoQ, dez. 2024. Disponível em: &lt;a href="https://www.infoq.com/articles/java-trends-report-2024/" rel="noopener noreferrer"&gt;https://www.infoq.com/articles/java-trends-report-2024/&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[4]&lt;/strong&gt; BACKENDBYTES. &lt;em&gt;GraalVM Native Images in Production: From 5-Second Startup to 50ms&lt;/em&gt;. BackendBytes, fev. 2026. Disponível em: &lt;a href="https://backendbytes.com/articles/graalvm-native-images-java-production/" rel="noopener noreferrer"&gt;https://backendbytes.com/articles/graalvm-native-images-java-production/&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[5]&lt;/strong&gt; ORACLE. &lt;em&gt;Detaching GraalVM from the Java Ecosystem Train&lt;/em&gt;. Oracle Java Blog, set. 2025. Disponível em: &lt;a href="https://blogs.oracle.com/java/detaching-graalvm-from-the-java-ecosystem-train" rel="noopener noreferrer"&gt;https://blogs.oracle.com/java/detaching-graalvm-from-the-java-ecosystem-train&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[6]&lt;/strong&gt; OPENJDK. &lt;em&gt;JEP 483: Ahead-of-Time Class Loading &amp;amp; Linking&lt;/em&gt;. OpenJDK, 2024. Disponível em: &lt;a href="https://openjdk.org/jeps/483" rel="noopener noreferrer"&gt;https://openjdk.org/jeps/483&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[7]&lt;/strong&gt; OPENJDK. &lt;em&gt;JEP 514: Ahead-of-Time Command-Line Ergonomics&lt;/em&gt;. OpenJDK, 2025. Disponível em: &lt;a href="https://openjdk.org/jeps/514" rel="noopener noreferrer"&gt;https://openjdk.org/jeps/514&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[8]&lt;/strong&gt; OPENJDK. &lt;em&gt;JEP 515: Ahead-of-Time Method Profiling&lt;/em&gt;. OpenJDK, 2025. Disponível em: &lt;a href="https://openjdk.org/jeps/515" rel="noopener noreferrer"&gt;https://openjdk.org/jeps/515&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[9]&lt;/strong&gt; OPENJDK. &lt;em&gt;JEP 516: Ahead-of-Time Cache&lt;/em&gt;. OpenJDK, 2026. Disponível em: &lt;a href="https://openjdk.org/jeps/516" rel="noopener noreferrer"&gt;https://openjdk.org/jeps/516&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[10]&lt;/strong&gt; BAELDUNG. &lt;em&gt;JVM Tiered Compilation&lt;/em&gt;. Baeldung, 2024. Disponível em: &lt;a href="https://www.baeldung.com/jvm-tiered-compilation" rel="noopener noreferrer"&gt;https://www.baeldung.com/jvm-tiered-compilation&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[11]&lt;/strong&gt; ORACLE GRAAL TEAM. &lt;em&gt;Announcing Oracle GraalVM for JDK 24&lt;/em&gt;. Oracle Graal Blog, 2024. Disponível em: &lt;a href="https://blogs.oracle.com/graal/oracle-graalvm-for-jdk-24" rel="noopener noreferrer"&gt;https://blogs.oracle.com/graal/oracle-graalvm-for-jdk-24&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[12]&lt;/strong&gt; GRAALVM. &lt;em&gt;Native Image Documentation&lt;/em&gt;. GraalVM, 2025. Disponível em: &lt;a href="https://www.graalvm.org/latest/docs/" rel="noopener noreferrer"&gt;https://www.graalvm.org/latest/docs/&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[13]&lt;/strong&gt; INFOQ EDITORIAL TEAM. &lt;em&gt;InfoQ Java Trends Report 2025&lt;/em&gt;. InfoQ, dez. 2025. Disponível em: &lt;a href="https://www.infoq.com/articles/java-trends-report-2025/" rel="noopener noreferrer"&gt;https://www.infoq.com/articles/java-trends-report-2025/&lt;/a&gt;. Acesso em: jun. 2025.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Documento de estudo pessoal · Diego Brandão · 2025&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>performance</category>
      <category>graalvm</category>
      <category>jit</category>
    </item>
    <item>
      <title>Migração do Java 11 para Java 17: Benefícios e Trade-offs com Evidências Técnicas</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Sun, 07 Sep 2025 18:45:03 +0000</pubDate>
      <link>https://dev.to/diegobrandao/migracao-do-java-11-para-java-17-beneficios-e-trade-offs-com-evidencias-tecnicas-302n</link>
      <guid>https://dev.to/diegobrandao/migracao-do-java-11-para-java-17-beneficios-e-trade-offs-com-evidencias-tecnicas-302n</guid>
      <description>&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Resumo&lt;/li&gt;
&lt;li&gt;
Benefícios da Migração

&lt;ul&gt;
&lt;li&gt;1.1 Melhorias de Performance
&lt;/li&gt;
&lt;li&gt;1.2 Novos Recursos de Linguagem
&lt;/li&gt;
&lt;li&gt;1.3 Melhorias de Segurança
&lt;/li&gt;
&lt;li&gt;1.4 Suporte Long-Term Support (LTS)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Trade-offs e Desafios

&lt;ul&gt;
&lt;li&gt;2.1 Questões de Compatibilidade
&lt;/li&gt;
&lt;li&gt;2.2 Desafios Específicos da Migração
&lt;/li&gt;
&lt;li&gt;2.3 Custos de Migração
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Casos de Estudo Reais

&lt;ul&gt;
&lt;li&gt;3.1 Salesforce
&lt;/li&gt;
&lt;li&gt;3.2 Halodoc
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Recomendações Práticas

&lt;ul&gt;
&lt;li&gt;4.1 Estratégia de Migração
&lt;/li&gt;
&lt;li&gt;4.2 Alternativas Graduais
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;li&gt;Referências&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Resumo
&lt;/h2&gt;

&lt;p&gt;A migração do Java 11 para Java 17 representa uma atualização estratégica significativa para aplicações enterprise. Java 17 é uma versão Long-Term Support (LTS) que oferece melhorias substanciais em performance, segurança e recursos de linguagem, com suporte Oracle Premier até setembro de 2026. Este artigo apresenta uma análise técnica baseada em evidências sobre os benefícios e trade-offs desta migração.&lt;/p&gt;

&lt;p&gt;Estudos de benchmark demonstram ganhos de performance de 6-26% com Java 17, enquanto novos recursos como Records, Sealed Classes e melhor tratamento de NullPointerException melhoram significativamente a produtividade do desenvolvedor. Os principais trade-offs incluem questões de compatibilidade com bibliotecas legadas e a necessidade de atualização de dependências.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Benefícios da Migração
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1 Melhorias de Performance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Evidências de Benchmark Independentes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A OptaPlanner conduziu benchmarks extensivos comparando Java 11, 16 e 17, utilizando hardware estável (Intel Xeon Silver 4116 @ 2.1 GHz, 128 GiB RAM) em problemas de otimização reais durante 5 minutos cada. Os resultados demonstraram melhorias consistentes de performance.&lt;/p&gt;

&lt;p&gt;A Azul Systems reportou em benchmarks de 2025 que OpenJDK 17 foi 6% mais rápido que a baseline, enquanto soluções otimizadas como Azul Platform Prime alcançaram 26% de melhoria.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Melhorias no Garbage Collection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Java 17 introduz melhorias no garbage collector, particularmente em situações de baixa memória, resultando em ganhos de performance para aplicações que lidam com grandes datasets ou operações intensivas de memória.&lt;/p&gt;

&lt;p&gt;O G1 garbage collector tornou-se padrão a partir do Java 9, oferecendo performance mais consistente e tempos de resposta mais previsíveis. &lt;strong&gt;ZGC (Z Garbage Collector) tornou-se production-ready no JDK 17&lt;/strong&gt;, oferecendo coleta de lixo de baixa latência (sub-10ms) para heaps de até vários terabytes. &lt;strong&gt;Shenandoah está disponível em builds específicos como Red Hat OpenJDK e Amazon Corretto&lt;/strong&gt;, mas não faz parte do Oracle JDK oficial.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2 Novos Recursos de Linguagem
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Records&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Records permitem criar classes de dados imutáveis especificando apenas os campos necessários; todos os outros métodos são gerados automaticamente. Records atuam como classes de dados onde todos os campos são final, garantindo imutabilidade da referência. &lt;strong&gt;Importante&lt;/strong&gt;: Records são imutáveis por contrato apenas se usados com tipos imutáveis. O fato dos campos serem &lt;code&gt;final&lt;/code&gt; garante imutabilidade da referência, mas não garante thread-safety absoluto se o campo for um objeto mutável.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Java 11 - Classe tradicional&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataClass&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DataClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&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="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* implementação */&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* implementação */&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Java 17 - Record&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;DataClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// Cuidado: Records com objetos mutáveis&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;PersonRecord&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hobbies&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="nc"&gt;PersonRecord&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PersonRecord&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"João"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;());&lt;/span&gt;
&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hobbies&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"futebol"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Modifica o estado interno!&lt;/span&gt;
&lt;span class="c1"&gt;// Para verdadeira imutabilidade, use List.copyOf() ou Collections.unmodifiableList()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Sealed Classes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sealed Classes foram adicionadas à linguagem Java, restringindo quais outras classes ou interfaces podem estendê-las ou implementá-las, melhorando a segurança de tipos e organização do código.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern Matching e Switch Expressions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Switch expressions melhoradas permitem sintaxe mais concisa e segura. O operador instanceof também foi aprimorado, permitindo verificação de tipo e cast em uma única linha. &lt;strong&gt;A principal vantagem é legibilidade e segurança de tipo&lt;/strong&gt;, eliminando a necessidade de casts explícitos e reduzindo a possibilidade de ClassCastException.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Melhor Tratamento de NullPointerException&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uma atualização incrivelmente útil no Java 17 são as NullPointerExceptions melhoradas! Finalmente, nos logs de stack trace, é possível ver qual campo específico causou a NullPointerException.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Java 17 - NPE melhorada&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toLowerCase&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Exception output:&lt;/span&gt;
&lt;span class="c1"&gt;// java.lang.NullPointerException: Cannot invoke "String.toLowerCase()" &lt;/span&gt;
&lt;span class="c1"&gt;// because "s" is null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.3 Melhorias de Segurança
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Atualizações Regulares de Segurança&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O modelo de lançamento de segurança Java mudou para estar alinhado com o cronograma Oracle Critical Patch Update (CPU), onde releases CPU são lançados na terceira terça-feira de janeiro, abril, julho e outubro.&lt;/p&gt;

&lt;p&gt;JDK 17 introduziu melhorias significativas de segurança incluindo modo de validação segura XML habilitado por default, algoritmos SHA-1 desabilitados por padrão em assinaturas XML, e melhorias no suporte OCSP com requisições HTTP GET para performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encapsulamento Forte de Internals do JDK&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JEP 403 fortalece o encapsulamento de internals do JDK. Java 17 é fortemente encapsulado por padrão, então reflexão para internals do JDK não é mais permitida. Código que acessa campos e métodos não-públicos de APIs java.* lançará InaccessibleObjectException.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.4 Suporte Long-Term Support (LTS)
&lt;/h3&gt;

&lt;p&gt;Java 17 é uma versão LTS com Oracle Premier Support até setembro de 2026, proporcionando estabilidade e atualizações de segurança por período estendido. O processo de LTS garante que essas versões tornem-se mais estáveis e seguras devido a correções de bugs, melhorias de performance e patches de segurança.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Trade-offs e Desafios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Questões de Compatibilidade
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Deprecação e Remoção de APIs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Provavelmente a mudança mais significativa relacionada à segurança no JDK 17 é JEP 411: Deprecate the Security Manager for Removal. JDK 17 inicia esse processo depreciando várias APIs do Security Manager.&lt;/p&gt;

&lt;p&gt;Vários parâmetros JVM foram removidos ou depreciados até o Java 17. Se sua aplicação dependia das funcionalidades experimentais AOT ou Graal JIT no Java 11, considere a transição para GraalVM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problemas com Bibliotecas de Terceiros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nem todas as bibliotecas e frameworks de terceiros têm garantia de suporte ao Java 17 imediatamente. Verificar compatibilidade e atualizações é crucial. Ferramentas de build (Maven, Gradle) e IDEs devem ser atualizadas para suportar Java 17.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Desafios Específicos da Migração
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problemas com Lombok&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Um problema recorrente em migrações é incompatibilidade com versões antigas do Lombok. Um erro comum é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;java.lang.IllegalAccessError: class lombok.javac.apt.LombokProcessor cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A solução prática é atualizar o Lombok para uma versão compatível (por exemplo, &amp;gt;= 1.18.22) e validar a compilação/annotation-processing em ambientes CI e locais. Em casos extremos, configure o --add-opens temporariamente apenas para testes, mas prefira atualizar bibliotecas e remover dependências de internals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuração de Garbage Collection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Embora coletores de lixo mais novos como G1 ofereçam melhor performance, eles podem requerer ajustes. Aplicações com configurações customizadas de GC precisarão revisitar essas configurações.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modularização (Opcional)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: A modularização NÃO é obrigatória para Java 17. Aplicações podem continuar usando o classpath tradicional exatamente como em Java 11. A migração para o Module System (JPMS) é &lt;strong&gt;completamente opcional&lt;/strong&gt; e só deve ser considerada se você quiser benefícios específicos como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulamento mais forte de pacotes internos&lt;/li&gt;
&lt;li&gt;Dependências explícitas entre módulos&lt;/li&gt;
&lt;li&gt;Redução de footprint de memória em aplicações modulares&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A grande maioria das aplicações enterprise pode migrar para Java 17 sem qualquer mudança no sistema de módulos.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Custos de Migração
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Testes Extensivos Necessários&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Antes de migrar microserviços Java do JDK 11 para JDK 17, é essencial garantir que todos os testes unitários, de integração e de sistema passem com sucesso. Este passo é necessário para verificar que a aplicação funciona como esperado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tempo de Desenvolvimento&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Salesforce reportou que a migração do JDK 11 para JDK 17 levou três anos de planejamento com sete meses de desenvolvimento ativo. &lt;strong&gt;Importante&lt;/strong&gt;: Este prazo reflete o tamanho massivo do ecossistema Salesforce (Sales Cloud, Service Cloud, Marketing Cloud) com milhares de aplicações e microserviços. Empresas menores terão prazos significativamente mais curtos - a maioria das organizações pode completar a migração em algumas semanas ou meses, dependendo da complexidade da arquitetura.&lt;/p&gt;

&lt;p&gt;No entanto, as lições aprendidas pela Salesforce permitirão que futuras migrações, como JDK 21, sejam completadas em apenas um ano, demonstrando o valor do aprendizado organizacional.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Casos de Estudo Reais
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Salesforce
&lt;/h3&gt;

&lt;p&gt;A Salesforce liderou uma migração desafiadora do JDK 11 para JDK 17 para garantir performance e escalabilidade das aplicações principais, incluindo Sales Cloud, Service Cloud e Marketing Cloud. A migração entregou melhorias significativas de performance, possibilitando processamento mais rápido.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Halodoc
&lt;/h3&gt;

&lt;p&gt;A Halodoc migrou seus microserviços backend Java do JDK 11 para JDK 17, enfrentando desafios específicos como conflitos entre dependências Redisson e Jackson, que foram resolvidos através de cuidadoso exame das versões de dependências e ajustes necessários para garantir compatibilidade.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Recomendações Práticas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Estratégia de Migração
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Análise de Dependências&lt;/strong&gt;: Analisar dependências do projeto para garantir compatibilidade com Java 17. Atualizar bibliotecas ou frameworks desatualizados para versões que suportem a nova versão Java.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ambiente de Testes&lt;/strong&gt;: Testar aplicação em ambiente especial de testes com JDK atualizado. Revisar e atualizar todas as dependências e ferramentas de build para versões compatíveis com JDK 17.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Análise Estática&lt;/strong&gt;: Executar verificação estática de código para identificar onde problemas podem ocorrer. Ferramentas como Checkstyle, PMD, ou SpotBugs podem ser utilizadas.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4.2 Alternativas Graduais
&lt;/h3&gt;

&lt;p&gt;Para organizações não prontas para migração completa, alguns fornecedores de JDK oferecem soluções otimizadas que podem combinar versões de API com JVMs mais recentes. &lt;strong&gt;É recomendável avaliar benchmarks específicos para seu caso de uso&lt;/strong&gt; antes de adotar soluções comerciais que prometem melhorias de performance específicas.&lt;/p&gt;

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

&lt;p&gt;A migração do Java 11 para Java 17 oferece benefícios substanciais e mensuráveis:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefícios Principais:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Melhorias de performance de 6-26% conforme benchmarks independentes&lt;/li&gt;
&lt;li&gt;Recursos de linguagem modernos como Records, Sealed Classes e melhor tratamento de exceções (NPE melhoradas desde Java 14)&lt;/li&gt;
&lt;li&gt;Melhorias significativas de segurança e encapsulamento forte&lt;/li&gt;
&lt;li&gt;Suporte LTS: Oracle Premier até 2026, Extended até 2029, com alternativas de suporte de outros fornecedores&lt;/li&gt;
&lt;li&gt;ZGC production-ready para aplicações que necessitam baixa latência&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Trade-offs Principais:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Necessidade de atualização de dependências e ferramentas&lt;/li&gt;
&lt;li&gt;Problemas específicos com bibliotecas como Lombok&lt;/li&gt;
&lt;li&gt;Investimento em tempo de desenvolvimento e testes&lt;/li&gt;
&lt;li&gt;Configurações de GC podem requerer ajustes dependendo do perfil da aplicação&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Graças à forte compatibilidade retroativa do Java, a migração do 11 para o 17 tende a ser incremental e de baixo risco, especialmente em comparação com saltos maiores (ex: 8 → 17).&lt;/strong&gt; A compatibilidade permite mudar para Java 17 sem alterações de código obrigatórias (&lt;strong&gt;modularização é opcional&lt;/strong&gt;) e aproveitar todos os recursos atualizados. A versão 17 é Long-term Support, garantindo atualizações de segurança por período estendido com múltiplas opções de fornecedores.&lt;/p&gt;

&lt;p&gt;Para organizações enterprise, a migração é altamente recomendada, especialmente considerando que aplicações de grande escala e alta carga verão definitivamente melhor performance, tempo de inicialização mais rápido e menor footprint de memória após a migração.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Referências
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;HashStudioz Technologies. (2024). &lt;em&gt;Java Project Migration: Step-by-Step Guide from Java 11 to 17&lt;/em&gt;. Retrieved from &lt;a href="https://www.hashstudioz.com/blog/java-11-to-java-17-migration-guide/" rel="noopener noreferrer"&gt;https://www.hashstudioz.com/blog/java-11-to-java-17-migration-guide/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bell-SW. (2024). &lt;em&gt;How to Migrate from Java 11 to Java 17: Step-by-Step Tutorial&lt;/em&gt;. Retrieved from &lt;a href="https://bell-sw.com/blog/migration-from-java-11-to-java-17/" rel="noopener noreferrer"&gt;https://bell-sw.com/blog/migration-from-java-11-to-java-17/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HackerNoon. (2023). &lt;em&gt;Is Migrating From Java 11 to Java 17 Worth It?&lt;/em&gt; Retrieved from &lt;a href="https://hackernoon.com/is-migrating-from-java-11-to-java-17-worth-it" rel="noopener noreferrer"&gt;https://hackernoon.com/is-migrating-from-java-11-to-java-17-worth-it&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Medium - Pradeep Chirumamilla. (2024). &lt;em&gt;Java 11 to Java 17 Migration: A Guide with Key Features and Code Implementation&lt;/em&gt;. Retrieved from &lt;a href="https://medium.com/@pradeepchirumamilla01/java-11-to-java-17-migration-a-guide-with-key-features-and-code-implementation-dd63e0bd79e3" rel="noopener noreferrer"&gt;https://medium.com/@pradeepchirumamilla01/java-11-to-java-17-migration-a-guide-with-key-features-and-code-implementation-dd63e0bd79e3&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Halodoc Engineering. (2023). &lt;em&gt;A Practical Guide to Migrating from JDK 11 to JDK 17&lt;/em&gt;. Retrieved from &lt;a href="https://blogs.halodoc.io/jdk-17-migration/" rel="noopener noreferrer"&gt;https://blogs.halodoc.io/jdk-17-migration/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Zenesys. (2024). &lt;em&gt;Migrating a Project From Java 11 to Java 17: A Step-by-Step Guide&lt;/em&gt;. Retrieved from &lt;a href="https://www.zenesys.com/migrating-a-project-from-java-11-to-java-17-a-step-by-step-guide" rel="noopener noreferrer"&gt;https://www.zenesys.com/migrating-a-project-from-java-11-to-java-17-a-step-by-step-guide&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Medium - Alex Klimenko. (2025). &lt;em&gt;Migrating from Java 8 to Java 17: What Changed and Potential Issues&lt;/em&gt;. Retrieved from &lt;a href="https://medium.com/@alxkm/migrating-from-java-8-to-java-17-what-changed-and-potential-issues-85d2e85fc1ca" rel="noopener noreferrer"&gt;https://medium.com/@alxkm/migrating-from-java-8-to-java-17-what-changed-and-potential-issues-85d2e85fc1ca&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DEV Community - NIX. (2022). &lt;em&gt;Migrating a Project From Java 11 to Java 17: A Step-by-Step Guide for Developers&lt;/em&gt;. Retrieved from &lt;a href="https://dev.to/nix/migrating-a-project-from-java-11-to-java-17-a-step-by-step-guide-for-developers-42n"&gt;https://dev.to/nix/migrating-a-project-from-java-11-to-java-17-a-step-by-step-guide-for-developers-42n&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Salesforce Engineering. (2025). &lt;em&gt;Behind Salesforce's JDK 11 to JDK 17 Migration&lt;/em&gt;. Retrieved from &lt;a href="https://engineering.salesforce.com/behind-salesforces-jdk-11-to-jdk-17-migration-lessons-for-modernizing-large-scale-java-applications/" rel="noopener noreferrer"&gt;https://engineering.salesforce.com/behind-salesforces-jdk-11-to-jdk-17-migration-lessons-for-modernizing-large-scale-java-applications/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Medium - Alex Klimenko. (2024). &lt;em&gt;Modernizing Legacy Java: A Practical Guide to Migrating to Java 17/21+&lt;/em&gt;. Retrieved from &lt;a href="https://medium.com/@alxkm/modernizing-legacy-java-a-practical-guide-to-migrating-to-java-17-21-b3ab6a215f1f" rel="noopener noreferrer"&gt;https://medium.com/@alxkm/modernizing-legacy-java-a-practical-guide-to-migrating-to-java-17-21-b3ab6a215f1f&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OptaPlanner. (2021). &lt;em&gt;How much faster is Java 17?&lt;/em&gt; Retrieved from &lt;a href="https://www.optaplanner.org/blog/2021/09/15/HowMuchFasterIsJava17.html" rel="noopener noreferrer"&gt;https://www.optaplanner.org/blog/2021/09/15/HowMuchFasterIsJava17.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2021). &lt;em&gt;JDK 17 Release Notes, Important Changes, and Information&lt;/em&gt;. Retrieved from &lt;a href="https://www.oracle.com/java/technologies/javase/17-relnote-issues.html" rel="noopener noreferrer"&gt;https://www.oracle.com/java/technologies/javase/17-relnote-issues.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitHub - Ionut Balosin. (2024). &lt;em&gt;JVM Performance Benchmarks&lt;/em&gt;. Retrieved from &lt;a href="https://github.com/ionutbalosin/jvm-performance-benchmarks" rel="noopener noreferrer"&gt;https://github.com/ionutbalosin/jvm-performance-benchmarks&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Azul Systems. (2025). &lt;em&gt;Benchmarks Show Faster Java Performance Improvement&lt;/em&gt;. Retrieved from &lt;a href="https://www.azul.com/blog/benchmarks-show-faster-java-performance-improvement/" rel="noopener noreferrer"&gt;https://www.azul.com/blog/benchmarks-show-faster-java-performance-improvement/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2014). &lt;em&gt;Avoiding Benchmarking Pitfalls on the JVM&lt;/em&gt;. Retrieved from &lt;a href="https://www.oracle.com/technical-resources/articles/java/architect-benchmarking.html" rel="noopener noreferrer"&gt;https://www.oracle.com/technical-resources/articles/java/architect-benchmarking.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;oj! Algorithms. (2022). &lt;em&gt;JDK17 Benchmark&lt;/em&gt;. Retrieved from &lt;a href="https://www.ojalgo.org/2021/11/jdk17-benchmark/" rel="noopener noreferrer"&gt;https://www.ojalgo.org/2021/11/jdk17-benchmark/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2024). &lt;em&gt;Overview of Java SE Subscription Enterprise Performance Pack&lt;/em&gt;. Retrieved from &lt;a href="https://docs.oracle.com/en/java/java-components/enterprise-performance-pack/epp-user-guide/overview.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/java/java-components/enterprise-performance-pack/epp-user-guide/overview.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ionut Balosin. (2023). &lt;em&gt;JVM Performance Comparison for JDK 17&lt;/em&gt;. Retrieved from &lt;a href="https://ionutbalosin.com/2023/03/jvm-performance-comparison-for-jdk-17/" rel="noopener noreferrer"&gt;https://ionutbalosin.com/2023/03/jvm-performance-comparison-for-jdk-17/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pretius. (2022). &lt;em&gt;Java 17 features: A comparison between versions 8 and 17&lt;/em&gt;. Retrieved from &lt;a href="https://pretius.com/blog/java-17-features" rel="noopener noreferrer"&gt;https://pretius.com/blog/java-17-features&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2021). &lt;em&gt;JDK Releases&lt;/em&gt;. Retrieved from &lt;a href="https://www.java.com/releases/" rel="noopener noreferrer"&gt;https://www.java.com/releases/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2024). &lt;em&gt;Consolidated JDK 17 Release Notes&lt;/em&gt;. Retrieved from &lt;a href="https://www.oracle.com/java/technologies/javase/17all-relnotes.html" rel="noopener noreferrer"&gt;https://www.oracle.com/java/technologies/javase/17all-relnotes.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2025). &lt;em&gt;Oracle Java SE Support Roadmap&lt;/em&gt;. Retrieved from &lt;a href="https://www.oracle.com/java/technologies/java-se-support-roadmap.html" rel="noopener noreferrer"&gt;https://www.oracle.com/java/technologies/java-se-support-roadmap.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Baeldung. (2024). &lt;em&gt;New Features in Java 17&lt;/em&gt;. Retrieved from &lt;a href="https://www.baeldung.com/java-17-new-features" rel="noopener noreferrer"&gt;https://www.baeldung.com/java-17-new-features&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2024). &lt;em&gt;Java™ SE Development Kit 17, 17.0.15 Release Notes&lt;/em&gt;. Retrieved from &lt;a href="https://www.oracle.com/java/technologies/javase/17-0-15-relnotes.html" rel="noopener noreferrer"&gt;https://www.oracle.com/java/technologies/javase/17-0-15-relnotes.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2024). &lt;em&gt;Java Security Resource Center&lt;/em&gt;. Retrieved from &lt;a href="https://www.oracle.com/java/technologies/security.html" rel="noopener noreferrer"&gt;https://www.oracle.com/java/technologies/security.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wikipedia. (2025). &lt;em&gt;Java version history&lt;/em&gt;. Retrieved from &lt;a href="https://en.wikipedia.org/wiki/Java_version_history" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Java_version_history&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sean Mullan. (2021). &lt;em&gt;JDK 17 Security Enhancements&lt;/em&gt;. Retrieved from &lt;a href="https://seanjmullan.org/blog/2021/09/14/jdk17" rel="noopener noreferrer"&gt;https://seanjmullan.org/blog/2021/09/14/jdk17&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Red Hat. (2024). &lt;em&gt;OpenJDK Life Cycle and Support Policy&lt;/em&gt;. Retrieved from &lt;a href="https://access.redhat.com/articles/1299013" rel="noopener noreferrer"&gt;https://access.redhat.com/articles/1299013&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2021). &lt;em&gt;Java Platform, Standard Edition Oracle JDK Migration Guide, Release 11&lt;/em&gt;. Retrieved from &lt;a href="https://docs.oracle.com/en/java/javase/11/migrate/index.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/java/javase/11/migrate/index.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Oracle. (2024). &lt;em&gt;Migrating From JDK 8 to Later JDK Releases&lt;/em&gt;. Retrieved from &lt;a href="https://docs.oracle.com/en/java/javase/17/migrate/migrating-jdk-8-later-jdk-releases.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/java/javase/17/migrate/migrating-jdk-8-later-jdk-releases.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>Java Records vs Lombok: Guia Definitivo para Escolher a Ferramenta Certa</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Mon, 21 Jul 2025 23:23:42 +0000</pubDate>
      <link>https://dev.to/diegobrandao/java-records-vs-lombok-guia-definitivo-para-escolher-a-ferramenta-certa-47ij</link>
      <guid>https://dev.to/diegobrandao/java-records-vs-lombok-guia-definitivo-para-escolher-a-ferramenta-certa-47ij</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;A eterna busca por reduzir o código boilerplate em Java ganhou duas ferramentas poderosas: &lt;strong&gt;Java Records&lt;/strong&gt; (introduzidos no Java 14 e estabilizados no Java 16) e &lt;strong&gt;Lombok&lt;/strong&gt; (biblioteca amplamente adotada há anos). Embora ambos ataquem o mesmo problema - a verbosidade do Java - eles fazem isso de maneiras fundamentalmente diferentes, com implicações importantes para o design e arquitetura do seu código.&lt;/p&gt;

&lt;p&gt;Este artigo vai além da comparação superficial de sintaxe e mergulha nas diferenças semânticas, casos de uso práticos e trade-offs de cada abordagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Records Java: Mais que Redução de Boilerplate
&lt;/h2&gt;

&lt;h3&gt;
  
  
  O que são Records?
&lt;/h3&gt;

&lt;p&gt;Records não são apenas uma forma concisa de criar classes - eles são &lt;strong&gt;tipos de produto&lt;/strong&gt; com semântica específica. Segundo a JEP 395:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Records são portadores transparentes de dados imutáveis"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A palavra-chave aqui é &lt;strong&gt;transparente&lt;/strong&gt;. Records seguem o princípio:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A API de um record modela o estado, todo o estado, e nada além do estado"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Exemplo Básico
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes: 40+ linhas de código boilerplate&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Pessoa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;idade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getIdade&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* implementação */&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* implementação */&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* implementação */&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Depois: 1 linha&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Pessoa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idade&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;h3&gt;
  
  
  Características dos Records
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Imutabilidade por Design&lt;/strong&gt;: Todos os campos são &lt;code&gt;private final&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparência&lt;/strong&gt;: Não há estado oculto&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Construtores Canônicos&lt;/strong&gt;: Gerados automaticamente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Métodos Padrão&lt;/strong&gt;: &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt;, &lt;code&gt;toString()&lt;/code&gt; implementados automaticamente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acessores&lt;/strong&gt;: Métodos com o mesmo nome dos componentes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Lombok: Flexibilidade Através de Anotações
&lt;/h2&gt;

&lt;h3&gt;
  
  
  O que é Lombok?
&lt;/h3&gt;

&lt;p&gt;Lombok é uma biblioteca que &lt;strong&gt;gera código&lt;/strong&gt; em tempo de compilação através de anotações. Não impõe semântica específica - é pura redução de boilerplate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo com Lombok
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Método personalizado&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;aplicarDesconto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;desconto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;preco&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;desconto&lt;/span&gt;&lt;span class="o"&gt;;&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;h3&gt;
  
  
  Principais Anotações
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@Data&lt;/code&gt;: Gera getters, setters, &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt;, &lt;code&gt;toString()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Value&lt;/code&gt;: Classe imutável (equivalente a um record)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Builder&lt;/code&gt;: Padrão Builder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Slf4j&lt;/code&gt;: Injeção de logger&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Getter/@Setter&lt;/code&gt;: Getters e setters específicos&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparação Detalhada
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspecto&lt;/th&gt;
&lt;th&gt;Records&lt;/th&gt;
&lt;th&gt;Lombok&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Semântica&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tipos de produto transparentes&lt;/td&gt;
&lt;td&gt;Geração de código&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Imutabilidade&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Por padrão&lt;/td&gt;
&lt;td&gt;Opcional (@Value)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibilidade&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limitada&lt;/td&gt;
&lt;td&gt;Alta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Herança&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Não suportada&lt;/td&gt;
&lt;td&gt;Suportada&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Estado Oculto&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Proibido&lt;/td&gt;
&lt;td&gt;Permitido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dependência Externa&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Não&lt;/td&gt;
&lt;td&gt;Sim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Versão Java&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;14+ (estável no 16+)&lt;/td&gt;
&lt;td&gt;Qualquer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Desempenho&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nativo&lt;/td&gt;
&lt;td&gt;Geração em tempo de compilação&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Quando Usar Records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Use Records para:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. DTOs (Data Transfer Objects)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;UsuarioDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;nascimento&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;h4&gt;
  
  
  2. Objetos de Valor
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Dinheiro&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;moeda&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;h4&gt;
  
  
  3. Respostas de API
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;ApiResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;dados&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mensagem&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;h4&gt;
  
  
  4. Configurações Imutáveis
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;DatabaseConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;timeout&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;h4&gt;
  
  
  5. Entidades JPA Simples (com limitações)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt; &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;preco&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;h3&gt;
  
  
  ❌ Evite Records quando:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Precisar de mutabilidade&lt;/li&gt;
&lt;li&gt;Necessitar de herança&lt;/li&gt;
&lt;li&gt;Requerer estado oculto&lt;/li&gt;
&lt;li&gt;Trabalhar com frameworks que exigem construtores sem argumentos&lt;/li&gt;
&lt;li&gt;Precisar de métodos de ciclo de vida JPA complexos&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quando Usar Lombok
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Use Lombok para:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Entidades JPA Complexas
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Usuario&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuario"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cascade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CascadeType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pedido&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Modelos de Negócio com Comportamento
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContaBancaria&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sacar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sacando {} da conta {}"&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="n"&gt;numero&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&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="na"&gt;compareTo&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="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&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="n"&gt;saldo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&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="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saldo insuficiente"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&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;h4&gt;
  
  
  3. Builders Complexos
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Builder&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Relatorio&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;titulo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;dataInicio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;dataFim&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;colunas&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parametros&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Uso&lt;/span&gt;
&lt;span class="nc"&gt;Relatorio&lt;/span&gt; &lt;span class="n"&gt;relatorio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Relatorio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;titulo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Vendas Mensais"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dataInicio&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;minusMonths&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dataFim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;colunas&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"produto"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"quantidade"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"valor"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ❌ Evite Lombok quando:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;O projeto exigir zero dependências externas&lt;/li&gt;
&lt;li&gt;Houver problemas de compatibilidade com IDEs&lt;/li&gt;
&lt;li&gt;A equipe não estiver familiarizada com a biblioteca&lt;/li&gt;
&lt;li&gt;Precisar de garantias semânticas específicas&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Casos de Uso Práticos
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cenário 1: Sistema de E-commerce
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DTO para resposta da API - USE RECORD&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ProdutoResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;categoria&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// Entidade JPA com comportamento - USE LOMBOK&lt;/span&gt;
&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@Builder&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;preco&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;categoria&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;estoque&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;reduzirEstoque&lt;/span&gt;&lt;span class="o"&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="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;estoque&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Estoque insuficiente"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;estoque&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;;&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;h3&gt;
  
  
  Cenário 2: Sistema Bancário
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Objeto de valor imutável - USE RECORD&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Moeda&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;codigo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;simbolo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// Entidade complexa com estado mutável - USE LOMBOK&lt;/span&gt;
&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@EqualsAndHashCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onlyExplicitlyIncluded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Conta&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@EqualsAndHashCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Include&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;numero&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;titular&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"conta"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cascade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CascadeType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Transacao&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;transacoes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;transferir&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Conta&lt;/span&gt; &lt;span class="n"&gt;destino&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Transferindo {} de {} para {}"&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;numero&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destino&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;numero&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Lógica de transferência&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;h2&gt;
  
  
  Híbrido: Usando Records e Lombok Juntos
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Record com anotações do Lombok para funcionalidades adicionais&lt;/span&gt;
&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ProcessamentoResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;sucesso&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ProcessamentoResult&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Resultado do processamento {}: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sucesso&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"SUCESSO"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"FALHA"&lt;/span&gt;&lt;span class="o"&gt;);&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;h2&gt;
  
  
  O Futuro: Spring Data Commons Recomenda Records
&lt;/h2&gt;

&lt;p&gt;O Spring Framework oficialmente recomenda Records para DTOs e projeções:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Recomendação oficial do Spring Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;NamesOnly&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// Em vez de usar Lombok&lt;/span&gt;
&lt;span class="nd"&gt;@Value&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NamesOnly&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastname&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;h2&gt;
  
  
  Diretrizes para Tomada de Decisão
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Escolha Records quando:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Estiver no Java 16+&lt;/li&gt;
&lt;li&gt;✅ Precisar de objetos imutáveis&lt;/li&gt;
&lt;li&gt;✅ Quiser garantias semânticas fortes&lt;/li&gt;
&lt;li&gt;✅ Criar DTOs ou objetos de valor&lt;/li&gt;
&lt;li&gt;✅ Buscar máxima performance (sem overhead de biblioteca)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Escolha Lombok quando:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Precisar de flexibilidade máxima&lt;/li&gt;
&lt;li&gt;✅ Trabalhar com herança&lt;/li&gt;
&lt;li&gt;✅ Requerer mutabilidade&lt;/li&gt;
&lt;li&gt;✅ Usar versões antigas do Java&lt;/li&gt;
&lt;li&gt;✅ Precisar de funcionalidades como &lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt; ou @Slf4j&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use Ambos quando:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Records para DTOs e objetos de valor&lt;/li&gt;
&lt;li&gt;✅ Lombok para entidades e modelos de negócio&lt;/li&gt;
&lt;li&gt;✅ Aproveitar o melhor de cada abordagem&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migração Gradual
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Estratégia de Migração para Records:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identifique candidatos&lt;/strong&gt;: DTOs, objetos de valor, classes imutáveis simples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migre gradualmente&lt;/strong&gt;: Comece com classes menos críticas&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teste thoroughly&lt;/strong&gt;: Verifique serialização e frameworks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitore performance&lt;/strong&gt;: Records podem ter características diferentes&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Exemplo de Migração:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes (Lombok)&lt;/span&gt;
&lt;span class="nd"&gt;@Value&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Endereco&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;rua&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cidade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cep&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Depois (Record)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Endereco&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;rua&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cidade&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cep&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;h2&gt;
  
  
  Considerações de Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Records:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Sem overhead de biblioteca&lt;/li&gt;
&lt;li&gt;✅ Otimizações do compilador&lt;/li&gt;
&lt;li&gt;⚠️ Criação de objetos em atualizações (imutabilidade)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lombok:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Código gerado otimizado&lt;/li&gt;
&lt;li&gt;⚠️ Dependência de bibliotecas externas&lt;/li&gt;
&lt;li&gt;⚠️ Possível overhead de reflection em algumas situações&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;A escolha entre Records e Lombok não é uma questão de "melhor" ou "pior", mas sim de &lt;strong&gt;adequação ao contexto&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Records&lt;/strong&gt; brilham quando você precisa de semântica forte, imutabilidade e transparência&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lombok&lt;/strong&gt; excele quando você precisa de flexibilidade, mutabilidade e compatibilidade com versões antigas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A tendência é usar &lt;strong&gt;ambos estrategicamente&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Records para DTOs, objetos de valor e dados imutáveis&lt;/li&gt;
&lt;li&gt;Lombok para entidades complexas e modelos de negócio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com o Java evoluindo e mais projetos adotando versões recentes, Records estão se tornando a escolha padrão para muitos casos de uso. No entanto, Lombok continuará relevante para cenários que demandam máxima flexibilidade.&lt;/p&gt;

&lt;p&gt;A chave é entender que essas ferramentas resolvem problemas similares de maneiras diferentes, e a escolha certa depende das necessidades específicas do seu projeto, versão do Java e arquitetura da aplicação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências Bibliográficas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://medium.com/@umeshcapg/replace-some-lombok-features-with-record-in-java-17-a-modern-alternative-50b25aed3478" rel="noopener noreferrer"&gt;Replace Some Lombok Features with record in Java 17: A Modern Alternative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//Recommend%20Java%20records%20instead%20of%20Lombok%20for%20class-based%20projections."&gt;https://github.com/spring-projects/spring-data-commons/commit/959bde4d37b10342d963cf47d0bbf1b68000ff6a&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.toRecomenda%C3%A7%C3%A3o%20oficial%20do%20Spring%20Data"&gt;https://github.com/spring-projects/spring-data-commons/pull/2794&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.toRecords%20ou%20Lombok?%20Qual%20a%20melhor%20escolha%20para%20seu%20projeto%20Java?"&gt;https://medium.com/@fabio.alvaro/records-ou-lombok-qual-a-melhor-escolha-para-o-seu-projeto-java-b0d1fde468f2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.toJava%20Records%20vs%20JPA%20Entities%20and%20Lombok"&gt;https://javatechonline.com/java-records-vs-jpa-entities-and-lombok/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Por que Abandonar @Autowired em Campos e Adotar Injeção via Construtor</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Tue, 15 Jul 2025 00:55:48 +0000</pubDate>
      <link>https://dev.to/diegobrandao/por-que-abandonar-autowired-em-campos-e-adotar-injecao-via-construtor-5198</link>
      <guid>https://dev.to/diegobrandao/por-que-abandonar-autowired-em-campos-e-adotar-injecao-via-construtor-5198</guid>
      <description>&lt;p&gt;A injeção de dependência via construtor representa uma evolução natural das práticas de desenvolvimento com Spring Framework. Este documento apresenta os fundamentos técnicos que justificam essa transição e como implementá-la efetivamente em projetos modernos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contextualização
&lt;/h2&gt;

&lt;p&gt;O Spring Framework oferece três formas principais de injeção de dependência: por campo (field injection), por setter e por construtor. Embora a injeção por campo seja visualmente mais limpa e requeira menos código, ela apresenta limitações significativas que impactam a qualidade, manutenibilidade e robustez das aplicações.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principais Benefícios da Injeção via Construtor
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Transparência e Dependências Explícitas
&lt;/h3&gt;

&lt;p&gt;A injeção via construtor expõe claramente todas as dependências de uma classe em sua assinatura. Esta transparência facilita a compreensão do código, permitindo que desenvolvedores identifiquem rapidamente quais componentes uma classe necessita para funcionar corretamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo prático:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Injeção por campo - dependências ocultas&lt;/span&gt;
&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Dependências não são evidentes na assinatura da classe&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Injeção por construtor - dependências explícitas&lt;/span&gt;
&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emailService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;;&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;h3&gt;
  
  
  2. Testabilidade Aprimorada
&lt;/h3&gt;

&lt;p&gt;A injeção via construtor elimina a dependência do contexto Spring durante os testes unitários. As classes podem ser instanciadas diretamente, com mocks injetados como parâmetros do construtor, resultando em testes mais rápidos e independentes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vantagens nos testes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminação da necessidade de reflection&lt;/li&gt;
&lt;li&gt;Testes mais performáticos&lt;/li&gt;
&lt;li&gt;Maior simplicidade na configuração de mocks&lt;/li&gt;
&lt;li&gt;Independência do framework Spring nos testes unitários&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Princípio Fail-Fast
&lt;/h3&gt;

&lt;p&gt;A injeção por campo permite a criação de objetos mesmo quando dependências obrigatórias não estão disponíveis, resultando em &lt;code&gt;NullPointerException&lt;/code&gt; apenas durante a execução. A injeção via construtor impede a criação do objeto sem suas dependências, tornando problemas visíveis imediatamente durante a inicialização da aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Imutabilidade e Thread Safety
&lt;/h3&gt;

&lt;p&gt;Apenas através da injeção via construtor é possível definir campos de dependência como &lt;code&gt;final&lt;/code&gt;. Esta imutabilidade oferece:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Segurança de thread&lt;/strong&gt;: Campos final são thread-safe por natureza&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prevenção de efeitos colaterais&lt;/strong&gt;: Impossibilita modificações acidentais das dependências&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clareza conceitual&lt;/strong&gt;: Facilita o raciocínio sobre o estado dos objetos&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Detecção Precoce de Dependências Circulares
&lt;/h3&gt;

&lt;p&gt;Ciclos de dependência são detectados imediatamente durante a inicialização dos beans quando se utiliza injeção via construtor. Com injeção por campo, esses problemas podem permanecer ocultos até a execução específica do código afetado.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Incentivo ao Bom Design
&lt;/h3&gt;

&lt;p&gt;A injeção via construtor evidencia classes com muitas dependências, naturalmente incentivando a aplicação do &lt;strong&gt;Princípio da Responsabilidade Única (SRP)&lt;/strong&gt;. Construtores com muitos parâmetros sinalizam a necessidade de refatoração e decomposição de responsabilidades.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Alinhamento com Práticas Modernas do Spring
&lt;/h3&gt;

&lt;p&gt;Desde o Spring 4.3, o framework suporta injeção automática via construtor para classes com construtor único, dispensando a anotação &lt;code&gt;@Autowired&lt;/code&gt;. Esta é a abordagem oficialmente recomendada pela equipe do Spring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementação Prática
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Padrão Recomendado (Sem Lombok)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OrderRepository&lt;/span&gt; &lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="n"&gt;notificationService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;OrderService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderRepository&lt;/span&gt; &lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                       &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                       &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="n"&gt;notificationService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;paymentService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notificationService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notificationService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// métodos da classe...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Com Lombok (Quando Apropriado)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OrderRepository&lt;/span&gt; &lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="n"&gt;notificationService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// métodos da classe...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Estratégia de Migração
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Para Código Legado
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Priorização&lt;/strong&gt;: Inicie por classes críticas e com maior cobertura de testes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refatoração gradual&lt;/strong&gt;: Migre uma classe por vez para minimizar riscos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testes de regressão&lt;/strong&gt;: Garanta que a funcionalidade permanece inalterada&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validação&lt;/strong&gt;: Verifique se não há dependências circulares expostas&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Para Novos Desenvolvimentos
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Adote injeção via construtor como padrão desde o início&lt;/li&gt;
&lt;li&gt;Configure linters e ferramentas de análise estática para detectar uso de &lt;code&gt;@Autowired&lt;/code&gt; em campos&lt;/li&gt;
&lt;li&gt;Estabeleça como prática obrigatória em code reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Considerações Especiais
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dependências Opcionais
&lt;/h3&gt;

&lt;p&gt;Para dependências opcionais, utilize &lt;code&gt;@Autowired(required = false)&lt;/code&gt; no construtor ou considere padrões como Optional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                   &lt;span class="nd"&gt;@Autowired&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;CacheService&lt;/span&gt; &lt;span class="n"&gt;cacheService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cacheService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofNullable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cacheService&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;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;A injeção via construtor não apresenta overhead significativo em relação à injeção por campo. Os benefícios em qualidade e manutenibilidade superam amplamente qualquer diferença marginal de performance.&lt;/p&gt;

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

&lt;p&gt;A adoção da injeção via construtor representa um investimento na qualidade de longo prazo do código. Os benefícios em testabilidade, clareza, robustez e alinhamento com as melhores práticas do Spring justificam plenamente essa transição.&lt;/p&gt;

&lt;p&gt;Esta mudança não é apenas uma questão de preferência pessoal, mas uma evolução natural em direção a um código mais robusto, testável e maintível, alinhado com os princípios modernos de desenvolvimento de software.&lt;/p&gt;




&lt;h2&gt;
  
  
  Referências Bibliográficas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.baeldung.com/java-spring-field-injection-cons" rel="noopener noreferrer"&gt;Why Field Injection is Not Recommended - Baeldung&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@umeshcapg/why-spring-developers-prefers-constructor-injection-vs-3816f3972d71" rel="noopener noreferrer"&gt;Why Spring Developers Prefer Constructor Injection - Umesh Kumar Yadav&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@mesfandiari77/a-deep-dive-into-why-autowired-can-harm-your-spring-application-77481ffb9574" rel="noopener noreferrer"&gt;A Deep Dive Into Why @Autowired Can Harm Your Spring Application - MEsfandiari&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@himanshu675/stop-using-autowired-in-spring-heres-why-it-s-doing-more-harm-than-good-e0399a9ac292" rel="noopener noreferrer"&gt;Stop Using @Autowired in Spring - Himanshu&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@kariapratham/why-you-should-stop-using-autowired-in-spring-7b2335e0e6cf" rel="noopener noreferrer"&gt;Why You Should Stop Using @Autowired in Spring - Pratham Karia&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/@dulanjayasandaruwan1998/spring-doesnt-recommend-autowired-anymore-05fc05309dad" rel="noopener noreferrer"&gt;Spring Doesn't Recommend @Autowired Anymore - Dulan Jaya Sandaruwan&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Maratona de Testes Automatizados — Step 1: Testes Unitários</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Sun, 08 Jun 2025 16:55:13 +0000</pubDate>
      <link>https://dev.to/diegobrandao/maratona-de-testes-automatizados-step-1-testes-unitarios-1kee</link>
      <guid>https://dev.to/diegobrandao/maratona-de-testes-automatizados-step-1-testes-unitarios-1kee</guid>
      <description>&lt;h1&gt;
  
  
  Maratona de Testes em Java: Da Teoria à Prática
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 1: Testes Unitários - A Base Sólida da Pirâmide de Testes
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Por que testes unitários são fundamentais?&lt;/li&gt;
&lt;li&gt;O que realmente define um teste unitário?&lt;/li&gt;
&lt;li&gt;O que exatamente devemos testar?&lt;/li&gt;
&lt;li&gt;Estruturando seus testes com clareza&lt;/li&gt;
&lt;li&gt;As ferramentas do ofício: JUnit e Mockito&lt;/li&gt;
&lt;li&gt;Exemplo completo: Testando um Controller REST&lt;/li&gt;
&lt;li&gt;Solitary vs. Sociable: Duas abordagens&lt;/li&gt;
&lt;li&gt;DRY vs. DAMP nos testes&lt;/li&gt;
&lt;li&gt;Evitando armadilhas comuns&lt;/li&gt;
&lt;li&gt;Práticas avançadas e técnicas eficazes&lt;/li&gt;
&lt;li&gt;Integração Contínua&lt;/li&gt;
&lt;li&gt;Lições finais&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;li&gt;Recursos recomendados&lt;/li&gt;
&lt;li&gt;Referências Bibliográficas&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Por que testes unitários são fundamentais?
&lt;/h3&gt;

&lt;p&gt;Testes unitários são como os alicerces de um edifício: invisíveis para o usuário final, mas absolutamente essenciais para a integridade e sustentação de todo o sistema. Eles são a base da "Pirâmide de Testes", um conceito desenvolvido por Mike Cohn que organiza os testes em camadas de diferentes granularidades, indicando também quantos testes devemos ter em cada uma dessas camadas.&lt;/p&gt;

&lt;p&gt;No artigo "The Practical Test Pyramid", Ham Vocke destaca que "seus testes unitários serão muito rápidos. Em uma máquina razoável, você poderá rodar milhares deles em poucos minutos." Esta velocidade é crucial para o desenvolvimento ágil, permitindo que você obtenha feedback praticamente instantâneo sobre suas alterações de código.&lt;/p&gt;

&lt;h3&gt;
  
  
  O que realmente define um teste unitário?
&lt;/h3&gt;

&lt;p&gt;Um teste unitário eficaz possui estas características essenciais:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Característica&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;th&gt;Por quê isso importa&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;⚡ Rápido&lt;/td&gt;
&lt;td&gt;Executa em milissegundos&lt;/td&gt;
&lt;td&gt;Permite feedback imediato durante o desenvolvimento&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧩 Isolado&lt;/td&gt;
&lt;td&gt;Sem dependência externa (rede, banco, disco)&lt;/td&gt;
&lt;td&gt;Evita falhas por causas externas à unidade testada&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔄 Determinístico&lt;/td&gt;
&lt;td&gt;Sempre produz o mesmo resultado&lt;/td&gt;
&lt;td&gt;Elimina testes "flaky" (instáveis)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🎯 Focado&lt;/td&gt;
&lt;td&gt;Verifica uma única lógica ou comportamento&lt;/td&gt;
&lt;td&gt;Facilita identificar exatamente o que falhou&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📖 Legível&lt;/td&gt;
&lt;td&gt;Clara separação entre cenário e verificação&lt;/td&gt;
&lt;td&gt;Permite manutenção e entendimento a longo prazo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Como Ham Vocke menciona, "teste pequenas partes da sua base de código em isolamento e evite acessar bancos de dados, o sistema de arquivos ou fazer requisições HTTP." Este isolamento é o que torna os testes unitários verdadeiramente "unitários".&lt;/p&gt;

&lt;h3&gt;
  
  
  O que exatamente devemos testar?
&lt;/h3&gt;

&lt;p&gt;Segundo Vocke, "você pode escrever testes unitários para todas as classes do seu código de produção, independentemente da funcionalidade delas." Isso significa que quase tudo pode e deve ser testado unitariamente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Classes de domínio&lt;/strong&gt; com regras de negócio&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Controllers&lt;/strong&gt; (testar mapeamentos e respostas)&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Services&lt;/strong&gt; (testar fluxos e orquestrações)&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Repositórios&lt;/strong&gt; com lógica própria&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Utils, validators, formatters&lt;/strong&gt; (funções de propósito específico)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O importante é focar no &lt;em&gt;comportamento observável&lt;/em&gt; da unidade, não em sua implementação interna. Como Vocke recomenda, devemos "testar para o comportamento observável em vez de refletir a estrutura interna do código em nossos testes."&lt;/p&gt;

&lt;h3&gt;
  
  
  Estruturando seus testes com clareza
&lt;/h3&gt;

&lt;p&gt;Ham Vocke destaca duas formas eficazes de estruturar testes, que ele chama de "uma boa estrutura para todos os seus testes":&lt;/p&gt;

&lt;h4&gt;
  
  
  📐 1. Arrange → Act → Assert
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveCalcularValorTotalComDesconto&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange - Prepara o cenário&lt;/span&gt;
    &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Notebook"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"João"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VIP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Act - Executa a ação&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;valorFinal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculadoraPreco&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Assert - Verifica o resultado&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1800.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valorFinal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.001&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;h4&gt;
  
  
  💬 2. Given → When → Then (estilo BDD)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;clienteVipDeveReceberDescontoEspecial&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Given - Dado um cliente VIP e um produto&lt;/span&gt;
    &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Maria"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VIP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Smartphone"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// When - Quando calcular o preço final&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;valorFinal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculadoraPreco&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Then - Então deve aplicar 10% de desconto&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;900.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valorFinal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.001&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;Vocke sugere que este padrão "pode ser aplicado a outros testes de nível mais alto também. Em todos os casos, eles garantem que seus testes permaneçam fáceis e consistentes de ler."&lt;/p&gt;

&lt;h3&gt;
  
  
  As ferramentas do ofício: JUnit e Mockito
&lt;/h3&gt;

&lt;h4&gt;
  
  
  JUnit 5
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.BeforeEach&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.DisplayName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;junit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jupiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.*;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculadoraTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Calculadora&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@BeforeEach&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;calc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Calculadora&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Soma de dois números positivos"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveSomarDoisNumerosPositivos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Act&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;somar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Divisão por zero deve lançar exceção"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveLancarExcecaoAoDividirPorZero&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Assert + Act (verificando exceção)&lt;/span&gt;
        &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ArithmeticException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dividir&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&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;h4&gt;
  
  
  Mockito
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.extension.ExtendWith&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.mockito.InjectMocks&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.mockito.Mock&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.mockito.junit.jupiter.MockitoExtension&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mockito&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Mockito&lt;/span&gt;&lt;span class="o"&gt;.*;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;junit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jupiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.*;&lt;/span&gt;

&lt;span class="nd"&gt;@ExtendWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockitoExtension&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PedidoServiceTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mock&lt;/span&gt;
    &lt;span class="nc"&gt;DescontoService&lt;/span&gt; &lt;span class="n"&gt;descontoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Mock&lt;/span&gt;
    &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@InjectMocks&lt;/span&gt;
    &lt;span class="nc"&gt;PedidoService&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveAplicarDescontoAoFinalizarPedido&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pedido&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;descontoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcularDesconto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Act&lt;/span&gt;
        &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;finalizarPedido&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValorTotal&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;enviarConfirmacao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;);&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;h3&gt;
  
  
  Exemplo completo: Testando um Controller REST
&lt;/h3&gt;

&lt;p&gt;Vamos ver um exemplo prático de como testar um controller REST em Spring Boot:&lt;/p&gt;

&lt;h4&gt;
  
  
  O Controller em produção
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/produtos"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProdutoController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ProdutoService&lt;/span&gt; &lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProdutoController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProdutoService&lt;/span&gt; &lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;produtoService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="nc"&gt;Long&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buscarPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProdutoDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notFound&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;criar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nc"&gt;ProdutoRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;criar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPreco&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;created&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/produtos/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProdutoDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;));&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;h4&gt;
  
  
  Teste unitário com MockMVC
&lt;/h4&gt;

&lt;p&gt;Ham Vocke explica que ferramentas como MockMVC são importantes porque "Spring MVC's controller faz uso intensivo de anotações para declarar em quais caminhos eles estão escutando, quais verbos HTTP usar, quais parâmetros eles analisam do caminho da URL ou parâmetros de consulta e assim por diante. Simplesmente invocar um método do controller em seus testes unitários não testará todas essas coisas cruciais."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ExtendWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockitoExtension&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProdutoControllerTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;MockMvc&lt;/span&gt; &lt;span class="n"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Mock&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;ProdutoService&lt;/span&gt; &lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@InjectMocks&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;ProdutoController&lt;/span&gt; &lt;span class="n"&gt;produtoController&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@BeforeEach&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;mockMvc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MockMvcBuilders&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;standaloneSetup&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoController&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveRetornarProdutoQuandoExistir&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Teclado Mecânico"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;350.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buscarPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Act &amp;amp; Assert&lt;/span&gt;
        &lt;span class="n"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/produtos/1"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isOk&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.nome"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Teclado Mecânico"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.preco"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;350.0&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveRetornarNotFoundQuandoProdutoNaoExistir&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buscarPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;99L&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// Act &amp;amp; Assert&lt;/span&gt;
        &lt;span class="n"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/produtos/99"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isNotFound&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveCriarNovoProduto&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produtoParaSalvar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mouse"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;89.9&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produtoSalvo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mouse"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;89.9&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;produtoSalvo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;criar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoSalvo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Act &amp;amp; Assert&lt;/span&gt;
        &lt;span class="n"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/produtos"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{\"nome\":\"Mouse\",\"preco\":89.9}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isCreated&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Location"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/api/produtos/42"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.nome"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mouse"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.preco"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;89.9&lt;/span&gt;&lt;span class="o"&gt;));&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;h3&gt;
  
  
  Solitary vs. Sociable: Duas abordagens para testes unitários
&lt;/h3&gt;

&lt;p&gt;Segundo Vocke, "alguns argumentam que todos os colaboradores da sua unidade sob teste devem ser substituídos por mocks ou stubs", enquanto "outros argumentam que apenas colaboradores que são lentos ou têm efeitos colaterais maiores deveriam ser substituídos por stubs ou mocks."&lt;/p&gt;

&lt;p&gt;Este conceito foi criado por Jay Fields em seu livro "Working Effectively with Unit Tests", que cunhou os termos "testes unitários solitários" para testes que substituem todos os colaboradores, e "testes unitários sociáveis" para testes que permitem interações com colaboradores reais.&lt;/p&gt;

&lt;p&gt;Ham Vocke confessa: "Eu me vejo usando ambas as abordagens o tempo todo. Se se torna estranho usar colaboradores reais, usarei mocks e stubs generosamente. Se eu sentir que envolver o colaborador real me dá mais confiança em um teste, apenas faço stub das partes mais externas do meu serviço."&lt;/p&gt;

&lt;h4&gt;
  
  
  Exemplo de teste solitário (com mocks)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveCalcularImpostoSobreVendaComMocks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valorBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1000.00"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Mockando todas as dependências&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aliquotaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buscarAliquota&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SP"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.18"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;descontoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcularDesconto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorBase&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"100.00"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Act&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;imposto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculadoraImpostoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorBase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SP"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Assert&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"162.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;imposto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// (1000 - 100) * 0.18&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Exemplo de teste sociável (com colaboradores reais)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveCalcularImpostoSobreVendaComColaboradoresReais&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valorBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1000.00"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Usando implementação real do serviço de desconto&lt;/span&gt;
    &lt;span class="nc"&gt;DescontoService&lt;/span&gt; &lt;span class="n"&gt;descontoServiceReal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DescontoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Ainda mockando o serviço de alíquota (externo)&lt;/span&gt;
    &lt;span class="nc"&gt;AliquotaService&lt;/span&gt; &lt;span class="n"&gt;aliquotaMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AliquotaService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aliquotaMock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buscarAliquota&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SP"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.18"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Injetando uma mistura de dependências reais e mockadas&lt;/span&gt;
    &lt;span class="nc"&gt;CalculadoraImpostoService&lt;/span&gt; &lt;span class="n"&gt;calculadora&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CalculadoraImpostoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;descontoServiceReal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aliquotaMock&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Act&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;imposto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculadora&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorBase&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SP"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Assert&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"180.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;imposto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Considerando que o desconto real é 0&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  DRY vs. DAMP nos testes: Equilibrando clareza e repetição
&lt;/h3&gt;

&lt;p&gt;Ham Vocke alerta: "Não tente ser excessivamente DRY (Don't Repeat Yourself). Duplicação é aceitável se melhorar a legibilidade."&lt;/p&gt;

&lt;p&gt;Em testes, muitas vezes é melhor priorizar a clareza em vez da não-repetição. Um acrônimo útil para recordar é DAMP: &lt;strong&gt;D&lt;/strong&gt;escriptive &lt;strong&gt;A&lt;/strong&gt;nd &lt;strong&gt;M&lt;/strong&gt;eaningful &lt;strong&gt;P&lt;/strong&gt;hrases.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exemplo questionável (muito DRY):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Definição central, reusada em todos os testes&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produtoPadrao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@BeforeEach&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;clienteVip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"João"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VIP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;produtoPadrao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Item"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveAplicarDescontoVipEmProduto&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;calculadoraPreco&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoPadrao&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveIncluirFreteGratisPara&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;beneficioService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;temFreteGratis&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clienteVip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;produtoPadrao&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;h4&gt;
  
  
  Exemplo melhor (mais DAMP):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveAplicarDescontoVipEmProduto&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange - Dados específicos para este teste&lt;/span&gt;
    &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"João"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VIP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;notebook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Notebook"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Act&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;valorComDesconto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculadoraPreco&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notebook&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Assert - Expectativa clara&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1800.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valorComDesconto&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                &lt;span class="s"&gt;"Cliente VIP deve receber 10% de desconto"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveIncluirFreteGratisPara&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange - Dados específicos para este teste&lt;/span&gt;
    &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteVip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Maria"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VIP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;smartTV&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Smart TV"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1500.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Act&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;temFreteGratis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;beneficioService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;temFreteGratis&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clienteVip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;smartTV&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Assert - Expectativa clara&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temFreteGratis&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
              &lt;span class="s"&gt;"Cliente VIP deve ter frete grátis independente do produto"&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;h3&gt;
  
  
  Evitando armadilhas comuns
&lt;/h3&gt;

&lt;h4&gt;
  
  
  "Mas eu preciso testar este método privado!"
&lt;/h4&gt;

&lt;p&gt;Ham Vocke alerta: "Se você já se encontrou em uma situação em que realmente precisa testar um método privado, você deve dar um passo atrás e se perguntar por quê." Ele continua: "Estou bastante certo de que isso é mais um problema de design do que um problema de escopo."&lt;/p&gt;

&lt;p&gt;Quando você sente essa necessidade, geralmente há um problema de design da classe — ela provavelmente está fazendo muitas coisas e violando o princípio da responsabilidade única.&lt;/p&gt;

&lt;p&gt;A solução mais elegante:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Antes: Classe grande com método privado complexo&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FaturamentoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// lógica...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;calcularImpostos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorBase&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// método privado complexo&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;calcularImpostos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// lógica complexa de cálculo de impostos&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Depois: Extrair para uma classe dedicada com interface pública&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FaturamentoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ImpostoCalculator&lt;/span&gt; &lt;span class="n"&gt;impostoCalculator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FaturamentoService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ImpostoCalculator&lt;/span&gt; &lt;span class="n"&gt;impostoCalculator&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;impostoCalculator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;impostoCalculator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// lógica...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;impostoCalculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorBase&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Agora é público!&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImpostoCalculator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// mesma lógica complexa, agora testável&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;h4&gt;
  
  
  "Preciso ter 100% de cobertura!"
&lt;/h4&gt;

&lt;p&gt;Vocke argumenta contra testar código trivial: "Sim, você deve testar a interface pública. Mais importante, no entanto, você não testa código trivial. Não se preocupe, Kent Beck disse que tudo bem. Você não ganhará nada testando getters ou setters simples ou outras implementações triviais."&lt;/p&gt;

&lt;p&gt;Focar em cobertura por si só pode levar a testes ruins que não adicionam valor. Busque qualidade em vez de quantidade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Práticas avançadas e técnicas eficazes
&lt;/h3&gt;

&lt;p&gt;À medida que você ganha experiência em testes unitários, algumas técnicas avançadas podem ajudar a tornar seus testes mais elegantes, legíveis e fáceis de manter. Vejamos três técnicas importantes que podem elevar significativamente a qualidade da sua suite de testes.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Dados de teste expressivos
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;O que é:&lt;/strong&gt; Métodos de fábrica (factory methods) ou objetos builders que criam dados de teste com nomes semânticos, em vez de usar configurações inline de objetos diretamente nos testes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quando usar:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quando os objetos de teste têm muitas propriedades que precisam ser configuradas&lt;/li&gt;
&lt;li&gt;Quando você repete a mesma configuração de objetos em vários testes&lt;/li&gt;
&lt;li&gt;Quando a configuração obscurece a intenção principal do teste&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefícios:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Foco no "o quê" está sendo testado, não no "como" os objetos são criados&lt;/li&gt;
&lt;li&gt;Leitura mais natural - o nome do método descreve o cenário&lt;/li&gt;
&lt;li&gt;Encapsulamento de detalhes irrelevantes para a intenção do teste&lt;/li&gt;
&lt;li&gt;Fácil reutilização entre testes similares
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ruim: Dados aleatórios desconexos&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveAprovarCreditoParaClienteBomPagador&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"X123"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setScoreCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRendaMensal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;aprovado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;creditoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;analisarCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aprovado&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Melhor: Nome do método de fábrica expressivo&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveAprovarCreditoParaClienteBomPagador&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteBomPagador&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;criarClienteComBomHistoricoCredito&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;aprovado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;creditoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;analisarCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clienteBomPagador&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aprovado&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="nf"&gt;criarClienteComBomHistoricoCredito&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Maria"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setScoreCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRendaMensal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cliente&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;Você também pode evoluir para padrões mais sofisticados como builders fluentes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Usando um builder expressivo&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveAprovarCreditoParaClienteBomPagador&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteBomPagador&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClienteBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;padrao&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comBomHistoricoCredito&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comRendaAdequada&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;aprovado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;creditoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;analisarCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clienteBomPagador&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aprovado&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;h4&gt;
  
  
  2. Assertion libraries expressivas
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;O que são:&lt;/strong&gt; Bibliotecas que oferecem uma sintaxe mais fluente e legível para verificações, substituindo os métodos padrão do JUnit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quando usar:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Para verificações complexas ou múltiplas em um único objeto&lt;/li&gt;
&lt;li&gt;Quando se deseja uma leitura mais próxima da linguagem natural&lt;/li&gt;
&lt;li&gt;Para verificações de coleções, onde se quer verificar múltiplos aspectos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bibliotecas populares:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AssertJ: fluente e orientada a objetos&lt;/li&gt;
&lt;li&gt;Hamcrest: baseada em matchers&lt;/li&gt;
&lt;li&gt;Truth (Google): alternativa simples e expressiva&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefícios:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testes mais legíveis, quase como frases em inglês&lt;/li&gt;
&lt;li&gt;Mensagens de erro mais descritivas quando falham&lt;/li&gt;
&lt;li&gt;Encadeamento de verificações reduz duplicação&lt;/li&gt;
&lt;li&gt;Maior expressividade para casos complexos
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// JUnit padrão - Funcionais mas menos expressivas&lt;/span&gt;
&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lista&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lista&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"item1"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAtivo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// AssertJ - Mais fluente e expressivo&lt;/span&gt;
&lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lista&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"item1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doesNotContain&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"item99"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAtivo&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isTrue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando um teste falha, a mensagem de erro com AssertJ é mais informativa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected size:&amp;lt;3&amp;gt; but was:&amp;lt;2&amp;gt;
Expected to contain:&amp;lt;"item1"&amp;gt; but did not
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Testes parametrizados para casos similares
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;O que são:&lt;/strong&gt; Testes que executam o mesmo código com diferentes entradas e expectativas de saída, gerando automaticamente múltiplos casos de teste a partir de uma única definição.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quando usar:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Para testar múltiplas variações de um mesmo caso (comportamento com diferentes entradas)&lt;/li&gt;
&lt;li&gt;Para regras de negócio que têm muitos casos específicos (ex: cálculos tributários)&lt;/li&gt;
&lt;li&gt;Quando a lógica é a mesma, mas os dados variam&lt;/li&gt;
&lt;li&gt;Para evitar duplicação de código em testes semelhantes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefícios:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redução drástica de código duplicado&lt;/li&gt;
&lt;li&gt;Facilidade para adicionar novos casos de teste&lt;/li&gt;
&lt;li&gt;Documentação clara de todos os casos suportados&lt;/li&gt;
&lt;li&gt;Facilita identificar quais casos específicos falharam
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ParameterizedTest&lt;/span&gt;
&lt;span class="nd"&gt;@CsvSource&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt;
    &lt;span class="s"&gt;"SP, 0.18"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"RJ, 0.20"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"MG, 0.17"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"RS, 0.17"&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deveCalcularImpostoCorretoPorEstado&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;estado&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;aliquotaEsperada&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
    &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Genérico"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Act&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;aliquota&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;impostoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;obterAliquota&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;estado&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Assert&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aliquotaEsperada&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aliquota&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;O JUnit 5 suporta múltiplas fontes de dados para testes parametrizados:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@ValueSource&lt;/code&gt;: para listas simples de valores (&lt;code&gt;@ValueSource(ints = {1, 2, 3})&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@CsvSource&lt;/code&gt;: para pares ou tuplas de valores como mostrado acima&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@EnumSource&lt;/code&gt;: para testar com valores de um enum&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@MethodSource&lt;/code&gt;: para casos complexos onde os dados são gerados por um método&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@ArgumentsSource&lt;/code&gt;: para implementações personalizadas de geradores de dados&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essas técnicas avançadas são particularmente úteis quando sua base de código cresce e você precisa manter um conjunto grande de testes. Elas ajudam a reduzir a duplicação, melhorar a legibilidade e facilitar a manutenção a longo prazo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integração Contínua: Executando testes unitários automaticamente
&lt;/h3&gt;

&lt;p&gt;Os testes unitários devem ser executados:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Localmente&lt;/strong&gt; antes de commit/push&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Na CI&lt;/strong&gt; em cada push para qualquer branch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Antes de merge&lt;/strong&gt; para branches principais&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este feedback rápido é possível graças à velocidade dos testes unitários.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lições finais
&lt;/h3&gt;

&lt;p&gt;Ham Vocke resume bem: "Uma vez que você pegar o jeito de escrever testes unitários, você se tornará cada vez mais fluente em escrevê-los. Substitua colaboradores externos por stubs, configure alguns dados de entrada, chame seu assunto sob teste e verifique se o valor retornado é o que você esperava."&lt;/p&gt;

&lt;p&gt;Testes unitários são um investimento que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⏱️ Economiza tempo a longo prazo&lt;/li&gt;
&lt;li&gt;🔒 Permite refatorações com segurança&lt;/li&gt;
&lt;li&gt;📚 Documenta o comportamento esperado&lt;/li&gt;
&lt;li&gt;💻 Melhora o design do código&lt;/li&gt;
&lt;li&gt;🧠 Reduz a carga cognitiva ao desenvolver&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Como resumido no artigo de referência: "O código de teste é tão importante quanto o código de produção. Dê a ele o mesmo nível de cuidado e atenção. 'Isso é apenas código de teste' não é uma desculpa válida para justificar código desleixado."&lt;/p&gt;

&lt;p&gt;Ao dominar a arte dos testes unitários, você estabelece a base sólida para construir um sistema robusto e confiável, que pode evoluir com segurança ao longo do tempo.&lt;/p&gt;

&lt;p&gt;No próximo passo da nossa maratona, abordaremos testes de integração - a camada intermediária da pirâmide de testes que verifica como seus componentes trabalham juntos.&lt;/p&gt;




&lt;h3&gt;
  
  
  Recursos recomendados
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;📕 "Working Effectively with Unit Tests" por Jay Fields&lt;/li&gt;
&lt;li&gt;📗 "Test Driven Development: By Example" por Kent Beck&lt;/li&gt;
&lt;li&gt;📘 "Clean Code" por Robert C. Martin (capítulo sobre testes)&lt;/li&gt;
&lt;li&gt;🌐 Documentação oficial do JUnit 5&lt;/li&gt;
&lt;li&gt;🌐 Documentação oficial do Mockito&lt;/li&gt;
&lt;li&gt;🌐 Documentação oficial do AssertJ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Referências Bibliográficas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Vocke, Ham. (2018). "The Practical Test Pyramid". &lt;em&gt;Martin Fowler&lt;/em&gt;. Disponível em: &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html" rel="noopener noreferrer"&gt;https://martinfowler.com/articles/practical-test-pyramid.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cohn, Mike. (2009). "Succeeding with Agile: Software Development Using Scrum". Addison-Wesley Professional.&lt;/li&gt;
&lt;li&gt;Fields, Jay. (2014). "Working Effectively with Unit Tests". Leanpub.&lt;/li&gt;
&lt;li&gt;Beck, Kent. (2002). "Test Driven Development: By Example". Addison-Wesley Professional.&lt;/li&gt;
&lt;li&gt;Martin, Robert C. (2008). "Clean Code: A Handbook of Agile Software Craftsmanship". Prentice Hall.&lt;/li&gt;
&lt;li&gt;Fowler, Martin. (2006). "Mocks Aren't Stubs". &lt;em&gt;MartinFowler.com&lt;/em&gt;. Disponível em: &lt;a href="https://martinfowler.com/articles/mocksArentStubs.html" rel="noopener noreferrer"&gt;https://martinfowler.com/articles/mocksArentStubs.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Spring Framework Documentation. "Testing". Disponível em: &lt;a href="https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html" rel="noopener noreferrer"&gt;https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;JUnit 5 User Guide. Disponível em: &lt;a href="https://junit.org/junit5/docs/current/user-guide/" rel="noopener noreferrer"&gt;https://junit.org/junit5/docs/current/user-guide/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Mockito Reference Documentation. Disponível em: &lt;a href="https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html" rel="noopener noreferrer"&gt;https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AssertJ Documentation. Disponível em: &lt;a href="https://assertj.github.io/doc/" rel="noopener noreferrer"&gt;https://assertj.github.io/doc/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>testing</category>
    </item>
    <item>
      <title>Maratona de Testes Automatizados — Step 0: Fundamentos, Importância e a Pirâmide de Testes</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Tue, 06 May 2025 02:55:38 +0000</pubDate>
      <link>https://dev.to/diegobrandao/maratona-de-testes-automatizados-step-0-fundamentos-importancia-e-a-piramide-de-testes-3i6n</link>
      <guid>https://dev.to/diegobrandao/maratona-de-testes-automatizados-step-0-fundamentos-importancia-e-a-piramide-de-testes-3i6n</guid>
      <description>&lt;h2&gt;
  
  
  Step 0: Fundamentos, Importância e a Pirâmide de Testes
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Por que testamos software?&lt;/li&gt;
&lt;li&gt;Entendendo a Pirâmide de Testes&lt;/li&gt;
&lt;li&gt;O Anti-padrão: O Sorvete de Testes&lt;/li&gt;
&lt;li&gt;Duplicação Inteligente vs. Duplicação Desnecessária&lt;/li&gt;
&lt;li&gt;DRY vs. DAMP em Testes&lt;/li&gt;
&lt;li&gt;Testes de Caixa Branca vs. Caixa Preta&lt;/li&gt;
&lt;li&gt;Princípios Essenciais para Todos os Níveis&lt;/li&gt;
&lt;li&gt;O que vem a seguir?&lt;/li&gt;
&lt;li&gt;Referências Bibliográficas&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Por que testamos software?
&lt;/h3&gt;

&lt;p&gt;Testar software transcende a simples busca por defeitos — é fundamentalmente um ato de &lt;strong&gt;construir confiança&lt;/strong&gt;. Testes automatizados proporcionam a liberdade de evoluir o código sem receio, realizar refatorações profundas, validar integrações complexas, e entregar continuamente com a segurança de um sistema verificado.&lt;/p&gt;

&lt;p&gt;Como Ham Vocke observa no artigo "The Practical Test Pyramid":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Automating your repetitive tests can be a big game changer in your life as a software developer. Automate these tests and you no longer have to mindlessly follow click protocols in order to check if your software still works correctly. Automate your tests and you can change your codebase without batting an eye."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Automatizar seus testes repetitivos pode ser um grande divisor de águas na sua vida como desenvolvedor de software. Automatize esses testes e você não precisará mais seguir protocolos de cliques sem pensar para verificar se seu software ainda funciona corretamente. Automatize seus testes e você poderá mudar sua base de código sem piscar."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A automação de testes é transformadora precisamente porque liberta desenvolvedores de tarefas repetitivas e tediosas, convertendo-as em verificações automáticas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Testes manuais → Repetitivos → Tediosos → Propensos a erros → Lentos
Testes automatizados → Consistentes → Confiáveis → Rápidos → Confortantes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O impacto disso vai além da qualidade do software; reflete diretamente na qualidade de vida do desenvolvedor e na dinâmica das equipes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entendendo a Pirâmide de Testes
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Pirâmide de Testes&lt;/strong&gt; (Test Pyramid) foi introduzida por &lt;strong&gt;Mike Cohn&lt;/strong&gt; em seu livro &lt;em&gt;Succeeding with Agile&lt;/em&gt;. Trata-se de uma metáfora visual poderosa que orienta a construção de uma suíte de testes balanceada, rápida e sustentável a longo prazo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkncykfgi8417hgvcxih3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkncykfgi8417hgvcxih3.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A pirâmide nos comunica dois conceitos fundamentais:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Diferentes níveis de granularidade&lt;/strong&gt;: Os testes são agrupados em categorias que variam de escopo, desde pequenos métodos isolados até o sistema completo integrado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Distribuição ideal&lt;/strong&gt;: Quanto mais subimos na pirâmide, menor deve ser a quantidade de testes, seguindo o princípio de "muitos testes rápidos e baratos na base, poucos testes caros e lentos no topo".&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Como Ham Vocke explica:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Write lots of small and fast unit tests. Write some more coarse-grained tests and very few high-level tests that test your application from end to end."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Escreva muitos testes unitários pequenos e rápidos. Escreva alguns testes mais abrangentes e muito poucos testes de alto nível que testem sua aplicação de ponta a ponta."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A estrutura contemporânea da pirâmide consiste em:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Nível&lt;/th&gt;
&lt;th&gt;Tipo de Teste&lt;/th&gt;
&lt;th&gt;Características&lt;/th&gt;
&lt;th&gt;Quantidade&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Base&lt;/td&gt;
&lt;td&gt;Testes Unitários&lt;/td&gt;
&lt;td&gt;Rápidos, isolados, confiáveis&lt;/td&gt;
&lt;td&gt;Muitos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Meio&lt;/td&gt;
&lt;td&gt;Testes de Integração&lt;/td&gt;
&lt;td&gt;Verificam comunicação entre componentes&lt;/td&gt;
&lt;td&gt;Moderada&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Topo&lt;/td&gt;
&lt;td&gt;Testes E2E/UI&lt;/td&gt;
&lt;td&gt;Simulam comportamento do usuário&lt;/td&gt;
&lt;td&gt;Poucos&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Esta distribuição não é acidental — reflete o equilíbrio econômico entre &lt;strong&gt;velocidade de feedback&lt;/strong&gt;, &lt;strong&gt;cobertura de cenários&lt;/strong&gt; e &lt;strong&gt;custo de manutenção&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nota sobre a Evolução da Pirâmide de Testes
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Esta seção complementa o entendimento sobre a Pirâmide de Testes, explicando sua evolução histórica.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É importante destacar que a Pirâmide de Testes que apresentamos neste artigo representa uma versão mais contemporânea e refinada do conceito original introduzido por Mike Cohn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Pirâmide Original de Cohn (2009)&lt;/strong&gt; consistia em três camadas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Base&lt;/strong&gt;: Testes Unitários (Unit Tests)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meio&lt;/strong&gt;: Testes de Serviço (Service Tests)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Topo&lt;/strong&gt;: Testes de Interface do Usuário (UI Tests)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkeuawovx25ut86oxnyv2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkeuawovx25ut86oxnyv2.png" alt=" " width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O termo "Service Tests" usado por Cohn era um tanto ambíguo e causou confusão na comunidade de desenvolvimento. Ele se referia a testes que verificavam a funcionalidade sem passar pela interface do usuário, mas que podiam envolver múltiplos componentes ou módulos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Pirâmide Moderna&lt;/strong&gt; que apresentamos evoluiu para oferecer maior clareza e se adaptar às práticas atuais de desenvolvimento:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Base&lt;/strong&gt;: Testes Unitários (Unit Tests)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meio&lt;/strong&gt;: Testes de Integração (Integration Tests)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Topo&lt;/strong&gt;: Testes E2E/UI (End-to-End/UI Tests)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Por que a mudança?
&lt;/h3&gt;

&lt;p&gt;Esta evolução não foi apenas uma questão de terminologia, mas reflete mudanças fundamentais nas práticas de desenvolvimento:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maior granularidade&lt;/strong&gt;: A camada intermediária agora é geralmente subdividida para acomodar diferentes tipos de integrações (API, componentes, contratos).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Arquiteturas distribuídas&lt;/strong&gt;: Com a popularização de microsserviços e sistemas distribuídos, o conceito de "Service Tests" se tornou insuficiente para capturar a complexidade das integrações modernas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DevOps e CI/CD&lt;/strong&gt;: A automação completa de pipelines de entrega contínua demandou uma categorização mais precisa dos testes para otimizar velocidade e eficiência.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Práticas ágeis maduras&lt;/strong&gt;: A experiência acumulada nas últimas décadas permitiu refinar o modelo para melhor servir aos fluxos de trabalho modernos.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Martin Fowler e outros influentes profissionais da área contribuíram para esta evolução, resultando em uma pirâmide mais detalhada e adaptada às necessidades contemporâneas de desenvolvimento de software.&lt;/p&gt;

&lt;p&gt;A essência da metáfora original de Cohn permanece intacta: muitos testes rápidos na base, poucos testes lentos no topo. O refinamento da pirâmide representa nossa compreensão mais sofisticada de como implementar este princípio em contextos diversos e complexos.&lt;/p&gt;

&lt;h3&gt;
  
  
  O Anti-padrão: O Sorvete de Testes
&lt;/h3&gt;

&lt;p&gt;Enquanto a pirâmide aponta para a estabilidade e eficiência, seu anti-padrão é o &lt;strong&gt;"Sorvete de Testes"&lt;/strong&gt; (Test Ice Cream Cone), termo cunhado por &lt;strong&gt;Alberto Savoia&lt;/strong&gt; e popularizado por &lt;strong&gt;Martin Fowler&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvbmgm7zxcvdok8tg6ev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvbmgm7zxcvdok8tg6ev.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No sorvete de testes, a distribuição é invertida:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A base (testes unitários) é pequena ou inexistente&lt;/li&gt;
&lt;li&gt;O meio (integração) é moderado&lt;/li&gt;
&lt;li&gt;O topo (UI/E2E) é excessivamente volumoso&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ham Vocke alerta:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Watch out that you don't end up with a test ice-cream cone that will be a nightmare to maintain and takes way too long to run."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Tenha cuidado para não acabar com um sorvete de testes que será um pesadelo para manter e demorará muito tempo para executar."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As consequências desta distorção são severas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Feedback lento&lt;/strong&gt;: O ciclo de desenvolvimento se torna arrastado&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnóstico difícil&lt;/strong&gt;: Falhas são complexas de isolar e corrigir&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fragilidade&lt;/strong&gt;: Pequenas mudanças causam falhas em cascata&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alto custo&lt;/strong&gt;: A manutenção consome recursos desproporcionais&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A regra prática é: quanto mais alto o teste na pirâmide, maior o custo de manutenção, tempo de execução e propensão a falhas intermitentes ("flaky tests").&lt;/p&gt;

&lt;h3&gt;
  
  
  Duplicação Inteligente vs. Duplicação Desnecessária
&lt;/h3&gt;

&lt;p&gt;Um equívoco comum é assumir que qualquer forma de duplicação de cobertura de testes é inaceitável. Ham Vocke apresenta uma visão mais equilibrada sobre este tema:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If a higher-level test gives you more confidence that your application works correctly, you should have it. Writing a unit test for a Controller class helps to test the logic within the Controller itself. Still, this won't tell you whether the REST endpoint this Controller provides actually responds to HTTP requests."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Se um teste de nível superior lhe dá mais confiança de que sua aplicação funciona corretamente, você deve tê-lo. Escrever um teste unitário para uma classe Controller ajuda a testar a lógica dentro do Controller em si. Ainda assim, isso não dirá se o endpoint REST que este Controller fornece realmente responde a requisições HTTP."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Existem dois tipos de duplicação em testes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Duplicação inteligente&lt;/strong&gt;: Testa o mesmo comportamento, mas sob perspectivas diferentes e complementares:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teste unitário: valida a lógica interna&lt;/li&gt;
&lt;li&gt;Teste de integração: valida a comunicação entre componentes&lt;/li&gt;
&lt;li&gt;Teste E2E: valida o fluxo completo sob a perspectiva do usuário&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Duplicação desnecessária&lt;/strong&gt;: Testa exatamente o mesmo aspecto em múltiplos níveis, sem valor agregado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repetir todos os casos de borda e condicionais em todos os níveis da pirâmide&lt;/li&gt;
&lt;li&gt;Duplicar testes de validação em múltiplas camadas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ham Vocke recomenda:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If you have tested all conditions confidently on a lower-level test, there's no need to keep a higher-level test in your test suite."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Se você testou todas as condições com confiança em um teste de nível inferior, não há necessidade de manter um teste de nível superior em sua suíte de testes."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Isto nos leva a duas regras práticas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Se um teste de nível superior encontra um erro e não há teste de nível inferior falhando, &lt;strong&gt;você precisa escrever um teste de nível inferior&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Priorize a implementação de testes nos &lt;strong&gt;níveis mais baixos da pirâmide, sempre que possível.&lt;/strong&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  DRY vs. DAMP em Testes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DRY (Don't Repeat Yourself)&lt;/strong&gt; é um princípio fundamental da engenharia de software, mas em testes, existe uma tensão com outro princípio: &lt;strong&gt;DAMP (Descriptive And Meaningful Phrases)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ham Vocke observa:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Don't try to be overly DRY. Duplication is okay, if it improves readability. Try to find a balance between DRY and DAMP code."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Não tente ser excessivamente DRY. Duplicação é aceitável, se melhorar a legibilidade. Tente encontrar um equilíbrio entre código DRY e DAMP."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Esta visão reflete uma maturidade na abordagem dos testes automatizados:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Princípio&lt;/th&gt;
&lt;th&gt;Foco&lt;/th&gt;
&lt;th&gt;Benefício&lt;/th&gt;
&lt;th&gt;Riscos se usado em excesso&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DRY&lt;/td&gt;
&lt;td&gt;Evitar redundância&lt;/td&gt;
&lt;td&gt;Facilidade de manutenção&lt;/td&gt;
&lt;td&gt;Testes interdependentes e frágeis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DAMP&lt;/td&gt;
&lt;td&gt;Clareza e intenção&lt;/td&gt;
&lt;td&gt;Testes auto-documentados&lt;/td&gt;
&lt;td&gt;Admite certa repetição, desde que contribua para a clareza&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Em testes, clareza é frequentemente mais valiosa que concisão extrema, pois testes são lidos não apenas por quem os escreveu, mas por desenvolvedores investigando falhas ou entendendo o comportamento esperado do sistema.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testes de Caixa Branca vs. Caixa Preta
&lt;/h3&gt;

&lt;p&gt;Para compreender melhor os diferentes níveis da pirâmide, é útil relacioná-los com dois paradigmas clássicos de teste:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testes de Caixa Branca (White Box)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilizam conhecimento da estrutura interna do código&lt;/li&gt;
&lt;li&gt;Testam caminhos de execução, cobertura de branches, lógica interna&lt;/li&gt;
&lt;li&gt;Focam em "como" o sistema implementa comportamentos&lt;/li&gt;
&lt;li&gt;Predominantes em: &lt;strong&gt;testes unitários&lt;/strong&gt; e &lt;strong&gt;testes de integração&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Testes de Caixa Preta (Black Box)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tratam o sistema como uma "caixa fechada"&lt;/li&gt;
&lt;li&gt;Testam apenas as interfaces públicas e o comportamento observável&lt;/li&gt;
&lt;li&gt;Focam em "o que" o sistema faz, não em como faz&lt;/li&gt;
&lt;li&gt;Predominantes em: &lt;strong&gt;testes E2E&lt;/strong&gt; e &lt;strong&gt;testes de aceitação&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Existe também uma abordagem híbrida:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testes de Caixa Cinza (Grey Box)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Combinam conhecimento da estrutura interna com teste via interfaces externas&lt;/li&gt;
&lt;li&gt;Usam conhecimento do design para testar de forma mais eficiente&lt;/li&gt;
&lt;li&gt;Comuns em: &lt;strong&gt;testes de integração&lt;/strong&gt; e &lt;strong&gt;testes de API&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Nível da Pirâmide&lt;/th&gt;
&lt;th&gt;Tipo&lt;/th&gt;
&lt;th&gt;Abordagem Predominante&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Base&lt;/td&gt;
&lt;td&gt;Unitários&lt;/td&gt;
&lt;td&gt;Caixa Branca&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Meio&lt;/td&gt;
&lt;td&gt;Integração/Contratos&lt;/td&gt;
&lt;td&gt;Caixa Cinza&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Topo&lt;/td&gt;
&lt;td&gt;UI, E2E, Aceitação&lt;/td&gt;
&lt;td&gt;Caixa Preta&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Princípios Essenciais para Todos os Níveis
&lt;/h3&gt;

&lt;p&gt;Independentemente do nível da pirâmide, alguns princípios fundamentais devem ser observados:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Teste comportamento, não implementação&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Foque no "o quê", não no "como"&lt;/li&gt;
&lt;li&gt;Isso permite refatoração sem quebrar testes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;"Test for observable behavior instead." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Teste o comportamento observável, em vez disso." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Código de teste é código de produção&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Aplique as mesmas práticas de qualidade&lt;/li&gt;
&lt;li&gt;Refatore e mantenha limpo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;"Test code is as important as production code. Give it the same level of care and attention." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"O código de teste é tão importante quanto o código de produção. Dê a ele o mesmo nível de cuidado e atenção." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Estruture claramente&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Use padrão "Arrange-Act-Assert" ou "Given-When-Then"&lt;/li&gt;
&lt;li&gt;Mantenha o teste focado em um único aspecto&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;"A good structure for all your tests is this one: Set up the test data, Call your method under test, Assert that the expected results are returned." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Uma boa estrutura para todos os seus testes é esta: Configure os dados de teste, Chame seu método sob teste, Verifique que os resultados esperados são retornados." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Priorize feedback rápido&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Coloque testes rápidos nos primeiros estágios do pipeline&lt;/li&gt;
&lt;li&gt;Testes lentos em estágios posteriores&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;"A good build pipeline tells you that you messed up as quick as possible." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Um bom pipeline de build informa que você errou o mais rápido possível." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Evite duplicação desnecessária&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Se já está bem testado em nível mais baixo, um teste mais alto deve focar em novos aspectos&lt;/li&gt;
&lt;li&gt;Seja implacável eliminando testes que não agregam valor&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;"I delete high-level tests that are already covered on a lower level (given they don't provide extra value)." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tradução:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Eu excluo testes de alto nível que já estão cobertos em um nível inferior (desde que não forneçam valor adicional)." - Ham Vocke&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  O que vem a seguir?
&lt;/h3&gt;

&lt;p&gt;No &lt;strong&gt;Step 1&lt;/strong&gt; da nossa maratona, mergulharemos a fundo na base da pirâmide: os &lt;strong&gt;testes unitários&lt;/strong&gt;. Exploraremos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A definição precisa de uma "unidade" de teste&lt;/li&gt;
&lt;li&gt;A diferença entre testes "sociáveis" e "solitários"&lt;/li&gt;
&lt;li&gt;O uso eficaz de Mocks e Stubs&lt;/li&gt;
&lt;li&gt;A estruturação ideal de testes unitários&lt;/li&gt;
&lt;li&gt;Exemplos práticos em Java utilizando JUnit e Mockito&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prepare-se para construir uma base sólida que permitirá que seu código evolua com segurança e confiança!&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências Bibliográficas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Vocke, Ham. (2018). "The Practical Test Pyramid". &lt;em&gt;Martin Fowler&lt;/em&gt;. Disponível em: &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html" rel="noopener noreferrer"&gt;https://martinfowler.com/articles/practical-test-pyramid.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cohn, Mike. (2009). "Succeeding with Agile: Software Development Using Scrum". Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fowler, Martin. (2012). "Test Pyramid". &lt;em&gt;MartinFowler.com&lt;/em&gt;. Disponível em: &lt;a href="https://martinfowler.com/bliki/TestPyramid.html" rel="noopener noreferrer"&gt;https://martinfowler.com/bliki/TestPyramid.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Freeman, Steve; Pryce, Nat. (2009). "Growing Object-Oriented Software, Guided by Tests". Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Meszaros, Gerard. (2007). "xUnit Test Patterns: Refactoring Test Code". Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Khorikov, Vladimir. (2020). "Unit Testing: Principles, Practices, and Patterns". Manning Publications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Osherove, Roy. (2013). "The Art of Unit Testing: With Examples in .NET". Manning Publications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Beck, Kent. (2002). "Test Driven Development: By Example". Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fields, Jay. (2014). "Working Effectively with Unit Tests". Leanpub.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Savoia, Alberto. (2011). "The Way of Testivus". Disponível em: &lt;a href="https://www.artima.com/weblogs/viewpost.jsp?thread=203994" rel="noopener noreferrer"&gt;https://www.artima.com/weblogs/viewpost.jsp?thread=203994&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>testing</category>
    </item>
    <item>
      <title>A Arte da Simplicidade no Desenvolvimento de Software: DRY, KISS, YAGNI e TDA</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Wed, 30 Apr 2025 22:59:33 +0000</pubDate>
      <link>https://dev.to/diegobrandao/a-arte-da-simplicidade-no-desenvolvimento-de-software-dry-kiss-yagni-e-tda-aak</link>
      <guid>https://dev.to/diegobrandao/a-arte-da-simplicidade-no-desenvolvimento-de-software-dry-kiss-yagni-e-tda-aak</guid>
      <description>&lt;p&gt;&lt;em&gt;"A simplicidade é o último grau de sofisticação."&lt;/em&gt; - Leonardo da Vinci&lt;/p&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introdução&lt;/li&gt;
&lt;li&gt;O que são Princípios de Desenvolvimento de Software?&lt;/li&gt;
&lt;li&gt;Por que seguir Princípios de Desenvolvimento é importante?&lt;/li&gt;
&lt;li&gt;DRY - Don't Repeat Yourself (Não Se Repita)&lt;/li&gt;
&lt;li&gt;DRY e o Padrão Factory&lt;/li&gt;
&lt;li&gt;KISS - Keep It Simple, Stupid (Mantenha Simples, Estúpido)&lt;/li&gt;
&lt;li&gt;YAGNI - You Aren't Gonna Need It (Você Não Vai Precisar Disso)&lt;/li&gt;
&lt;li&gt;TDA - Tell, Don't Ask (Diga, Não Pergunte)&lt;/li&gt;
&lt;li&gt;TDA e a Lei de Demeter&lt;/li&gt;
&lt;li&gt;Críticas e Limitações dos Princípios&lt;/li&gt;
&lt;li&gt;Integrando os Princípios em seu Desenvolvimento&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;li&gt;Referências Bibliográficas&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;No cenário atual do desenvolvimento de software, onde a complexidade dos sistemas cresce exponencialmente, a busca por clareza e simplicidade tornou-se uma necessidade fundamental. Desenvolvedores experientes reconhecem que código complicado não é sinônimo de código sofisticado - pelo contrário, a verdadeira elegância reside na simplicidade.&lt;/p&gt;

&lt;p&gt;Este artigo explora quatro princípios fundamentais que transformaram o desenvolvimento de software: DRY (Don't Repeat Yourself), KISS (Keep It Simple, Stupid), YAGNI (You Aren't Gonna Need It) e TDA (Tell, Don't Ask). Estes princípios não são apenas técnicas isoladas, mas filosofias de design que, quando aplicadas corretamente, resultam em código mais limpo, manutenível e, paradoxalmente, mais poderoso.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que são Princípios de Desenvolvimento de Software?
&lt;/h2&gt;

&lt;p&gt;Princípios de desenvolvimento de software são diretrizes conceituais que orientam as decisões de design e implementação durante o processo de criação de software. Diferentemente de padrões de design específicos ou frameworks, estes princípios transcendem linguagens de programação e paradigmas, servindo como uma bússola para navegação no vasto campo de possibilidades do desenvolvimento de software.&lt;/p&gt;

&lt;p&gt;Estes princípios representam o conhecimento acumulado ao longo de décadas pela comunidade global de desenvolvimento, capturando lições frequentemente aprendidas da maneira mais difícil: através de projetos malsucedidos, manutenções onerosas e bugs persistentes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que seguir Princípios de Desenvolvimento é importante?
&lt;/h2&gt;

&lt;p&gt;A importância de seguir princípios de desenvolvimento transcende preferências estéticas de código. Considere as seguintes vantagens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redução de custos a longo prazo&lt;/strong&gt;: Sistemas bem projetados são consideravelmente mais econômicos para manter e estender.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Escalabilidade&lt;/strong&gt;: Código que segue princípios sólidos adapta-se melhor ao crescimento da aplicação.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Facilidade de colaboração&lt;/strong&gt;: Princípios compartilhados estabelecem uma linguagem comum entre desenvolvedores.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resiliência&lt;/strong&gt;: Sistemas bem projetados respondem melhor a mudanças nas especificações.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Qualidade perceptível&lt;/strong&gt;: Usuários finais identificam indiretamente a qualidade do design através da confiabilidade e responsividade do sistema.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Examinemos agora os quatro princípios que são o foco deste artigo, explorando sua origem, aplicação e impacto.&lt;/p&gt;

&lt;h2&gt;
  
  
  DRY - Don't Repeat Yourself (Não Se Repita)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Origem e História
&lt;/h3&gt;

&lt;p&gt;O princípio DRY foi formulado por Andy Hunt e Dave Thomas em seu influente livro "The Pragmatic Programmer", publicado em 1999. A definição original é direta e poderosa: "Todo conhecimento deve ter uma representação única, inequívoca e autoritativa dentro de um sistema."&lt;/p&gt;

&lt;p&gt;Embora Hunt e Thomas tenham cunhado o termo, o conceito de evitar repetição em código já era uma prática valorizada anteriormente. O mérito deles foi articular e formalizar este conhecimento tácito que já circulava entre desenvolvedores experientes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que é importante?
&lt;/h3&gt;

&lt;p&gt;A importância do DRY reside em sua capacidade de reduzir significativamente a dívida técnica. Quando o mesmo código ou lógica é repetido em múltiplos lugares, qualquer alteração necessária deve ser implementada em todos esses locais. Inevitavelmente, alguns desses pontos serão esquecidos, resultando em inconsistências e bugs difíceis de rastrear.&lt;/p&gt;

&lt;p&gt;Além disso, o DRY:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduz o tamanho do código, facilitando sua compreensão&lt;/li&gt;
&lt;li&gt;Concentra a lógica em locais específicos, facilitando otimizações&lt;/li&gt;
&lt;li&gt;Melhora a coesão do código, agrupando funcionalidades relacionadas&lt;/li&gt;
&lt;li&gt;Minimiza a ocorrência de erros durante atualizações e manutenções&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exemplos Práticos em Java
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sem aplicar o princípio DRY:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProdutoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ProdutoRepository&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProdutoService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProdutoRepository&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;produtoRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;        
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="nf"&gt;buscarProdutoPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&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="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RecursoNaoEncontradoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Produto não encontrado"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="n"&gt;responseDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDescricao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDescricao&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPreco&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPreco&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCategoria&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDisponivel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisponivel&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarTodosProdutos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;responseDTOs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="n"&gt;responseDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDescricao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDescricao&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPreco&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPreco&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCategoria&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDisponivel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisponivel&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTOs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;responseDTOs&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarProdutosPorCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;categoria&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;categoria&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;responseDTOs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="n"&gt;responseDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDescricao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDescricao&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPreco&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPreco&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCategoria&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDisponivel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisponivel&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;responseDTOs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;responseDTOs&lt;/span&gt;&lt;span class="o"&gt;;&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;&lt;strong&gt;Aplicando o princípio DRY:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProdutoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ProdutoRepository&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProdutoService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProdutoRepository&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;produtoRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;        
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="nf"&gt;buscarProdutoPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&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="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RecursoNaoEncontradoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Produto não encontrado"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;converterParaDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarTodosProdutos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;converterParaDTO&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarProdutosPorCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;categoria&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;categoria&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;converterParaDTO&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="nf"&gt;converterParaDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="n"&gt;responseDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDescricao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDescricao&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPreco&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPreco&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCategoria&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDisponivel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisponivel&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;responseDTO&lt;/span&gt;&lt;span class="o"&gt;;&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;Na versão DRY, extraímos a lógica de conversão da entidade para DTO em um método separado &lt;code&gt;converterParaDTO()&lt;/code&gt;, que é reutilizado em todos os métodos que precisam dessa funcionalidade. Se a estrutura do DTO mudar ou se novos campos forem adicionados, precisamos alterar apenas esse método, não todos os lugares onde a conversão é feita.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aplicando o princípio DRY com MapStruct:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uma maneira ainda mais elegante de aplicar o princípio DRY para mapeamento entre objetos é utilizando a biblioteca MapStruct. Esta abordagem elimina completamente a necessidade de escrever código de mapeamento manual, reduzindo ainda mais a duplicação e o potencial para erros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Definir a interface do mapper&lt;/span&gt;
&lt;span class="nd"&gt;@Mapper&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;componentModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"spring"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ProdutoMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="nf"&gt;toDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toDTOList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Refatorar o serviço para usar o mapper&lt;/span&gt;
&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProdutoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ProdutoRepository&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ProdutoMapper&lt;/span&gt; &lt;span class="n"&gt;produtoMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProdutoService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProdutoRepository&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ProdutoMapper&lt;/span&gt; &lt;span class="n"&gt;produtoMapper&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;produtoRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;produtoMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt; &lt;span class="nf"&gt;buscarProdutoPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&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="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RecursoNaoEncontradoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Produto não encontrado"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produtoMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarTodosProdutos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produtoMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDTOList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtos&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProdutoResponseDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarProdutosPorCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;categoria&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Produto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;produtos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByCategoria&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;categoria&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produtoMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDTOList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtos&lt;/span&gt;&lt;span class="o"&gt;);&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;O MapStruct gera automaticamente a implementação da interface &lt;code&gt;ProdutoMapper&lt;/code&gt; durante o processo de compilação, eliminando toda a duplicação de código de mapeamento. Se a estrutura do DTO ou da entidade mudar, basta atualizar a interface do mapper e a implementação será regenerada automaticamente.&lt;/p&gt;

&lt;p&gt;Esta abordagem oferece várias vantagens sobre o mapeamento manual:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Elimina completamente o código repetitivo&lt;/strong&gt;: Não precisamos escrever nenhum código de mapeamento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alta performance&lt;/strong&gt;: O código gerado pelo MapStruct é muito eficiente, similar ao que escreveríamos manualmente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menos propensão a erros&lt;/strong&gt;: Se novos campos forem adicionados à entidade ou ao DTO, o compilador gerará avisos se o mapeamento não estiver completo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configurações avançadas&lt;/strong&gt;: MapStruct oferece suporte a mapeamentos complexos, conversões personalizadas e herança.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este é um exemplo perfeito da aplicação do princípio DRY levado ao seu máximo potencial, onde eliminamos não apenas a duplicação direta, mas também a necessidade de escrever código repetitivo em primeiro lugar.&lt;/p&gt;

&lt;h2&gt;
  
  
  DRY e o Padrão Factory
&lt;/h2&gt;

&lt;p&gt;É importante destacar a relação sinérgica entre o princípio DRY e o padrão de design Factory. O padrão Factory é um dos padrões de criação mais utilizados na programação orientada a objetos e apresenta particular afinidade com o princípio DRY.&lt;/p&gt;

&lt;p&gt;Quando aplicamos DRY para eliminar duplicação de código relacionado à criação de objetos complexos, frequentemente implementamos alguma variação do padrão Factory. Observe o exemplo com um cenário típico de API REST:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sem Factory (violando DRY):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/v1/pedidos"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PedidoController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PedidoService&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PedidoController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PedidoService&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pedidoService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;        
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PedidoDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;criarPedido&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;PedidoRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Criação do cliente manualmente&lt;/span&gt;
        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClienteId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTipoCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoCliente&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PREMIUM&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoCliente&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&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="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;REGULAR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoCliente&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// NOVO&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;criarPedido&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convertToDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/v1/clientes"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClienteController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ClienteService&lt;/span&gt; &lt;span class="n"&gt;clienteService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ClienteController&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClienteService&lt;/span&gt; &lt;span class="n"&gt;clienteService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clienteService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;        
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ClienteDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;cadastrarCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;ClienteRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Criação do cliente manualmente (duplicação de código)&lt;/span&gt;
        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTipoCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoCliente&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PREMIUM&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoCliente&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&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="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;REGULAR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoCliente&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// NOVO&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteSalvo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;salvarCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convertToDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clienteSalvo&lt;/span&gt;&lt;span class="o"&gt;));&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;&lt;strong&gt;Com Factory (aplicando DRY):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Factory para criação de clientes&lt;/span&gt;
&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClienteFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="nf"&gt;criarCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tipoClienteStr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;TipoCliente&lt;/span&gt; &lt;span class="n"&gt;tipoCliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tipoClienteStr&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTipoCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tipoCliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Configuração baseada no tipo de cliente&lt;/span&gt;
  &lt;span class="cm"&gt;/*       
   * Estou utilizando neste exemplo o switch case do Java 21,
   * que introduz a sintaxe moderna com "-&amp;gt;", mais legível e concisa.
 */&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tipoCliente&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;PREMIUM&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configurarClientePremium&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;REGULAR&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configurarClienteRegular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;NOVO&lt;/span&gt;    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configurarClienteNovo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="nf"&gt;criarCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClienteRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="nc"&gt;TipoCliente&lt;/span&gt; &lt;span class="n"&gt;tipoCliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TipoCliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoCliente&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTipoCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tipoCliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Configuração baseada no tipo de cliente&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tipoCliente&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;PREMIUM&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configurarClientePremium&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;REGULAR&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configurarClienteRegular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;NOVO&lt;/span&gt;    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;configurarClienteNovo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configurarClientePremium&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configurarClienteRegular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configurarClienteNovo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBeneficioFrete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrazoEntregaDias&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usando a Factory nos controllers&lt;/span&gt;
&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/v1/pedidos"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PedidoController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PedidoService&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ClienteFactory&lt;/span&gt; &lt;span class="n"&gt;clienteFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PedidoController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PedidoService&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                            &lt;span class="nc"&gt;ClienteFactory&lt;/span&gt; &lt;span class="n"&gt;clienteFactory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pedidoService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clienteFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PedidoDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;criarPedido&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;PedidoRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;


        &lt;span class="c1"&gt;// Criação do cliente através da factory&lt;/span&gt;
        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;criarCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClienteId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; 
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoCliente&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedidoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;criarPedido&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convertToDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/v1/clientes"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClienteController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ClienteService&lt;/span&gt; &lt;span class="n"&gt;clienteService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;    
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ClienteFactory&lt;/span&gt; &lt;span class="n"&gt;clienteFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ClienteController&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClienteService&lt;/span&gt;  &lt;span class="n"&gt;clienteService&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                              &lt;span class="nc"&gt;ClienteFactory&lt;/span&gt; &lt;span class="n"&gt;clienteFactory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clienteService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clienteFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ClienteDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;cadastrarCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;ClienteRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;


        &lt;span class="c1"&gt;// Criação do cliente através da factory&lt;/span&gt;
        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;criarCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;clienteSalvo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;salvarCliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convertToDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clienteSalvo&lt;/span&gt;&lt;span class="o"&gt;));&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;Este padrão não apenas elimina a duplicação, mas também centraliza a lógica de criação e configuração de clientes, facilitando futuras modificações e manutenção. Se as regras de negócio para um tipo específico de cliente mudarem, apenas os métodos relevantes na factory precisarão ser atualizados, em vez de buscar e alterar essa lógica em múltiplos controllers e serviços.&lt;/p&gt;

&lt;h2&gt;
  
  
  KISS - Keep It Simple, Stupid (Mantenha Simples, Estúpido)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Origem e História
&lt;/h3&gt;

&lt;p&gt;O princípio KISS tem uma origem interessante no campo da engenharia aeroespacial. Foi atribuído a Kelly Johnson, engenheiro da Lockheed Skunk Works, responsável pelo design de aeronaves como o U-2 e o SR-71 Blackbird durante as décadas de 1960 e 1970. Johnson instruía seus engenheiros que seus sistemas deveriam ser simples o suficiente para serem reparados por um mecânico comum em condições de campo com ferramentas básicas.&lt;/p&gt;

&lt;p&gt;O acrônimo "Keep It Simple, Stupid" foi posteriormente adotado pela Marinha dos EUA em 1960. O conceito rapidamente transcendeu o contexto militar e encontrou aplicação em diversas áreas, incluindo o desenvolvimento de software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que é importante?
&lt;/h3&gt;

&lt;p&gt;A importância do KISS no desenvolvimento de software é multifacetada:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manutenibilidade&lt;/strong&gt;: Código simples é mais fácil de entender e modificar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Depuração&lt;/strong&gt;: Soluções simples apresentam menor superfície para bugs potenciais.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integração de novos desenvolvedores&lt;/strong&gt;: Profissionais recém-chegados ao projeto conseguem compreender e contribuir para o código mais rapidamente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Desempenho&lt;/strong&gt;: Soluções simples frequentemente apresentam melhor desempenho que alternativas complexas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adaptabilidade&lt;/strong&gt;: Sistemas simples geralmente respondem melhor a novos requisitos.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Exemplos Práticos em Java
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sem aplicar o princípio KISS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidadorEmailService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;    

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UsuarioRepository&lt;/span&gt; &lt;span class="n"&gt;usuarioRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;    
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;EmailBlacklistRepository&lt;/span&gt; &lt;span class="n"&gt;blacklistRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;    
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ConfiguracoesService&lt;/span&gt; &lt;span class="n"&gt;configuracoesService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ValidadorEmailService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;UsuarioRepository&lt;/span&gt; &lt;span class="n"&gt;usuarioRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;EmailBlacklistRepository&lt;/span&gt; &lt;span class="n"&gt;blacklistRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;ConfiguracoesService&lt;/span&gt; &lt;span class="n"&gt;configuracoesService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;usuarioRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usuarioRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blacklistRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;blacklistRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configuracoesService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuracoesService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="nf"&gt;validarEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&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;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificação 1: Email não pode ser nulo ou vazio&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_EMPTY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Email não pode ser vazio"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificação 2: Formato básico do email&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_INVALID_FORMAT"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Email deve conter @"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificação 3: Validação estrutural detalhada&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;partes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;partes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_INVALID_STRUCTURE"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Email deve ter exatamente uma parte local e uma parte de domínio"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;localPart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;partes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;domainPart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;partes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localPart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_LOCAL_PART_EMPTY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Parte local do email não pode ser vazia"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domainPart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_DOMAIN_EMPTY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Domínio do email não pode ser vazio"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;domainPart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_INVALID_DOMAIN"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Domínio deve ter pelo menos um ponto"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;domainParts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;domainPart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\\."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;domainParts&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_INVALID_DOMAIN_PART"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Partes do domínio não podem ser vazias"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificação 4: Verificação de caracteres permitidos&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;allowedCharsLocal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_+"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;localPart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toCharArray&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allowedCharsLocal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;indexOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_INVALID_CHAR_LOCAL"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Caractere não permitido na parte local: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;allowedCharsDomain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;domainPart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toCharArray&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allowedCharsDomain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;indexOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_INVALID_CHAR_DOMAIN"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Caractere não permitido no domínio: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificação 5: Regras de negócio específicas&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blacklistRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmailDomainBlacklisted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domainPart&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_DOMAIN_BLACKLISTED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Domínio não permitido"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuarioRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;existsByEmail&lt;/span&gt;&lt;span class="o"&gt;(&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;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;configuracoesService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmailUniqueRequired&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_ALREADY_EXISTS"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Email já cadastrado"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Se chegou até aqui, o email é válido&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&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;&lt;strong&gt;Aplicando o princípio KISS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidadorEmailService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UsuarioRepository&lt;/span&gt; &lt;span class="n"&gt;usuarioRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;EmailBlacklistRepository&lt;/span&gt; &lt;span class="n"&gt;blacklistRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ConfiguracoesService&lt;/span&gt; &lt;span class="n"&gt;configuracoesService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ValidadorEmailService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UsuarioRepository&lt;/span&gt; &lt;span class="n"&gt;usuarioRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;EmailBlacklistRepository&lt;/span&gt; &lt;span class="n"&gt;blacklistRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;ConfiguracoesService&lt;/span&gt; &lt;span class="n"&gt;configuracoesService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;usuarioRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usuarioRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blacklistRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;blacklistRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configuracoesService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuracoesService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Expressão regular para validação de email seguindo RFC 5322&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="no"&gt;EMAIL_PATTERN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^[a-zA-Z0-9_+&amp;amp;*-]+(?:\\.[a-zA-Z0-9_+&amp;amp;*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="nf"&gt;validarEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&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;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificação 1: Email não pode ser nulo ou vazio&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_EMPTY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Email não pode ser vazio"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificação 2: Formato do email usando regex&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="no"&gt;EMAIL_PATTERN&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_INVALID_FORMAT"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Formato de email inválido"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificação 3: Regras de negócio específicas&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;dominio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lastIndexOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'@'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blacklistRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmailDomainBlacklisted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dominio&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_DOMAIN_BLACKLISTED"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Domínio não permitido"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuarioRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;existsByEmail&lt;/span&gt;&lt;span class="o"&gt;(&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;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;configuracoesService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmailUniqueRequired&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_ALREADY_EXISTS"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Email já cadastrado"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Se chegou até aqui, o email é válido&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&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;Na versão KISS, utilizamos uma expressão regular padronizada para validar o formato do email, em vez de implementar manualmente todas as verificações estruturais. Isso torna o código significativamente mais curto, mais legível e menos propenso a erros, enquanto mantém todas as regras de negócio necessárias.&lt;/p&gt;

&lt;p&gt;Aplicando o princípio KISS com expressão regular e Apache Commons Lang3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.commons.lang3.StringUtils&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidadorEmailService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt; &lt;span class="no"&gt;EMAIL_PATTERN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^[a-zA-Z0-9_+&amp;amp;*-]+(?:\\.[a-zA-Z0-9_+&amp;amp;*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="nf"&gt;validarEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&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;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Utilização do StringUtils.isBlank() da Apache Commons Lang3&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StringUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBlank&lt;/span&gt;&lt;span class="o"&gt;(&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;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_EMPTY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Email não pode ser vazio"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Validação de formato com regex&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="no"&gt;EMAIL_PATTERN&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMAIL_INVALID_FORMAT"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Formato de email inválido"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Demais regras de negócio...&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&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;Por que isso é KISS?&lt;/p&gt;

&lt;p&gt;Ao usar o método StringUtils.isBlank() da biblioteca Apache Commons Lang3, encapsulamos a verificação de null, string vazia e espaços em branco em uma única chamada clara e descritiva. Isso reduz ruído, melhora a legibilidade e evita erros comuns em validações manuais.&lt;/p&gt;

&lt;p&gt;Essa abordagem exemplifica bem o princípio KISS — evitar reinventar a roda e utilizar ferramentas confiáveis para manter o código simples, expressivo e eficiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  YAGNI - You Aren't Gonna Need It (Você Não Vai Precisar Disso)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Origem e História
&lt;/h3&gt;

&lt;p&gt;O princípio YAGNI surgiu no contexto do Extreme Programming (XP), uma metodologia ágil de desenvolvimento de software formulada por Kent Beck no final dos anos 1990. O conceito central propõe que os desenvolvedores não devem adicionar funcionalidades até que sejam realmente necessárias, não apenas porque potencialmente poderiam ser úteis no futuro.&lt;/p&gt;

&lt;p&gt;YAGNI é um princípio contra-intuitivo para muitos desenvolvedores, pois contraria o instinto natural de planejar com antecedência e tentar antecipar necessidades futuras. No entanto, a experiência coletiva da indústria demonstrou que a maioria das funcionalidades projetadas para uso futuro nunca são efetivamente necessárias, ou são implementadas de forma diferente quando a necessidade real emerge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que é importante?
&lt;/h3&gt;

&lt;p&gt;A importância do YAGNI pode ser compreendida através de seus benefícios diretos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Foco em valor imediato&lt;/strong&gt;: Direciona os recursos para resolver problemas reais e atuais.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redução de complexidade&lt;/strong&gt;: Cada funcionalidade adicional aumenta a complexidade do sistema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Economia de recursos&lt;/strong&gt;: Tempo e energia são conservados ao evitar desenvolvimento desnecessário.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Design mais claro&lt;/strong&gt;: Sistemas projetados para resolver problemas reais tendem a apresentar designs mais coerentes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adaptabilidade&lt;/strong&gt;: É mais fácil adaptar um sistema simples a novos requisitos do que retrabalhar um sistema complexo.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Exemplos Práticos em Java
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sem aplicar o princípio YAGNI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuarios"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Usuario&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;senha&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Campos necessários atualmente&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;ativo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;dataCriacao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;ultimoLogin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Campos para funcionalidades futuras que "talvez" sejam necessárias&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;telefone&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;endereco&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;complemento&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cidade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;estado&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cep&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;dataNascimento&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;genero&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;fotoPerfil&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;biografia&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tokenResetSenha&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;dataExpiracaoToken&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;contaVerificada&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tokenVerificacao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;tentativasLogin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;bloqueado&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;dataBloqueio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;preferenciasNotificacao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;configuracaoPrivacidade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tipoUsuario&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt; &lt;span class="n"&gt;avaliacao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;numeroAvaliacoes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Relações que "podem ser úteis" no futuro&lt;/span&gt;
    &lt;span class="nd"&gt;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuario"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pedido&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuario"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Endereco&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;enderecos&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@ManyToMany&lt;/span&gt;
    &lt;span class="nd"&gt;@JoinTable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuarios_interesses"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;joinColumns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@JoinColumn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuario_id"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inverseJoinColumns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@JoinColumn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"interesse_id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Interesse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;interesses&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@ManyToMany&lt;/span&gt;
    &lt;span class="nd"&gt;@JoinTable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuarios_roles"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;joinColumns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@JoinColumn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuario_id"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inverseJoinColumns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@JoinColumn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"role_id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Role&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Getters e setters para TODOS os campos...&lt;/span&gt;
    &lt;span class="c1"&gt;// (métodos omitidos para brevidade)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/v1/usuarios"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsuarioController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UsuarioService&lt;/span&gt; &lt;span class="n"&gt;usuarioService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UsuarioController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UsuarioService&lt;/span&gt; &lt;span class="n"&gt;usuarioService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;usuarioService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usuarioService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarUsuario&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="nc"&gt;Long&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="nc"&gt;Usuario&lt;/span&gt; &lt;span class="n"&gt;usuario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usuarioService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buscarPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converterParaDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt; &lt;span class="nf"&gt;converterParaDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Usuario&lt;/span&gt; &lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Conversão com todos os campos possíveis&lt;/span&gt;
        &lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAtivo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAtivo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDataCriacao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDataCriacao&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUltimoLogin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUltimoLogin&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// Campos para funcionalidades futuras&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTelefone&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTelefone&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEndereco&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEndereco&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setComplemento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getComplemento&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCidade&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCidade&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEstado&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEstado&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCep&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDataNascimento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDataNascimento&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setGenero&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getGenero&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setFotoPerfil&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFotoPerfil&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBiografia&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBiografia&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setContaVerificada&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isContaVerificada&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBloqueado&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBloqueado&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTipoUsuario&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTipoUsuario&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAvaliacao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAvaliacao&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNumeroAvaliacoes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNumeroAvaliacoes&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// Relações&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPedidos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPedidos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPedidos&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;converterPedidoParaDTO&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEnderecos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEnderecos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEnderecos&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;converterEnderecoParaDTO&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;;&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;&lt;strong&gt;Aplicando o princípio YAGNI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"usuarios"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Usuario&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;senha&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Apenas campos necessários para os requisitos atuais&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;ativo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;dataCriacao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;ultimoLogin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Getters e setters apenas para os campos existentes&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&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;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&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;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getSenha&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;senha&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setSenha&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;senha&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;senha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;senha&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isAtivo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ativo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAtivo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;ativo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ativo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ativo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="nf"&gt;getDataCriacao&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dataCriacao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setDataCriacao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;dataCriacao&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dataCriacao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataCriacao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="nf"&gt;getUltimoLogin&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ultimoLogin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setUltimoLogin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;ultimoLogin&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ultimoLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ultimoLogin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/v1/usuarios"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsuarioController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UsuarioService&lt;/span&gt; &lt;span class="n"&gt;usuarioService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UsuarioController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UsuarioService&lt;/span&gt; &lt;span class="n"&gt;usuarioService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;usuarioService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usuarioService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{id}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarUsuario&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="nc"&gt;Long&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="nc"&gt;Usuario&lt;/span&gt; &lt;span class="n"&gt;usuario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usuarioService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buscarPorId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converterParaDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt; &lt;span class="nf"&gt;converterParaDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Usuario&lt;/span&gt; &lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Apenas os campos necessários atualmente&lt;/span&gt;
        &lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UsuarioDTO&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAtivo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAtivo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDataCriacao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDataCriacao&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUltimoLogin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUltimoLogin&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Apenas os métodos CRUD necessários...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na versão YAGNI, a entidade &lt;code&gt;Usuario&lt;/code&gt; e seu respectivo DTO contêm apenas os campos necessários para os requisitos atuais do sistema. Campos adicionais, relacionamentos e métodos que poderiam ser úteis no futuro foram eliminados. Isso resulta em um código mais limpo, mais fácil de entender e manter. Se futuramente houver necessidade de adicionar novos campos ou relacionamentos, eles podem ser incluídos quando a necessidade real surgir, evitando a complexidade desnecessária e o esforço de manutenção de código que pode nunca ser utilizado.&lt;/p&gt;

&lt;h2&gt;
  
  
  TDA - Tell, Don't Ask (Diga, Não Pergunte)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Origem e História
&lt;/h3&gt;

&lt;p&gt;O princípio "Tell, Don't Ask" foi popularizado por Andy Hunt e Dave Thomas (os mesmos autores de "The Pragmatic Programmer" que formalizaram o DRY). O conceito fundamental estabelece que objetos devem ser responsáveis por seu próprio comportamento, e o código cliente deve "dizer" a um objeto o que fazer, em vez de "perguntar" sobre seu estado interno e tomar decisões baseadas nessa informação.&lt;/p&gt;

&lt;p&gt;Este princípio é fundamentalmente relacionado à programação orientada a objetos e enfatiza o encapsulamento - o princípio de que os detalhes internos de um objeto devem ser ocultos do mundo exterior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que é importante?
&lt;/h3&gt;

&lt;p&gt;A importância do TDA manifesta-se em vários aspectos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Encapsulamento&lt;/strong&gt;: Mantém a lógica relacionada a dados específicos junto com esses dados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Coesão&lt;/strong&gt;: Resulta em classes mais coesas onde comportamentos relacionados estão agrupados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Desacoplamento&lt;/strong&gt;: Reduz o acoplamento entre componentes do sistema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manutenibilidade&lt;/strong&gt;: Mudanças em regras de negócio afetam apenas as classes responsáveis por essas regras.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testabilidade&lt;/strong&gt;: Classes que seguem TDA são geralmente mais fáceis de testar isoladamente.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Exemplos Práticos em Java
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sem aplicar o princípio TDA:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PedidoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PedidoRepository&lt;/span&gt; &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;        
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ClienteRepository&lt;/span&gt; &lt;span class="n"&gt;clienteRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;    
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ProdutoRepository&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;    
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PedidoService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PedidoRepository&lt;/span&gt; &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                        &lt;span class="nc"&gt;ClienteRepository&lt;/span&gt; &lt;span class="n"&gt;clienteRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;ProdutoRepository&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pedidoRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clienteRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clienteRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;produtoRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emailService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processarPagamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;pedidoId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedidoId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RecursoNaoEncontradoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pedido não encontrado"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCliente&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Valida disponibilidade dos produtos&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ItemPedido&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getItens&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProduto&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// Verifica se tem estoque suficiente&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEstoqueDisponivel&lt;/span&gt;&lt;span class="o"&gt;()&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;.&lt;/span&gt;&lt;span class="na"&gt;getQuantidade&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NegocioException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Produto "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" sem estoque suficiente"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Verifica limite do cliente para pagamento por crédito&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CREDITO"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;limiteDisponivel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSaldoUtilizado&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValorTotal&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limiteDisponivel&lt;/span&gt;&lt;span class="o"&gt;)&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="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NegocioException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cliente não possui limite de crédito suficiente"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Atualiza saldo utilizado do cliente&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSaldoUtilizado&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSaldoUtilizado&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValorTotal&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
            &lt;span class="n"&gt;clienteRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Atualiza status do pedido e processa pagamento&lt;/span&gt;
        &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StatusPedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PAGO&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setFormaPagamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDataPagamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// Reduz estoque dos produtos&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ItemPedido&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getItens&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProduto&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEstoqueDisponivel&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEstoqueDisponivel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getQuantidade&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;produtoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Envia email de confirmação&lt;/span&gt;
&lt;span class="c1"&gt;// Utilizando Text Block (Java 15+) para melhor legibilidade da mensagem&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""
    Seu pedido #%d no valor de R$ %.2f foi confirmado com sucesso.
    """&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formatted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValorTotal&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

&lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enviarEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Confirmação de Pagamento"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="o"&gt;);&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;&lt;strong&gt;Aplicando o princípio TDA:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PedidoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PedidoRepository&lt;/span&gt; &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;    
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PedidoService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PedidoRepository&lt;/span&gt; &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                         &lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pedidoRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emailService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processarPagamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;pedidoId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedidoId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RecursoNaoEncontradoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pedido não encontrado"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Validar disponibilidade de produtos&lt;/span&gt;
        &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validarDisponibilidadeProdutos&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Processar pagamento&lt;/span&gt;
        &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;pagamentoRealizado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processarPagamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;pagamentoRealizado&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NegocioException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Falha ao processar pagamento"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;pedidoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Enviar confirmação ao cliente&lt;/span&gt;
        &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enviarConfirmacao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@ManyToOne&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cascade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CascadeType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pedido"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ItemPedido&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;itens&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Enumerated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EnumType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STRING&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;StatusPedido&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;dataPagamento&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valorTotal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Outros campos e getters/setters&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validarDisponibilidadeProdutos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ItemPedido&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;itens&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validarDisponibilidade&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NegocioException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Produto "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProduto&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" sem estoque suficiente"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;processarPagamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Validar pagamento com base na forma escolhida&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CREDITO"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;temLimite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validarLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorTotal&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;temLimite&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;utilizarCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorTotal&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Atualizar status e data&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StatusPedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PAGO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formaPagamento&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dataPagamento&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Atualizar estoque&lt;/span&gt;
        &lt;span class="n"&gt;itens&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;ItemPedido:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;atualizarEstoque&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;enviarConfirmacao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EmailService&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Utilizando Text Block (Java 15+) para melhor legibilidade da mensagem&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""
        Seu pedido #%d no valor de R$ %.2f foi confirmado com sucesso.
        """&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formatted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valorTotal&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enviarEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Confirmação de Pagamento"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Campos e outros métodos&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;limiteCredito&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;saldoUtilizado&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;validarLimiteCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valorCompra&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;limiteDisponivel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;limiteCredito&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saldoUtilizado&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;valorCompra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limiteDisponivel&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;utilizarCredito&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saldoUtilizado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saldoUtilizado&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&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="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ItemPedido&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@ManyToOne&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@ManyToOne&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valorUnitario&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Getters e setters&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;validarDisponibilidade&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEstoqueDisponivel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;atualizarEstoque&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reduzirEstoque&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Campos e getters/setters&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;estoqueDisponivel&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;reduzirEstoque&lt;/span&gt;&lt;span class="o"&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="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;estoqueDisponivel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NegocioException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Estoque insuficiente"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;estoqueDisponivel&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;;&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;Na versão que aplica o princípio TDA, cada entidade é responsável por seu próprio comportamento. O &lt;code&gt;PedidoService&lt;/code&gt; não pergunta mais sobre o estado interno dos objetos para tomar decisões; em vez disso, delega comportamentos aos objetos apropriados. Por exemplo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O &lt;code&gt;Pedido&lt;/code&gt; é responsável por validar a disponibilidade de seus itens.&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;Cliente&lt;/code&gt; é responsável por validar seu próprio limite de crédito.&lt;/li&gt;
&lt;li&gt;Cada &lt;code&gt;ItemPedido&lt;/code&gt; sabe como validar sua disponibilidade e atualizar o estoque.&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;Produto&lt;/code&gt; é responsável por gerenciar seu próprio estoque.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este design encapsula melhor o comportamento dentro dos objetos relevantes, tornando o código mais modular, mais fácil de manter e estender. Além disso, facilita a adição de novas regras de negócio relacionadas a cada entidade sem precisar modificar o serviço principal.&lt;/p&gt;

&lt;h2&gt;
  
  
  TDA e a Lei de Demeter
&lt;/h2&gt;

&lt;p&gt;É relevante observar que o princípio Tell, Don't Ask (TDA) frequentemente opera em conjunto com a Lei de Demeter (LoD), também conhecida como "princípio do menor conhecimento". A Lei de Demeter estabelece que um objeto só deve invocar métodos que pertençam a:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O próprio objeto&lt;/li&gt;
&lt;li&gt;Objetos recebidos como parâmetros para o método&lt;/li&gt;
&lt;li&gt;Objetos criados diretamente pelo método&lt;/li&gt;
&lt;li&gt;Propriedades/campos diretos do objeto&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No exemplo do TDA previamente discutido, quando transformamos o código, estamos também aderindo à Lei de Demeter. Vamos analisar um exemplo mais específico:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Código violando a Lei de Demeter:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RelatorioVendasService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;VendaRepository&lt;/span&gt; &lt;span class="n"&gt;vendaRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;RelatorioVendasService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VendaRepository&lt;/span&gt; &lt;span class="n"&gt;vendaRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vendaRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vendaRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt; &lt;span class="nf"&gt;gerarRelatorioMensal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;lojaId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ano&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Venda&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vendas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vendaRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByLojaIdAndPeriodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lojaId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ano&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt; &lt;span class="n"&gt;relatorio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lojaId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ano&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Venda&lt;/span&gt; &lt;span class="n"&gt;venda&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vendas&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Viola Lei de Demeter: navega pela cadeia de objetos&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nomeProduto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;venda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getItens&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getProduto&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;categoriasProduto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;venda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getItens&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getProduto&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getCategoria&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nomeVendedor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;venda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVendedor&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getDepartamento&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getGerente&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// Mais código usando estas informações...&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;;&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;&lt;strong&gt;Código aderente à Lei de Demeter e ao TDA:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RelatorioVendasService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;VendaRepository&lt;/span&gt; &lt;span class="n"&gt;vendaRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;RelatorioVendasService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VendaRepository&lt;/span&gt; &lt;span class="n"&gt;vendaRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vendaRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vendaRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt; &lt;span class="nf"&gt;gerarRelatorioMensal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;lojaId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ano&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Venda&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vendas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vendaRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByLojaIdAndPeriodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lojaId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ano&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt; &lt;span class="n"&gt;relatorio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lojaId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ano&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Delegamos a responsabilidade para a entidade Venda&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Venda&lt;/span&gt; &lt;span class="n"&gt;venda&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vendas&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adicionarVenda&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;venda&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Venda&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// atributos e outros métodos&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;adicionarAoRelatorio&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt; &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// A Venda conhece sua própria estrutura e sabe como&lt;/span&gt;
        &lt;span class="c1"&gt;// extrair informações relevantes&lt;/span&gt;
        &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adicionarValorVenda&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registrarFormaPagamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formaPagamento&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ItemVenda&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;itens&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adicionarAoRelatorio&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vendedor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adicionarEstatisticasAoRelatorio&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ItemVenda&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// atributos e outros métodos&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;adicionarAoRelatorio&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt; &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adicionarItem&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quantidade&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valorUnitario&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;obterInformacaoResumida&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Vendedor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// atributos e outros métodos&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;adicionarEstatisticasAoRelatorio&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RelatorioMensal&lt;/span&gt; &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registrarVendedor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adicionarComissao&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcularComissao&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// O Vendedor sabe como obter informações do departamento sem expor&lt;/span&gt;
        &lt;span class="c1"&gt;// a estrutura interna do departamento&lt;/span&gt;
        &lt;span class="n"&gt;relatorio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registrarDepartamento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;obterInformacaoDepartamento&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;obterInformacaoDepartamento&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Encapsula acesso à cadeia de objetos&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;departamento&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;obterInformacaoCompleta&lt;/span&gt;&lt;span class="o"&gt;();&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;No exemplo aderente à Lei de Demeter, cada objeto é responsável pelo seu próprio comportamento e por conhecer sua estrutura interna. O serviço não precisa navegar por cadeias de objetos, pois cada entidade sabe como extrair e fornecer suas próprias informações, seguindo o princípio "Tell, Don't Ask".&lt;/p&gt;

&lt;p&gt;A Lei de Demeter é frequentemente resumida como "só fale com seus amigos imediatos, não com os amigos dos seus amigos". Essa abordagem reduz o acoplamento entre componentes, facilita a manutenção e promove um melhor encapsulamento, complementando perfeitamente o princípio TDA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Críticas e Limitações dos Princípios
&lt;/h2&gt;

&lt;p&gt;Apesar de seus evidentes benefícios, é importante reconhecer que cada um destes princípios tem suas limitações e críticas relevantes. Aplicá-los sem considerar o contexto específico pode resultar em problemas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Críticas ao DRY
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Acoplamento indesejado&lt;/strong&gt;: A busca pela eliminação de toda duplicação pode criar acoplamento entre componentes que deveriam ser independentes. Quando partes do sistema que evoluem por razões diferentes compartilham código, mudanças em uma parte podem afetar outras desnecessariamente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Abstração prematura&lt;/strong&gt;: Para eliminar duplicação, frequentemente criamos abstrações que são difíceis de entender e podem ser mais complexas que a duplicação original. Isso levou ao princípio alternativo WET (Write Everything Twice ou "Escreva Tudo Duas Vezes"), sugerindo que alguma duplicação controlada pode ser preferível a abstrações inadequadas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Repetição acidental vs. essencial&lt;/strong&gt;: Nem toda semelhança no código representa uma verdadeira duplicação conceitual. Por vezes, partes do código parecem similares mas têm propósitos distintos e podem evoluir em direções diferentes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Críticas ao KISS
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subjetividade da simplicidade&lt;/strong&gt;: O que é "simples" para um desenvolvedor pode ser complexo para outro. Essa subjetividade dificulta a aplicação consistente do princípio.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplificação excessiva&lt;/strong&gt;: Em sistemas intrinsecamente complexos, soluções excessivamente simplificadas podem não abordar adequadamente a complexidade inerente do domínio.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compromisso com desempenho&lt;/strong&gt;: Soluções mais simples podem não oferecer o desempenho ideal. Em sistemas com requisitos rigorosos de performance, o KISS pode conduzir a soluções subótimas.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Críticas ao YAGNI
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dívida técnica estrutural&lt;/strong&gt;: Seguir YAGNI estritamente pode resultar em arquiteturas difíceis de adaptar posteriormente. Algumas decisões arquiteturais fundamentais são difíceis de modificar uma vez que o sistema está em produção.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custo de retrabalho&lt;/strong&gt;: Se uma funcionalidade inicialmente adiada realmente se torna necessária, o custo de implementá-la posteriormente pode ser significativamente maior do que teria sido se incorporada desde o início.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conhecimento do domínio&lt;/strong&gt;: Em domínios bem estabelecidos, desenvolvedores experientes podem prever com razoável precisão quais funcionalidades serão necessárias, tornando o YAGNI menos relevante.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Críticas ao TDA
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Classes sobrecarregadas&lt;/strong&gt;: Uma aplicação estrita do TDA pode resultar em classes com múltiplas responsabilidades, violando o Princípio de Responsabilidade Única (SRP).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Incompatibilidade com paradigmas funcionais&lt;/strong&gt;: Em programação funcional ou em designs orientados a dados, o TDA pode ser inadequado ou simplesmente não aplicável.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Desafios com aspectos transversais&lt;/strong&gt;: Funcionalidades como logging, segurança ou auditoria frequentemente necessitam "perguntar" sobre o estado interno dos objetos para funcionar adequadamente.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Como observado pelo arquiteto de software Sebastian Malaca, "princípios são genéricos e livres de contexto, mas soluções reais são baseadas em contexto, então ajuste os princípios ao contexto, não o contrário". Esta é uma perspectiva valiosa para considerar durante a aplicação destes princípios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrando os Princípios em seu Desenvolvimento
&lt;/h2&gt;

&lt;p&gt;Estes quatro princípios (DRY, KISS, YAGNI e TDA) não existem isoladamente - eles se complementam e, quando aplicados com discernimento, criam uma abordagem holística para o desenvolvimento de software de qualidade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como os princípios se relacionam?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DRY + KISS&lt;/strong&gt;: A eliminação de duplicação (DRY) frequentemente resulta em soluções mais simples (KISS).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;KISS + YAGNI&lt;/strong&gt;: Manter a simplicidade (KISS) muitas vezes envolve evitar adicionar funcionalidades desnecessárias (YAGNI).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;YAGNI + TDA&lt;/strong&gt;: Concentrar-se apenas no necessário no momento (YAGNI) conduz a um design onde objetos têm responsabilidades claras e bem definidas (TDA).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TDA + DRY&lt;/strong&gt;: Quando objetos são responsáveis por seu próprio comportamento (TDA), torna-se mais fácil evitar duplicação de lógica (DRY).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementando na Prática
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comece com KISS&lt;/strong&gt;: Ao iniciar qualquer componente, busque a solução mais simples e direta possível.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Aplique YAGNI&lt;/strong&gt;: Questione cada funcionalidade proposta: "É necessária agora?". Se a resposta for negativa, postergue sua implementação.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refatore para DRY&lt;/strong&gt;: À medida que o código evolui, identifique duplicações e refatore para eliminar redundâncias.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Estruture com TDA&lt;/strong&gt;: Organize seu código orientado a objetos para que cada classe seja responsável por seu próprio comportamento.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use discernimento&lt;/strong&gt;: Lembre-se que princípios são diretrizes, não regras absolutas. Saiba quando ser flexível e adaptá-los ao contexto específico.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Os princípios DRY, KISS, YAGNI e TDA não são apenas técnicas de codificação - são uma filosofia de desenvolvimento que valoriza clareza, manutenção e eficácia. Quando você internaliza e aplica esses princípios, eles mudam não só o código que você escreve, mas também a maneira como você pensa sobre os problemas de software.&lt;/p&gt;

&lt;p&gt;No mundo atual, onde a complexidade técnica cresce a cada dia, a habilidade de manter a simplicidade enquanto resolve problemas complexos é um diferencial valioso. Esses princípios dão um caminho confiável para alcançar esse equilíbrio difícil, desde que você os veja como guias e não como regras absolutas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lembre-se: os princípios existem para nos servir, não o contrário. O desenvolvedor maduro sabe quando aplicá-los rigorosamente e quando adaptá-los (ou até mesmo quebrá-los de propósito) para servir a um objetivo maior no design do sistema.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Como Leonardo da Vinci disse há séculos, "a simplicidade é o último grau de sofisticação". No desenvolvimento de software, essa verdade continua valendo, mas o caminho para a simplicidade nem sempre é fácil - exige discernimento, experiência e sabedoria para aplicar os princípios certos, na hora certa, do jeito certo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências Bibliográficas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Hunt, A., &amp;amp; Thomas, D. (1999). The Pragmatic Programmer: From Journeyman to Master. Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Martin, R. C. (2008). Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Beck, K. (1999). Extreme Programming Explained: Embrace Change. Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fowler, M. (2018). Refactoring: Improving the Design of Existing Code (2nd ed.). Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Freeman, S., &amp;amp; Pryce, N. (2009). Growing Object-Oriented Software, Guided by Tests. Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gamma, E., Helm, R., Johnson, R., &amp;amp; Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;McConnell, S. (2004). Code Complete: A Practical Handbook of Software Construction (2nd ed.). Microsoft Press.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Castilho, R. (2014). Tell, don't ask. [Blog]. Disponível em: &lt;a href="https://robsoncastilho.com.br/2014/05/11/conceitos-tell-dont-ask/" rel="noopener noreferrer"&gt;https://robsoncastilho.com.br/2014/05/11/conceitos-tell-dont-ask/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Souza, U. (2022). KISS, YAGNI, DRY – três princípios que todo desenvolvedor deveria conhecer! DEV Community. Disponível em: &lt;a href="https://dev.to/urielsouza29/kiss-yagni-dry-tres-principios-que-todo-desenvolvedor-deveria-conhecer-47gg"&gt;https://dev.to/urielsouza29/kiss-yagni-dry-tres-principios-que-todo-desenvolvedor-deveria-conhecer-47gg&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Thiagomr. (2020). Desvendando o mundo mágico dos acrônimos: SOLID, KISS, YAGNI, DRY, DDD, TDD. DEV Community. Disponível em: &lt;a href="https://dev.to/thiagomr/desvendando-o-mundo-magico-dos-acronimos-solid-kiss-yagni-dry-ddd-tdd-2onp"&gt;https://dev.to/thiagomr/desvendando-o-mundo-magico-dos-acronimos-solid-kiss-yagni-dry-ddd-tdd-2onp&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lazaros. (2023). Conheça os 6 princípios essenciais para arquitetura de um software. Disponível em: &lt;a href="https://www.lazaros.com.br/blog/6-principios-arquitetura-software/" rel="noopener noreferrer"&gt;https://www.lazaros.com.br/blog/6-principios-arquitetura-software/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prado, L. P. (2017). O princípio Tell, Don't Ask. [Blog]. Disponível em: &lt;a href="https://luizpauloprado.com.br/2017/01/04/o-principio-tell-dont-ask/" rel="noopener noreferrer"&gt;https://luizpauloprado.com.br/2017/01/04/o-principio-tell-dont-ask/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fonseca Chaves, G. (2020). Conceito Tell, Don't Ask. LinkedIn. Disponível em: &lt;a href="https://pt.linkedin.com/pulse/conceito-tell-dont-ask-guilherme-fonseca-chaves" rel="noopener noreferrer"&gt;https://pt.linkedin.com/pulse/conceito-tell-dont-ask-guilherme-fonseca-chaves&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Silva, R. (2019). Princípio Tell, Don't Ask. [Blog]. Disponível em: &lt;a href="https://ramonsilva.net/post/princ%C3%ADpio-tell-don-t-ask" rel="noopener noreferrer"&gt;https://ramonsilva.net/post/princípio-tell-don-t-ask&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>Padronizando Commits Git com um Script Bash: Uma Solução Simples para um Problema Comum</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Mon, 28 Apr 2025 19:11:51 +0000</pubDate>
      <link>https://dev.to/diegobrandao/padronizando-commits-git-com-um-script-bash-uma-solucao-simples-para-um-problema-comum-2bdl</link>
      <guid>https://dev.to/diegobrandao/padronizando-commits-git-com-um-script-bash-uma-solucao-simples-para-um-problema-comum-2bdl</guid>
      <description>&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;O que são Commits Semânticos e por que são importantes&lt;/li&gt;
&lt;li&gt;A origem do problema&lt;/li&gt;
&lt;li&gt;A solução: um hook Git em Bash&lt;/li&gt;
&lt;li&gt;
Anatomia do script

&lt;ul&gt;
&lt;li&gt;O hook de validação&lt;/li&gt;
&lt;li&gt;O gerenciador de hooks&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Instalação e uso&lt;/li&gt;
&lt;li&gt;Conclusão e lições aprendidas&lt;/li&gt;
&lt;li&gt;FAQ - Perguntas Frequentes&lt;/li&gt;
&lt;li&gt;Próximos passos&lt;/li&gt;
&lt;li&gt;Referências Bibliográficas&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  O que são Commits Semânticos e por que são importantes
&lt;/h2&gt;

&lt;p&gt;Commits semânticos são uma convenção para escrever mensagens de commit padronizadas que comunicam claramente a intenção por trás de cada mudança no código. Esta abordagem surgiu da Convenção de Commits Convencionais (Conventional Commits), que por sua vez foi inspirada no Angular Commit Guidelines, utilizado pelo time do Google no desenvolvimento do Angular.&lt;/p&gt;

&lt;p&gt;A ideia central é que cada commit deve descrever explicitamente seu propósito através de um formato estruturado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tipo(escopo): descrição
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Origem e Evolução
&lt;/h3&gt;

&lt;p&gt;A convenção de commits semânticos ganhou popularidade por volta de 2015-2016, quando equipes de desenvolvimento começaram a perceber a necessidade de padronizar as mensagens de commit para facilitar a automação de processos como geração de changelogs e versionamento semântico. Inicialmente adotada por projetos JavaScript, a prática se espalhou para diversas linguagens e ecossistemas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tipos de Commits
&lt;/h3&gt;

&lt;p&gt;Cada mensagem de commit começa com um "tipo" que indica a natureza da mudança:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;feat&lt;/strong&gt;: introduz uma nova funcionalidade no código&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;fix&lt;/strong&gt;: corrige um bug ou problema&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docs&lt;/strong&gt;: alterações apenas na documentação&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;style&lt;/strong&gt;: mudanças que não afetam o significado do código (espaços, formatação, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;refactor&lt;/strong&gt;: alteração de código que não corrige um bug nem adiciona uma feature&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;perf&lt;/strong&gt;: melhoria de performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;test&lt;/strong&gt;: adição ou correção de testes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;build&lt;/strong&gt;: alterações no sistema de build ou em dependências externas&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ci&lt;/strong&gt;: mudanças nos arquivos de configuração de CI/CD&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;chore&lt;/strong&gt;: outras alterações que não modificam src ou arquivos de teste&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;revert&lt;/strong&gt;: reverte um commit anterior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Onde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;escopo&lt;/strong&gt;: opcional, indica a parte do código afetada&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;descrição&lt;/strong&gt;: explica o que foi feito&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esta convenção traz diversos benefícios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Legibilidade&lt;/strong&gt;: Qualquer pessoa consegue entender rapidamente o propósito de um commit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatização&lt;/strong&gt;: Permite gerar changelogs e versionamento semântico automaticamente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organização&lt;/strong&gt;: Facilita filtrar commits por tipo (apenas correções, apenas novas features)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Histórico significativo&lt;/strong&gt;: Transforma o histórico de commits em uma documentação valiosa&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Em equipes grandes ou projetos de longo prazo, essa padronização se torna ainda mais crucial, pois ajuda a manter todos alinhados sobre as mudanças realizadas.&lt;/p&gt;

&lt;h2&gt;
  
  
  A origem do problema
&lt;/h2&gt;

&lt;p&gt;Ao trabalhar em projetos com múltiplos desenvolvedores, percebi a importância de manter um histórico de commits organizado e informativo. &lt;/p&gt;

&lt;p&gt;Minha motivação principal para criar este script veio de minha experiência anterior como desenvolvedor full stack, quando tive a oportunidade de implementar o Husky no ecossistema Node.js - uma ferramenta que simplesmente "trava" commits que não seguem o padrão desejado. Após ver o impacto positivo dessa prática, eu queria algo igualmente eficaz e simples para meus projetos Java atuais, sem necessidade de configurações complexas ou dependências adicionais.&lt;/p&gt;

&lt;p&gt;Embora existam algumas ferramentas semelhantes, como o JHusky (uma versão Java inspirada no Husky original) e alguns plugins Maven para hooks Git, descobri que muitas dessas soluções exigiam dependências específicas ou se integravam profundamente apenas com um único ecossistema. Eu queria algo verdadeiramente leve e portátil, que funcionasse em qualquer ambiente de desenvolvimento, independentemente das tecnologias utilizadas no projeto.&lt;/p&gt;

&lt;p&gt;Foi aí que decidi criar minha própria ferramenta usando Bash, uma linguagem disponível em praticamente qualquer ambiente de desenvolvimento, permitindo que equipes com tecnologias mistas pudessem aproveitar os benefícios de padronização de commits sem precisar instalar ferramentas específicas de linguagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  A solução: um hook Git em Bash
&lt;/h2&gt;

&lt;p&gt;Decidi então criar uma solução simples: um script Bash que instala um Git hook para validar mensagens de commit, garantindo que elas sigam o padrão de commits semânticos.&lt;/p&gt;

&lt;p&gt;Por que Bash? Porque está disponível em praticamente qualquer sistema Unix-like, não requer dependências externas, e qualquer desenvolvedor consegue modificá-lo para suas necessidades específicas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apresentação do Script
&lt;/h3&gt;

&lt;p&gt;O script que desenvolvi tem duas partes principais: o hook &lt;code&gt;commit-msg&lt;/code&gt; que faz a validação propriamente dita, e um gerenciador para instalar/remover esse hook em repositórios Git.&lt;/p&gt;

&lt;p&gt;Aqui está o que ele faz:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cria um hook &lt;code&gt;commit-msg&lt;/code&gt; que valida mensagens de commit usando expressões regulares&lt;/li&gt;
&lt;li&gt;Mostra feedbacks visuais coloridos quando o commit é rejeitado&lt;/li&gt;
&lt;li&gt;Fornece exemplos corretos para ajudar o desenvolvedor&lt;/li&gt;
&lt;li&gt;Permite instalar o hook em um repositório específico ou em todos os repositórios do sistema&lt;/li&gt;
&lt;li&gt;Oferece uma interface amigável para gerenciar os hooks&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Anatomia do script
&lt;/h2&gt;

&lt;h3&gt;
  
  
  O hook de validação
&lt;/h3&gt;

&lt;p&gt;A parte principal do script é o hook em si, que valida a mensagem de commit usando uma expressão regular:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;[a-zA-Z0-9_-]+&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;)?: .{1,}"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$commit_msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="nv"&gt;$pattern&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# Exibe mensagem de erro formatada com instruções&lt;/span&gt;
    &lt;span class="c"&gt;# ...&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta expressão regular garante que cada commit comece com um tipo válido (feat, fix, docs, etc.), opcionalmente seguido por um escopo entre parênteses, e depois por uma descrição.&lt;/p&gt;

&lt;p&gt;Quando uma mensagem não segue esse padrão, o script exibe uma mensagem de erro colorida que explica o formato correto e mostra exemplos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;draw_box &lt;span class="s2"&gt;"ERRO: Mensagem de commit não segue o padrão semântico!"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RED&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;$RED&lt;/span&gt;&lt;span class="s2"&gt;""Seu commit:&lt;/span&gt;&lt;span class="nv"&gt;$RESET&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$commit_msg&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;$YELLOW$BOLD&lt;/span&gt;&lt;span class="s2"&gt;""O formato correto é:&lt;/span&gt;&lt;span class="nv"&gt;$RESET&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt;tipo&amp;gt;(&amp;lt;escopo&amp;gt;): &amp;lt;descrição&amp;gt;"&lt;/span&gt;
&lt;span class="c"&gt;# ... explicação dos tipos válidos ...&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="nv"&gt;$BOLD$GREEN&lt;/span&gt;&lt;span class="s2"&gt;""Exemplos:&lt;/span&gt;&lt;span class="nv"&gt;$RESET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
draw_box &lt;span class="s2"&gt;"feat(login): adiciona validação de e-mail"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GREEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exemplo: A mensagem será exibida na aba de console do Git.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp6ces3t98ib682sla5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp6ces3t98ib682sla5b.png" alt=" " width="491" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplos rápidos
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;❌ Commits não semânticos (incorretos)&lt;/th&gt;
&lt;th&gt;✅ Commits semânticos (corretos)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Corrigido o bug de login"&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fix(auth): corrige validação de senha na tela de login&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Adicionado novo botão"&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feat(ui): adiciona botão de exportar na tela de relatórios&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Atualizando documentação"&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docs(readme): atualiza instruções de instalação&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Melhorias no código"&lt;/td&gt;
&lt;td&gt;&lt;code&gt;refactor(core): simplifica lógica de processamento de pagamentos&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  O gerenciador de hooks
&lt;/h3&gt;

&lt;p&gt;O script principal oferece uma interface de menu para:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instalar o hook em um repositório específico ou globalmente&lt;/li&gt;
&lt;li&gt;Remover hooks de um repositório específico ou globalmente&lt;/li&gt;
&lt;li&gt;Sair do script&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O menu é simples e intuitivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;===== &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BOLD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Gerenciador de Git Hook (&lt;/span&gt;&lt;span class="nv"&gt;$HOOK_NAME&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; =====&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BLUE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;1)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BOLD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Instalar hook&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BLUE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;2)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BOLD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Remover hook&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BLUE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;3)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BOLD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Sair&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao selecionar as opções 1 ou 2, você é apresentado a submenus que permitem escolher entre operações em um repositório específico ou em todos os repositórios do sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalação e uso
&lt;/h2&gt;

&lt;p&gt;A instalação do script é simples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone o repositório&lt;/span&gt;
git clone https://github.com/diegoSbrandao/git-hook-manager.git
&lt;span class="nb"&gt;cd &lt;/span&gt;git-hook-manager

&lt;span class="c"&gt;# Torne o script executável&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x install-windows-hook.sh

&lt;span class="c"&gt;# Execute o script&lt;/span&gt;
./install-windows-hook.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após executar o script, você verá um menu interativo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;===== Gerenciador de Git Hook (commit-msg) =====
1) Instalar hook
2) Remover hook
3) Sair
Escolha uma opção:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Opções do menu:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1) Instalar Hook
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1.1) Instalar hook a partir de um caminho&lt;/strong&gt;: Para adicionar o hook em um repositório específico.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1.2) Instalar hook em todos os repositórios do sistema&lt;/strong&gt;: Para uma instalação global.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2) Remover Hook
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2.1) Remover hook de um repositório específico&lt;/strong&gt;: Remove apenas hooks instalados por este script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2.2) Remover hooks de todos os repositórios do sistema&lt;/strong&gt;: Para remoção global.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O script foi desenvolvido para ser compatível com Linux, macOS, WSL e Git Bash no Windows, exigindo apenas requisitos básicos como &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt; e &lt;code&gt;grep&lt;/code&gt;, que geralmente já estão disponíveis nestes sistemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão e lições aprendidas
&lt;/h2&gt;

&lt;p&gt;O que aprendi com essa experiência é que às vezes soluções simples resolvem problemas complexos. O script não passa de 150 linhas de código Bash, mas teve um impacto significativo na qualidade do nosso trabalho.&lt;/p&gt;

&lt;p&gt;Também aprendi que padronização traz consistência, e consistência facilita a colaboração. Quando todos seguem o mesmo padrão, a comunicação flui melhor.&lt;/p&gt;

&lt;p&gt;Por fim, aprendi que ferramentas que ajudam os desenvolvedores a seguir boas práticas são tão importantes quanto as boas práticas em si. Não adianta estabelecer regras se não facilitamos o cumprimento delas.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ - Perguntas Frequentes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: O script impede commits que não sejam semânticos?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Sim, o hook rejeita automaticamente commits inválidos e exibe uma mensagem de erro explicativa com exemplos corretos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: É possível personalizar os tipos de commit aceitos?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Sim, você pode editar o script e modificar a expressão regular que define os tipos válidos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: O script funciona em ambientes Windows?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Sim, ele é compatível com Git Bash e WSL (Windows Subsystem for Linux) no Windows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: A instalação afeta todos os meus repositórios automaticamente?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Não, você precisa escolher se deseja instalar em um repositório específico ou em todos, dando controle total ao usuário.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: O hook afeta commits já realizados?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Não, o hook valida apenas novos commits, não alterando o histórico existente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Próximos passos
&lt;/h2&gt;

&lt;p&gt;É importante destacar que este script está atualmente em versão beta e ainda está em desenvolvimento. Como parte dos planos futuros, pretendo expandir sua funcionalidade integrando-o como um plugin para Maven ou IntelliJ IDEA, tornando-o ainda mais acessível para desenvolvedores Java.&lt;/p&gt;

&lt;p&gt;Quando estas versões estiverem disponíveis, atualizarei esta documentação com as novas informações e instruções de uso. Se você tem interesse em contribuir com este projeto ou tem sugestões para estas futuras implementações, não hesite em entrar em contato ou abrir uma issue no repositório.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências Bibliográficas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;CHACON, S.; STRAUB, B. &lt;strong&gt;Pro Git&lt;/strong&gt;. 2. ed. Apress, 2014. Disponível em: &lt;a href="https://git-scm.com/book/en/v2" rel="noopener noreferrer"&gt;https://git-scm.com/book/en/v2&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CONVENTIONAL COMMITS. &lt;strong&gt;Conventional Commits 1.0.0&lt;/strong&gt;. Disponível em: &lt;a href="https://www.conventionalcommits.org/" rel="noopener noreferrer"&gt;https://www.conventionalcommits.org/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Nota&lt;/strong&gt;: O projeto está licenciado sob a MIT License e está disponível em: &lt;a href="https://github.com/diegoSbrandao/git-hook-manager.git" rel="noopener noreferrer"&gt;https://github.com/diegoSbrandao/git-hook-manager.git&lt;/a&gt;. Sinta-se à vontade para adaptar às necessidades do seu projeto ou equipe. E se tiver sugestões de melhorias, ficarei feliz em recebê-las!&lt;/p&gt;

</description>
      <category>java</category>
      <category>bash</category>
      <category>git</category>
      <category>semantic</category>
    </item>
    <item>
      <title>ArchUnit: Garantindo a Integridade Arquitetural de Aplicações Java</title>
      <dc:creator>Diego de Sousa Brandão</dc:creator>
      <pubDate>Wed, 23 Apr 2025 02:39:45 +0000</pubDate>
      <link>https://dev.to/diegobrandao/archunit-garantindo-a-integridade-arquitetural-de-aplicacoes-java-29ec</link>
      <guid>https://dev.to/diegobrandao/archunit-garantindo-a-integridade-arquitetural-de-aplicacoes-java-29ec</guid>
      <description>&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introdução&lt;/li&gt;
&lt;li&gt;O que o ArchUnit faz?&lt;/li&gt;
&lt;li&gt;
Por que é importante?

&lt;ul&gt;
&lt;li&gt;Documentação Executável&lt;/li&gt;
&lt;li&gt;Feedback Rápido&lt;/li&gt;
&lt;li&gt;Refatoração Segura&lt;/li&gt;
&lt;li&gt;Padronização em Equipes Distribuídas&lt;/li&gt;
&lt;li&gt;Evolução Controlada&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Começando com ArchUnit

&lt;ul&gt;
&lt;li&gt;Configuração do Projeto&lt;/li&gt;
&lt;li&gt;Escrevendo seu Primeiro Teste&lt;/li&gt;
&lt;li&gt;Executando os Testes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Exemplos Práticos

&lt;ul&gt;
&lt;li&gt;Arquitetura em Camadas&lt;/li&gt;
&lt;li&gt;Arquitetura Limpa&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Recursos Avançados do ArchUnit

&lt;ul&gt;
&lt;li&gt;Regras Personalizadas Complexas&lt;/li&gt;
&lt;li&gt;Verificação de Interfaces e Herança&lt;/li&gt;
&lt;li&gt;Detecção de Ciclos de Dependência&lt;/li&gt;
&lt;li&gt;Cache de Importação&lt;/li&gt;
&lt;li&gt;Mensagens de Erro Personalizadas&lt;/li&gt;
&lt;li&gt;Utilizando Regras Pré-definidas&lt;/li&gt;
&lt;li&gt;Verificando Convenções de Nomenclatura&lt;/li&gt;
&lt;li&gt;Congelamento de Regras para Projetos Legados&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;li&gt;Referência Bibliográfica&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Em projetos de software de médio e grande porte, garantir que o código siga os padrões arquiteturais definidos é um desafio contínuo. Conforme o código cresce e mais desenvolvedores participam do projeto, torna-se cada vez mais difícil manter a consistência arquitetural. É nesse contexto que o ArchUnit surge como uma ferramenta poderosa para desenvolvedores Java.&lt;/p&gt;

&lt;p&gt;ArchUnit é uma biblioteca Java de código aberto que possibilita testar de forma automatizada se o código segue as regras arquiteturais estabelecidas. Ao contrário de ferramentas de análise estática tradicionais, o ArchUnit permite que você defina regras específicas para seu domínio e integre os testes de arquitetura diretamente na sua suíte de testes unitários.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que o ArchUnit faz?
&lt;/h2&gt;

&lt;p&gt;O ArchUnit permite que você teste aspectos como:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dependências entre pacotes e classes&lt;/strong&gt;: Garantir que camadas específicas não dependam de outras camadas indevidamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Convenções de nomenclatura&lt;/strong&gt;: Certificar que nomes de classes e métodos sigam os padrões estabelecidos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uso adequado de anotações&lt;/strong&gt;: Verificar se anotações específicas estão presentes onde deveriam estar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acesso a métodos e campos&lt;/strong&gt;: Verificar que determinados métodos ou campos só são acessados em contextos específicos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estrutura de herança&lt;/strong&gt;: Garantir que certas classes herdem ou implementem interfaces específicas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ciclos de dependência&lt;/strong&gt;: Identificar e evitar ciclos de dependência que possam comprometer a manutenibilidade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validação de padrões arquiteturais conhecidos&lt;/strong&gt;: Testar a conformidade com padrões como Arquitetura em Camadas, Arquitetura Limpa, etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Por que é importante?
&lt;/h2&gt;

&lt;p&gt;A importância do ArchUnit vai além da simples verificação de código:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Documentação Executável
&lt;/h3&gt;

&lt;p&gt;O ArchUnit transforma decisões arquiteturais em testes executáveis, servindo como documentação viva do projeto. Novos membros da equipe podem entender rapidamente as convenções arquiteturais examinando os testes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Feedback Rápido
&lt;/h3&gt;

&lt;p&gt;Ao integrar testes de arquitetura na sua pipeline de CI/CD, você recebe feedback imediato quando uma mudança no código viola as regras arquiteturais estabelecidas, prevenindo a degradação gradual da arquitetura.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Refatoração Segura
&lt;/h3&gt;

&lt;p&gt;Durante grandes refatorações, o ArchUnit pode garantir que as mudanças respeitem as regras arquiteturais, dando confiança para evoluir o código com segurança.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Padronização em Equipes Distribuídas
&lt;/h3&gt;

&lt;p&gt;Em equipes grandes ou distribuídas, o ArchUnit ajuda a manter consistência nas práticas de desenvolvimento, mesmo quando a comunicação direta entre equipes é limitada.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Evolução Controlada
&lt;/h3&gt;

&lt;p&gt;Quando a arquitetura precisa evoluir, você pode atualizar os testes de arquitetura para refletir as novas diretrizes, facilitando a transição controlada de um padrão arquitetural para outro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Começando com ArchUnit
&lt;/h2&gt;

&lt;p&gt;Vamos ver como configurar e começar a usar o ArchUnit em um projeto Java:&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuração do Projeto
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Para Maven (pom.xml):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Dependência principal do ArchUnit --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.tngtech.archunit&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;archunit-junit5&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Para Gradle (build.gradle):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;testImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.tngtech.archunit:archunit-junit5:1.4.0'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Escrevendo seu Primeiro Teste
&lt;/h3&gt;

&lt;p&gt;Depois de adicionar as dependências, você pode criar seu primeiro teste de arquitetura. Comece com algo simples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.archunit&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.tngtech.archunit.core.domain.JavaClasses&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.tngtech.archunit.core.importer.ClassFileImporter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.tngtech.archunit.lang.ArchRule&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tngtech&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;archunit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;syntax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ArchRuleDefinition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArchitectureTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Importando classes do seu projeto para análise&lt;/span&gt;
    &lt;span class="nc"&gt;JavaClasses&lt;/span&gt; &lt;span class="n"&gt;importedClasses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ClassFileImporter&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;importPackages&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.example.project"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;servicesShouldNotDependOnControllers&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Definindo uma regra arquitetural&lt;/span&gt;
        &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..service.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;notDependOnClassesThat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..controller.."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificando se a regra é respeitada&lt;/span&gt;
        &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;importedClasses&lt;/span&gt;&lt;span class="o"&gt;);&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;Este teste simples verifica se as classes no pacote &lt;code&gt;service&lt;/code&gt; não dependem de classes no pacote &lt;code&gt;controller&lt;/code&gt;, o que é uma regra comum em arquiteturas em camadas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Executando os Testes
&lt;/h3&gt;

&lt;p&gt;Para executar os testes de arquitetura:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Via Maven&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   mvn &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Via Gradle&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ./gradlew &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Na sua IDE&lt;/strong&gt;:
Execute o teste como qualquer outro teste JUnit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Se alguma regra for violada, você verá um erro no teste com uma mensagem detalhada explicando quais classes violaram a regra e como.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Architecture Violation [Priority: MEDIUM] - Rule 'classes that reside in a package '..service..' should not depend on classes that reside in a package '..controller..'' was violated (1 times):
Method com.example.project.service.UserService.getControllerData() calls method com.example.project.controller.UserController.getData()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Utilizando JUnit 5 para Simplificar os Testes
&lt;/h3&gt;

&lt;p&gt;Se você estiver usando JUnit 5, pode simplificar ainda mais seus testes usando as anotações fornecidas pelo ArchUnit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AnalyzeClasses&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.example.project"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ArchitectureRulesTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// O ArchUnit irá importar automaticamente as classes e verificar a regra&lt;/span&gt;
    &lt;span class="nd"&gt;@ArchTest&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;servicesShouldNotDependOnControllers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..service.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;notDependOnClassesThat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..controller.."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Regras adicionais podem ser definidas como campos estáticos&lt;/span&gt;
    &lt;span class="nd"&gt;@ArchTest&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;repositoriesShouldBeAccessedOnlyByServices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..repository.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;onlyBeAccessedByClassesThat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..service.."&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;Usando esta abordagem, não é necessário escrever explicitamente o código para importar as classes ou verificar as regras. O ArchUnit cuida disso automaticamente e também implementa um cache de classes entre os testes para melhorar o desempenho.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplos Práticos
&lt;/h2&gt;

&lt;p&gt;Vejamos dois exemplos práticos de como utilizar o ArchUnit para garantir a integridade de diferentes padrões arquiteturais:&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo 1: Arquitetura em Camadas (Layered Architecture)
&lt;/h3&gt;

&lt;p&gt;Este exemplo demonstra como validar uma arquitetura em camadas tradicional, comum em muitas aplicações:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.tngtech.archunit.core.domain.JavaClasses&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.tngtech.archunit.core.importer.ClassFileImporter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.tngtech.archunit.library.Architectures&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tngtech&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;archunit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Architectures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;layeredArchitecture&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LayeredArchitectureTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testLayeredArchitecture&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;JavaClasses&lt;/span&gt; &lt;span class="n"&gt;importedClasses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ClassFileImporter&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;importPackages&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.mycompany.app"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Definindo a arquitetura em camadas usando o padrão predefinido&lt;/span&gt;
        &lt;span class="nc"&gt;Architectures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LayeredArchitecture&lt;/span&gt; &lt;span class="n"&gt;layeredArchitecture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;layeredArchitecture&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="c1"&gt;// Definindo as camadas e os pacotes onde elas residem&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;layer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Controller"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;definedBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..controller.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;layer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Service"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;definedBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..service.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;layer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Repository"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;definedBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..repository.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;layer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Domain"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;definedBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..domain.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

                &lt;span class="c1"&gt;// Definindo as regras de dependência entre camadas&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;whereLayer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Controller"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;mayNotBeAccessedByAnyLayer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;whereLayer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Service"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;mayOnlyBeAccessedByLayers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Controller"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;whereLayer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Repository"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;mayOnlyBeAccessedByLayers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Service"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;whereLayer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Domain"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;mayOnlyBeAccessedByLayers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Service"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Repository"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Verificando a arquitetura&lt;/span&gt;
        &lt;span class="n"&gt;layeredArchitecture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;importedClasses&lt;/span&gt;&lt;span class="o"&gt;);&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;Este teste valida um padrão arquitetural em camadas típico onde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controllers ficam no topo da hierarquia e não devem ser acessados por outras camadas&lt;/li&gt;
&lt;li&gt;Services podem ser acessados apenas pelos Controllers&lt;/li&gt;
&lt;li&gt;Repositories podem ser acessados apenas por Services&lt;/li&gt;
&lt;li&gt;O Domain (entidades) pode ser acessado por Services e Repositories&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exemplo 2: Arquitetura Limpa (Clean Architecture / Onion Architecture)
&lt;/h3&gt;

&lt;p&gt;Este exemplo verifica a conformidade com os princípios da Arquitetura Limpa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.tngtech.archunit.core.domain.JavaClasses&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.tngtech.archunit.core.importer.ClassFileImporter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tngtech&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;archunit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Architectures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onionArchitecture&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CleanArchitectureTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testCleanArchitecture&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;JavaClasses&lt;/span&gt; &lt;span class="n"&gt;importedClasses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ClassFileImporter&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;importPackages&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.mycompany.app"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Definindo a arquitetura limpa (onion architecture)&lt;/span&gt;
        &lt;span class="c1"&gt;// Note que esta funcionalidade está disponível no pacote com.tngtech.archunit.library&lt;/span&gt;
        &lt;span class="n"&gt;onionArchitecture&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="c1"&gt;// Definindo as camadas da arquitetura limpa&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;domainModels&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..domain.model.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;domainServices&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..domain.service.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;applicationServices&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..application.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"persistence"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"..adapter.persistence.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rest"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"..adapter.rest.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cli"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"..adapter.cli.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

                &lt;span class="c1"&gt;// A verificação é implícita: camadas internas não podem&lt;/span&gt;
                &lt;span class="c1"&gt;// depender de camadas externas&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;importedClasses&lt;/span&gt;&lt;span class="o"&gt;);&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;Este teste valida os princípios fundamentais da Arquitetura Limpa, onde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O núcleo do domínio não depende de nenhuma outra camada&lt;/li&gt;
&lt;li&gt;A camada de aplicação depende apenas do domínio&lt;/li&gt;
&lt;li&gt;Os adaptadores (persistence, rest, cli) dependem da aplicação e do domínio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note que a função &lt;code&gt;onionArchitecture()&lt;/code&gt; é disponibilizada pelo pacote &lt;code&gt;com.tngtech.archunit.library.Architectures&lt;/code&gt;, então certifique-se de incluir a dependência correta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursos Avançados do ArchUnit
&lt;/h2&gt;

&lt;p&gt;Além dos exemplos acima, o ArchUnit oferece recursos avançados que muitos desenvolvedores desconhecem:&lt;/p&gt;

&lt;h3&gt;
  
  
  Regras Personalizadas Complexas
&lt;/h3&gt;

&lt;p&gt;Você pode criar regras de arquitetura altamente específicas usando a API fluente do ArchUnit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;areAnnotatedWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RestController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;haveSimpleNameEndingWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Controller"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andShould&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;bePublic&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andShould&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;onlyAccessMethodsThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;areDeclaredInController&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;or&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;areDeclaredInService&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verificação de Interfaces e Herança
&lt;/h3&gt;

&lt;p&gt;Embora o ArchUnit não tenha suporte nativo direto para verificação de hierarquia completa, você pode verificar implementações de interfaces ou extensões de classes específicas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Verificando se todas as classes em um pacote implementam uma interface&lt;/span&gt;
&lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..repository.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;implement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JpaRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Verificando se todas as classes que têm um determinado sufixo estendem uma classe base&lt;/span&gt;
&lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;rule2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;haveSimpleNameEndingWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Controller"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;beAssignableTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BaseController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Detecção de Ciclos de Dependência
&lt;/h3&gt;

&lt;p&gt;Os ciclos de dependência são um dos problemas arquiteturais mais difíceis de detectar manualmente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;noCyclicDependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slices&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matching&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.mycompany.app.(*).."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;beFreeOfCycles&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cache de Importação
&lt;/h3&gt;

&lt;p&gt;Para melhorar a performance dos testes em bases de código grandes, o ArchUnit oferece opções de cache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ClassFileImporter&lt;/span&gt; &lt;span class="n"&gt;importer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ClassFileImporter&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withImportOption&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ImportOption&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Predefined&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DO_NOT_INCLUDE_TESTS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withImportOption&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ImportOption&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Predefined&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DO_NOT_INCLUDE_JARS&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;JavaClasses&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;importer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;importPackages&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.mycompany.app"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É importante notar que este cache funciona apenas durante a mesma execução de testes e não persiste entre diferentes execuções ou builds. Ele melhora a performance ao reutilizar as classes importadas na mesma execução dos testes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mensagens de Erro Personalizadas
&lt;/h3&gt;

&lt;p&gt;Melhore a compreensão quando os testes falham:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;areAnnotatedWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..domain.model.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;because&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Entities são parte do modelo de domínio"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Utilizando Regras Pré-definidas
&lt;/h3&gt;

&lt;p&gt;O ArchUnit fornece várias regras pré-definidas na classe &lt;code&gt;GeneralCodingRules&lt;/code&gt; que podem ser utilizadas diretamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tngtech&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;archunit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GeneralCodingRules&lt;/span&gt;&lt;span class="o"&gt;.*;&lt;/span&gt;

&lt;span class="nd"&gt;@ArchTest&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;noClassesShouldUseJodaTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;NO_CLASSES_SHOULD_USE_JODATIME&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ArchTest&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;noClassesShouldUseStandardStreams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ArchTest&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;noClassesShouldThrowGenericExceptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ArchTest&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;noClassesShouldUseJavaUtilLogging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Observe que estas regras pré-definidas estão disponíveis no pacote &lt;code&gt;com.tngtech.archunit.library&lt;/code&gt;, e não no core do ArchUnit. Certifique-se de incluir a dependência correta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verificando Convenções de Nomenclatura
&lt;/h3&gt;

&lt;p&gt;Você pode garantir que suas convenções de nomenclatura sejam seguidas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ArchTest&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;serviceClassesShouldHaveServiceSuffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..service.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;haveSimpleNameEndingWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Service"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;@ArchTest&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;repositoryClassesShouldHaveRepositorySuffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..repository.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;haveSimpleNameEndingWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Repository"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orShould&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;haveSimpleNameEndingWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dao"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Congelamento de Regras para Projetos Legados
&lt;/h3&gt;

&lt;p&gt;Para equipes que trabalham com código legado, o ArchUnit oferece a funcionalidade de "congelamento" (freezing) de regras. Isso permite que você mantenha as violações existentes, mas impede novas violações:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Criando uma regra normal&lt;/span&gt;
&lt;span class="nc"&gt;ArchRule&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..service.."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;should&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;notDependOnClassesThat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resideInAPackage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..controller.."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Congelando a regra para permitir violações existentes&lt;/span&gt;
&lt;span class="nc"&gt;FreezingArchRule&lt;/span&gt; &lt;span class="n"&gt;frozenRule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FreezingArchRule&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;freeze&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Verificando apenas novas violações&lt;/span&gt;
&lt;span class="n"&gt;frozenRule&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;importedClasses&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta técnica é extremamente útil quando você quer melhorar gradualmente a arquitetura de um sistema legado sem ter que corrigir todas as violações de uma só vez.&lt;/p&gt;

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

&lt;p&gt;O ArchUnit representa um avanço significativo na forma como garantimos a qualidade arquitetural em projetos Java. Ao transformar regras arquiteturais em testes automatizados, ele ajuda a manter a integridade do código mesmo à medida que o projeto cresce e evolui.&lt;/p&gt;

&lt;p&gt;A ferramenta não apenas detecta violações arquiteturais precocemente, mas também serve como documentação viva das decisões arquiteturais tomadas pela equipe. Isto facilita a adaptação de novos membros e garante consistência em equipes distribuídas.&lt;/p&gt;

&lt;p&gt;Se você está enfrentando desafios para manter a consistência arquitetural em seu projeto Java, o ArchUnit pode ser uma adição valiosa ao seu conjunto de ferramentas de qualidade de código.&lt;/p&gt;

&lt;p&gt;Para ver um exemplo prático de implementação dos conceitos apresentados neste artigo, você pode acessar o repositório &lt;a href="https://github.com/diegoSbrandao/Arquitetura-em-Camadas-com-ArchUnit" rel="noopener noreferrer"&gt;Arquitetura em Camadas com ArchUnit&lt;/a&gt; que demonstra a aplicação desses princípios com exemplos de código e testes de arquitetura personalizados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referência Bibliográfica
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.archunit.org/" rel="noopener noreferrer"&gt;Site oficial do ArchUnit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javadoc.io/doc/com.tngtech.archunit/archunit/latest/index.html" rel="noopener noreferrer"&gt;Documentação do ArchUnit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/TNG/ArchUnit" rel="noopener noreferrer"&gt;Repositório GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.baeldung.com/java-archunit-intro" rel="noopener noreferrer"&gt;Introduction to ArchUnit&lt;/a&gt; - Baeldung&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
