<?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: Leticia Reis</title>
    <description>The latest articles on DEV Community by Leticia Reis (@leticiareizz).</description>
    <link>https://dev.to/leticiareizz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4115701%2F0b669ecb-1b32-4dcf-a184-433899081531.webp</url>
      <title>DEV Community: Leticia Reis</title>
      <link>https://dev.to/leticiareizz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leticiareizz"/>
    <language>en</language>
    <item>
      <title>Resiliência por Experimentação: Aplicação do ChaosEngineeringMasterDeck na Validação de uma Arquitetura de Microsserviços em Nuvem</title>
      <dc:creator>Leticia Reis</dc:creator>
      <pubDate>Thu, 15 Oct 2026 12:21:25 +0000</pubDate>
      <link>https://dev.to/leticiareizz/resiliencia-por-experimentacao-aplicacao-do-chaosengineeringmasterdeck-na-validacao-de-uma-40fn</link>
      <guid>https://dev.to/leticiareizz/resiliencia-por-experimentacao-aplicacao-do-chaosengineeringmasterdeck-na-validacao-de-uma-40fn</guid>
      <description>&lt;p&gt;&lt;strong&gt;Resumo.&lt;/strong&gt; Sistemas distribuídos em nuvem estão sujeitos a falhas parciais que dificilmente são reproduzidas por testes funcionais convencionais. Neste artigo, apresento o &lt;em&gt;Chaos Engineering&lt;/em&gt; como disciplina experimental voltada à verificação empírica da resiliência e descrevo o ChaosEngineeringMasterDeck, framework que minha equipe utiliza para estruturar experimentos de caos em cartas padronizadas, compostas por hipótese, variável injetada, métricas de controle, &lt;em&gt;Blast Radius&lt;/em&gt; e condição de aborto. Como estudo de caso, relato a aplicação da carta REDE-07, que injeta latência na comunicação entre dois microsserviços Spring Boot executados no Amazon EKS. A primeira execução refutou nossa hipótese de resiliência e evidenciou o esgotamento do pool de threads causado pela ausência de limite de tempo nas chamadas remotas. Após adotarmos de forma combinada os padrões Time Limiter, Bulkhead, Circuit Breaker e Fallback, a segunda execução confirmou a hipótese. Concluo que a prática converte suposições sobre resiliência em evidências mensuráveis e fortalece a responsabilidade compartilhada característica da cultura DevOps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Palavras-chave:&lt;/strong&gt; Chaos Engineering; resiliência; sistemas distribuídos; microsserviços; observabilidade; DevOps.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Introdução
&lt;/h2&gt;

&lt;p&gt;Atuo como engenheiro de software em uma equipe responsável por uma plataforma de comércio eletrônico baseada em microsserviços. Ao longo da migração dessa plataforma para a nuvem, percebi que a mesma arquitetura que nos trouxe escalabilidade e autonomia também aumentou de forma expressiva a complexidade operacional do sistema. Em uma arquitetura distribuída, cada chamada de rede representa um ponto potencial de falha, e a interação entre componentes produz comportamentos emergentes que não se manifestam em testes isolados. Falhas parciais, como degradação de latência, perda de uma zona de disponibilidade ou indisponibilidade temporária de um banco de dados, tendem a se propagar em cascata quando os mecanismos de proteção não foram adequadamente configurados.&lt;/p&gt;

&lt;p&gt;Foi nesse contexto que minha equipe passou a adotar o &lt;em&gt;Chaos Engineering&lt;/em&gt;, definido como a disciplina de realizar experimentos sobre um sistema com o objetivo de construir confiança em sua capacidade de suportar condições turbulentas em produção (BASIRI et al., 2016). A prática foi sistematizada pela Netflix durante a migração de sua infraestrutura para a Amazon Web Services, quando a empresa desenvolveu o Chaos Monkey, ferramenta que encerra instâncias aleatoriamente em produção para forçar o projeto de serviços tolerantes à perda de nós (BASIRI et al., 2016).&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Justificativa: por que provocar falhas intencionalmente
&lt;/h3&gt;

&lt;p&gt;O argumento que me convenceu a defender essa prática internamente é simples: falhas em sistemas distribuídos são inevitáveis. Quando aceito essa premissa, a pergunta relevante deixa de ser &lt;em&gt;se&lt;/em&gt; o sistema falhará e passa a ser &lt;em&gt;como&lt;/em&gt; ele se comportará quando falhar. Ao provocarmos falhas em condições controladas, com a equipe disponível, monitoramento ativo e plano de reversão definido, conseguimos descobrir fragilidades a um custo significativamente menor do que o de um incidente não planejado.&lt;/p&gt;

&lt;p&gt;Os testes automatizados que já mantínhamos verificam se o sistema produz o resultado esperado sob condições conhecidas. O &lt;em&gt;Chaos Engineering&lt;/em&gt;, por sua vez, investiga o comportamento do sistema sob condições adversas realistas, frequentemente associadas a configurações de infraestrutura, volume de tráfego e interações entre serviços que existem apenas em produção.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2 Mudança de paradigma
&lt;/h3&gt;

&lt;p&gt;Adotar a prática exigiu de mim e da minha equipe uma mudança na forma de conceber a confiabilidade, que sintetizo no Quadro 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quadro 1&lt;/strong&gt; – Comparação entre a abordagem tradicional e a abordagem do Chaos Engineering&lt;/p&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;Abordagem tradicional&lt;/th&gt;
&lt;th&gt;Abordagem do Chaos Engineering&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Objetivo&lt;/td&gt;
&lt;td&gt;Evitar a ocorrência de falhas&lt;/td&gt;
&lt;td&gt;Garantir a continuidade do serviço apesar das falhas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fonte de confiança&lt;/td&gt;
&lt;td&gt;Testes funcionais aprovados&lt;/td&gt;
&lt;td&gt;Falhas reais suportadas sob observação&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Natureza dos incidentes&lt;/td&gt;
&lt;td&gt;Eventos inesperados&lt;/td&gt;
&lt;td&gt;Hipóteses previamente testadas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resiliência&lt;/td&gt;
&lt;td&gt;Presumida a partir do projeto&lt;/td&gt;
&lt;td&gt;Verificada empiricamente&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.3 Princípios fundamentais
&lt;/h3&gt;

&lt;p&gt;Para orientar nossos experimentos, adotei como referência os Princípios de Chaos Engineering (PRINCIPLES OF CHAOS ENGINEERING, 2019), que estabelecem cinco diretrizes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Formular uma hipótese em torno do estado estável&lt;/strong&gt; (&lt;em&gt;steady state&lt;/em&gt;), definido por métricas observáveis de negócio e de sistema, e não pela simples disponibilidade dos servidores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variar eventos do mundo real&lt;/strong&gt;, injetando falhas que efetivamente ocorrem em produção, como latência, perda de nós e esgotamento de recursos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Executar experimentos em produção&lt;/strong&gt; ou no ambiente que mais se aproxime dela.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatizar os experimentos&lt;/strong&gt; para que sejam executados continuamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimizar o *Blast Radius&lt;/strong&gt;*, isto é, limitar o escopo do impacto potencial e ampliá-lo apenas à medida que a confiança no sistema aumenta.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nas seções seguintes, descrevo como operacionalizamos esses princípios por meio do ChaosEngineeringMasterDeck e relato um estudo de caso de sua aplicação.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. O ChaosEngineeringMasterDeck
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Definição
&lt;/h3&gt;

&lt;p&gt;O ChaosEngineeringMasterDeck é o framework que minha equipe desenvolveu para padronizar e priorizar experimentos de caos. Cada experimento é representado por uma carta, que possui uma versão impressa, utilizada em sessões presenciais de simulação que chamamos de &lt;em&gt;GameDays&lt;/em&gt;, e uma versão em arquivo YAML versionado no repositório do projeto. Essa dupla representação nos permite conduzir o mesmo experimento manualmente, para fins de aprendizado coletivo, ou de forma automatizada, como etapa recorrente do pipeline de entrega.&lt;/p&gt;

&lt;p&gt;Concebemos o framework para resolver três limitações que eu havia observado em nossa prática anterior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ausência de padronização:&lt;/strong&gt; cada engenheiro descrevia experimentos de uma forma, o que impedia a comparação de resultados.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ausência de salvaguardas:&lt;/strong&gt; iniciávamos experimentos sem condições de interrupção previamente definidas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Baixo engajamento:&lt;/strong&gt; a prática era percebida pelo time como atividade adicional e desvinculada do desenvolvimento. O formato de baralho introduziu um componente de gamificação que, na minha experiência, favoreceu a participação conjunta das equipes de desenvolvimento e operações.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.2 Organização por naipes e severidade
&lt;/h3&gt;

&lt;p&gt;Agrupamos as cartas em quatro naipes, cada um correspondente a uma camada da arquitetura, conforme o Quadro 2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quadro 2&lt;/strong&gt; – Naipes do ChaosEngineeringMasterDeck&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Naipe&lt;/th&gt;
&lt;th&gt;Camada&lt;/th&gt;
&lt;th&gt;Exemplos de experimentos&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rede&lt;/td&gt;
&lt;td&gt;Comunicação entre serviços&lt;/td&gt;
&lt;td&gt;Latência elevada, perda de pacotes, partição de rede, falha de resolução DNS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Computação&lt;/td&gt;
&lt;td&gt;Instâncias, contêineres e zonas&lt;/td&gt;
&lt;td&gt;Encerramento de pods, saturação de CPU, perda de uma zona de disponibilidade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dados&lt;/td&gt;
&lt;td&gt;Bancos de dados, cache e filas&lt;/td&gt;
&lt;td&gt;Failover de banco de dados, indisponibilidade de cache, acúmulo de mensagens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependências&lt;/td&gt;
&lt;td&gt;Serviços internos e externos&lt;/td&gt;
&lt;td&gt;Indisponibilidade de gateway de pagamento, API externa retornando HTTP 503&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;p&gt;Cada carta possui ainda um nível de severidade de 1 a 5. Estabelecemos uma regra de progressão segundo a qual equipes iniciantes executam apenas cartas de níveis 1 e 2, e cartas de níveis 4 e 5, como a perda de uma região inteira, só são habilitadas após a execução bem-sucedida das cartas de menor severidade do mesmo naipe. Com essa regra, aplicamos o princípio de minimização do &lt;em&gt;Blast Radius&lt;/em&gt; no nível do programa de experimentos, e não apenas no nível de cada experimento individual.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Estrutura de uma carta
&lt;/h3&gt;

&lt;p&gt;Estruturei as cartas de acordo com as etapas do método científico. A Figura 1 apresenta o modelo que utilizamos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figura 1&lt;/strong&gt; – Modelo de carta do ChaosEngineeringMasterDeck&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+------------------------------------------------+
| [NAIPE]-[NÚMERO]                 Severidade: N |
| Título do experimento                          |
+------------------------------------------------+
| HIPÓTESE                                       |
|   Se [falha], então [estado estável se mantém],|
|   porque [mecanismo de resiliência].           |
|                                                |
| ESTADO ESTÁVEL       métricas e valores-base   |
| VARIÁVEL INJETADA    tipo, intensidade, tempo  |
| BLAST RADIUS         limite máximo de impacto  |
| CONDIÇÃO DE ABORTO   critérios de interrupção  |
| ROLLBACK             procedimento de reversão  |
+------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;p&gt;Os campos têm as seguintes funções:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hipótese:&lt;/strong&gt; deve ser formulada obrigatoriamente no padrão &lt;em&gt;"Se [falha], então [o estado estável se mantém], porque [mecanismo de resiliência]"&lt;/em&gt;. Insisti na exigência da cláusula causal porque ela impede que executemos experimentos nos quais não conseguimos identificar o mecanismo que deveria proteger o sistema, o que por si só já constitui um achado relevante.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estado estável:&lt;/strong&gt; conjunto de métricas que caracterizam o comportamento normal do sistema, com seus respectivos valores de referência.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variável injetada:&lt;/strong&gt; a variável independente do experimento, especificada por tipo, alvo, intensidade, proporção do tráfego afetado e duração.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Métricas de controle:&lt;/strong&gt; as mesmas métricas do estado estável, que comparamos entre um grupo de controle, não submetido à falha, e um grupo experimental.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Blast Radius&lt;/em&gt;:&lt;/strong&gt; delimitação do impacto máximo admissível em termos de ambiente, usuários, serviços e tempo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condição de aborto:&lt;/strong&gt; limiares cuja violação interrompe o experimento automaticamente.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Estudo de Caso: Latência em Dependência Crítica
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Nota metodológica
&lt;/h3&gt;

&lt;p&gt;O cenário que descrevo nesta seção é um estudo de caso construído para fins didáticos. A arquitetura, as configurações e os procedimentos refletem práticas reais de mercado. Os valores numéricos que apresento nas Tabelas 1 e 2 são ilustrativos: defini-os de modo a manter coerência interna entre as métricas, e eles não correspondem a medições de um ambiente produtivo específico.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Arquitetura do sistema
&lt;/h3&gt;

&lt;p&gt;A plataforma em que trabalho é composta por microsserviços desenvolvidos em Spring Boot e executados no Amazon Elastic Kubernetes Service (EKS), distribuídos em três zonas de disponibilidade na região &lt;code&gt;sa-east-1&lt;/code&gt; (São Paulo). A Figura 2 apresenta o fluxo de criação de pedidos, que consideramos o fluxo crítico do negócio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figura 2&lt;/strong&gt; – Fluxo de criação de pedidos&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    +-------------+
   Cliente -------&amp;gt; | API Gateway |
                    +------+------+
                           |
                    +------v---------+       +-------------------+
                    | order-service  | ----&amp;gt; | inventory-service |
                    | (Spring Boot   |       |   (Spring Boot)   |
                    | + Resilience4j)|       +---------+---------+
                    +------+---------+                 |
                           |                   +-------v-------+
                    +------v--------+          |  Amazon RDS   |
                    |payment-service|          | (PostgreSQL)  |
                    +---------------+          +---------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;order-service&lt;/code&gt; consulta o &lt;code&gt;inventory-service&lt;/code&gt; de forma síncrona para verificar a disponibilidade de estoque antes de confirmar cada pedido. Por se tratar de uma dependência síncrona situada no caminho crítico, identifiquei sua degradação como o principal risco de propagação de falhas em nossa arquitetura.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Especificação do experimento
&lt;/h3&gt;

&lt;p&gt;A carta que selecionamos para o GameDay foi a REDE-07, cuja especificação apresento na Listagem 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listagem 1&lt;/strong&gt; – Especificação da carta REDE-07&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REDE-07&lt;/span&gt;
&lt;span class="na"&gt;naipe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rede&lt;/span&gt;
&lt;span class="na"&gt;severidade&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;titulo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Latência&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;na&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Dependência&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Crítica"&lt;/span&gt;

&lt;span class="na"&gt;hipotese&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;Se o inventory-service responder com acréscimo de 2000 ms de latência,&lt;/span&gt;
  &lt;span class="s"&gt;a taxa de sucesso na criação de pedidos permanecerá acima de 99%&lt;/span&gt;
  &lt;span class="s"&gt;e a latência p99 do order-service permanecerá abaixo de 800 ms,&lt;/span&gt;
  &lt;span class="s"&gt;porque o Circuit Breaker será aberto e o fallback utilizará&lt;/span&gt;
  &lt;span class="s"&gt;o cache de estoque.&lt;/span&gt;

&lt;span class="na"&gt;estado_estavel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;metrica&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;taxa_sucesso_pedidos&lt;/span&gt;
    &lt;span class="na"&gt;referencia&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;99.5%"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;metrica&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latencia_p99_order_service&lt;/span&gt;
    &lt;span class="na"&gt;referencia&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;450&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ms"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;metrica&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pedidos_por_minuto&lt;/span&gt;
    &lt;span class="na"&gt;referencia&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;variação&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5%&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;em&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;relação&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ao&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;grupo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;controle"&lt;/span&gt;

&lt;span class="na"&gt;variavel_injetada&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tipo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latencia&lt;/span&gt;
  &lt;span class="na"&gt;alvo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;order-service -&amp;gt; inventory-service&lt;/span&gt;
  &lt;span class="na"&gt;latencia_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2000&lt;/span&gt;
  &lt;span class="na"&gt;jitter_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
  &lt;span class="na"&gt;percentual_trafego&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;duracao&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10m&lt;/span&gt;
  &lt;span class="na"&gt;ferramenta&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;toxiproxy&lt;/span&gt;

&lt;span class="na"&gt;blast_radius&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ambiente&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;producao-canary&lt;/span&gt;
  &lt;span class="na"&gt;escopo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pods&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;do&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;order-service&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;grupo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;canary&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(5%&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dos&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;usuários)"&lt;/span&gt;
  &lt;span class="na"&gt;impacto_maximo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aproximadamente&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0,5%&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;das&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;requisições&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;criação&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pedido"&lt;/span&gt;
  &lt;span class="na"&gt;servicos_excluidos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;payment-service&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;auth-service&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;condicao_aborto&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;taxa&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;erro&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;HTTP&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5xx&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;canary&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2%&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;por&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mais&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;minuto"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latência&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;p99&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;canary&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;3000&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ms&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;por&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mais&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;minutos"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disparo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;qualquer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;alerta&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;severidade&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;P1"&lt;/span&gt;

&lt;span class="na"&gt;rollback&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;remoção&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;do&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;toxic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;latência&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Toxiproxy"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Delimitação do &lt;em&gt;Blast Radius&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;O &lt;em&gt;Blast Radius&lt;/em&gt; corresponde à extensão máxima do impacto caso a hipótese se revele falsa. Neste experimento, delimitei-o em três dimensões complementares:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ambiente:&lt;/strong&gt; restringimos o experimento ao grupo &lt;em&gt;canary&lt;/em&gt;, que recebe 5% do tráfego real por meio de roteamento ponderado no API Gateway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tráfego:&lt;/strong&gt; dentro do grupo &lt;em&gt;canary&lt;/em&gt;, submetemos à latência apenas 10% das chamadas ao &lt;code&gt;inventory-service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tempo:&lt;/strong&gt; fixamos a duração máxima em 10 minutos, com interrupção automática em caso de violação das condições de aborto.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O produto dessas restrições resulta em um impacto máximo estimado de 0,5% das requisições de criação de pedido durante, no máximo, 10 minutos. Antes da execução, apresentei esse nível de risco à área de produto, que o aceitou formalmente.&lt;/p&gt;

&lt;p&gt;Optei pelo ambiente produtivo, e não apenas pelo de homologação (&lt;em&gt;staging&lt;/em&gt;), com base no terceiro princípio do Chaos Engineering. Em minha experiência, volume de tráfego, padrões de acesso e dimensionamento de pools de conexão raramente são reproduzidos com fidelidade em homologação, e diversas fragilidades de resiliência só se manifestam sob carga real. Para equipes em estágio inicial de maturidade, contudo, considero o ambiente de homologação um ponto de partida adequado.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.5 Injeção da falha
&lt;/h3&gt;

&lt;p&gt;Injetei a latência por meio do Toxiproxy, proxy TCP de código aberto desenvolvido pela Shopify para simulação de condições adversas de rede (SHOPIFY, 2024). Implantamos o proxy como contêiner auxiliar (&lt;em&gt;sidecar&lt;/em&gt;) nos pods do &lt;code&gt;order-service&lt;/code&gt;, interceptando as conexões destinadas ao &lt;code&gt;inventory-service&lt;/code&gt;. A Listagem 2 apresenta o comando que utilizei.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listagem 2&lt;/strong&gt; – Injeção de latência com o Toxiproxy&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;toxiproxy-cli toxic add &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; latency &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attribute&lt;/span&gt; &lt;span class="nv"&gt;latency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attribute&lt;/span&gt; &lt;span class="nv"&gt;jitter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;300 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--toxicity&lt;/span&gt; 0.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--toxicName&lt;/span&gt; latency_inventory &lt;span class="se"&gt;\&lt;/span&gt;
  inventory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Observabilidade e Resultados
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Instrumentação
&lt;/h3&gt;

&lt;p&gt;Antes de injetar qualquer falha, precisei garantir que conseguíamos medir o estado estável. A instrumentação que utilizamos foi composta pelos seguintes elementos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Micrometer e Prometheus:&lt;/strong&gt; coleta de métricas dos serviços Spring Boot por meio do Spring Boot Actuator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafana:&lt;/strong&gt; painel que criei especificamente para o experimento, com exibição simultânea das métricas do grupo de controle e do grupo &lt;em&gt;canary&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenTelemetry e Jaeger:&lt;/strong&gt; rastreamento distribuído para identificar como o tempo de resposta se distribuía entre os serviços.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alertmanager:&lt;/strong&gt; avaliação contínua das condições de aborto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Listagem 3 apresenta as consultas PromQL que utilizei para as principais métricas de controle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listagem 3&lt;/strong&gt; – Consultas PromQL das métricas de controle&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Latência p99 do order-service, segmentada por grupo
histogram_quantile(0.99,
  sum(rate(http_server_requests_seconds_bucket{service="order-service", uri="/orders"}[1m]))
  by (le, group)
)

# Taxa de erros HTTP 5xx, segmentada por grupo
sum(rate(http_server_requests_seconds_count{service="order-service", status=~"5.."}[1m])) by (group)
/
sum(rate(http_server_requests_seconds_count{service="order-service"}[1m])) by (group)

# Estado do Circuit Breaker (valor 1 indica estado aberto)
resilience4j_circuitbreaker_state{name="inventory", state="open"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Primeira execução: refutação da hipótese
&lt;/h3&gt;

&lt;p&gt;A Listagem 4 apresenta a configuração de resiliência que estava vigente no &lt;code&gt;order-service&lt;/code&gt; antes do experimento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listagem 4&lt;/strong&gt; – Configuração original do Resilience4j&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resilience4j&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;circuitbreaker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;inventory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;sliding-window-size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
        &lt;span class="na"&gt;failure-rate-threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
        &lt;span class="na"&gt;wait-duration-in-open-state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;p&gt;Só ao analisar essa configuração em retrospecto percebi que ela não definia limite de tempo para as chamadas remotas nem critério de classificação de chamadas lentas. O Circuit Breaker contabilizava apenas exceções, de modo que uma chamada concluída com sucesso após 2 segundos não era registrada como falha. A Tabela 1 apresenta as métricas que observei nos primeiros quatro minutos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tabela 1&lt;/strong&gt; – Métricas da primeira execução&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Métrica&lt;/th&gt;
&lt;th&gt;Grupo de controle&lt;/th&gt;
&lt;th&gt;Grupo canary&lt;/th&gt;
&lt;th&gt;Referência&lt;/th&gt;
&lt;th&gt;Resultado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Taxa de sucesso&lt;/td&gt;
&lt;td&gt;99,7%&lt;/td&gt;
&lt;td&gt;98,1%&lt;/td&gt;
&lt;td&gt;≥ 99,5%&lt;/td&gt;
&lt;td&gt;Não atendido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latência p99&lt;/td&gt;
&lt;td&gt;410 ms&lt;/td&gt;
&lt;td&gt;2.380 ms&lt;/td&gt;
&lt;td&gt;&amp;lt; 450 ms&lt;/td&gt;
&lt;td&gt;Não atendido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Estado do Circuit Breaker&lt;/td&gt;
&lt;td&gt;Fechado&lt;/td&gt;
&lt;td&gt;Fechado&lt;/td&gt;
&lt;td&gt;Abertura esperada&lt;/td&gt;
&lt;td&gt;Não atendido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ocupação do pool de threads (Tomcat)&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Anomalia&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fonte: dados ilustrativos elaborados pelo autor.&lt;/p&gt;

&lt;p&gt;Ao analisar os rastros no Jaeger, identifiquei o mecanismo de propagação da falha. As chamadas lentas ao &lt;code&gt;inventory-service&lt;/code&gt; mantinham ocupadas as threads do servidor Tomcat. Com menos threads disponíveis, mesmo as requisições não submetidas à latência passaram a aguardar em fila. Assim, uma degradação aplicada a apenas 10% das chamadas comprometeu o desempenho de praticamente todo o grupo &lt;em&gt;canary&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A violação da condição de aborto relativa à latência p99 interrompeu o experimento automaticamente no quarto minuto. A remoção da latência no Toxiproxy levou menos de cinco segundos, e as métricas retornaram aos valores de referência em aproximadamente 40 segundos.&lt;/p&gt;

&lt;p&gt;Não interpreto a refutação da hipótese como insucesso do experimento, mas como seu resultado mais informativo. Com impacto limitado a cerca de 0,5% das requisições durante quatro minutos, identificamos uma fragilidade que, em um incidente real envolvendo a degradação do &lt;code&gt;inventory-service&lt;/code&gt;, poderia comprometer a totalidade da criação de pedidos.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Medidas corretivas
&lt;/h3&gt;

&lt;p&gt;Para corrigir o problema, adotamos de forma combinada quatro padrões de resiliência descritos por Nygard (2018), implementados por meio da biblioteca Resilience4j (RESILIENCE4J, 2024). A Listagem 5 apresenta a configuração resultante.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listagem 5&lt;/strong&gt; – Configuração revisada do Resilience4j&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resilience4j&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;circuitbreaker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;inventory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;sliding-window-size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
        &lt;span class="na"&gt;failure-rate-threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
        &lt;span class="na"&gt;slow-call-rate-threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
        &lt;span class="na"&gt;slow-call-duration-threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;500ms&lt;/span&gt;
        &lt;span class="na"&gt;wait-duration-in-open-state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;
        &lt;span class="na"&gt;permitted-number-of-calls-in-half-open-state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;timelimiter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;inventory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;timeout-duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;800ms&lt;/span&gt;
  &lt;span class="na"&gt;bulkhead&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;inventory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;max-concurrent-calls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;p&gt;A Listagem 6 mostra como apliquei os padrões no código do serviço.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listagem 6&lt;/strong&gt; – Aplicação dos padrões de resiliência no order-service&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;@CircuitBreaker&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;"inventory"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fallbackMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"estoqueDoCache"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@TimeLimiter&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;"inventory"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Bulkhead&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;"inventory"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Bulkhead&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;THREADPOOL&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;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Estoque&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;consultarEstoque&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;produtoId&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;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&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;inventoryClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buscar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoId&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;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Estoque&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;estoqueDoCache&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;produtoId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;ex&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;warn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fallback de estoque acionado para {}: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;produtoId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&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;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;completedFuture&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;estoqueCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ultimoValorConhecido&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produtoId&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;comFlagReconciliacao&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;Fonte: elaborado pelo autor.&lt;/p&gt;

&lt;p&gt;Cada padrão cumpre uma função específica:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time Limiter:&lt;/strong&gt; impõe limite de 800 ms para cada chamada ao &lt;code&gt;inventory-service&lt;/code&gt;, impedindo que threads permaneçam ocupadas indefinidamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bulkhead:&lt;/strong&gt; isola as chamadas ao &lt;code&gt;inventory-service&lt;/code&gt; em um pool de threads dedicado, de modo que sua saturação não comprometa os demais fluxos do &lt;code&gt;order-service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit Breaker com limiar de chamadas lentas:&lt;/strong&gt; passa a considerar chamadas acima de 500 ms no cálculo de abertura do circuito, interrompendo tentativas contra uma dependência degradada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback:&lt;/strong&gt; com o circuito aberto, o pedido é registrado com base no último valor de estoque conhecido no cache e marcado para reconciliação assíncrona. Essa foi uma decisão de negócio que tomamos em conjunto com a área de produto: consideramos preferível aceitar o pedido com pequeno risco de divergência de estoque a recusar a venda.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.4 Segunda execução: confirmação da hipótese
&lt;/h3&gt;

&lt;p&gt;Após implantarmos as correções, executei novamente a carta REDE-07 com os mesmos parâmetros. A Tabela 2 apresenta os resultados.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tabela 2&lt;/strong&gt; – Métricas da segunda execução&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Métrica&lt;/th&gt;
&lt;th&gt;Grupo de controle&lt;/th&gt;
&lt;th&gt;Grupo canary&lt;/th&gt;
&lt;th&gt;Referência&lt;/th&gt;
&lt;th&gt;Resultado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Taxa de sucesso&lt;/td&gt;
&lt;td&gt;99,7%&lt;/td&gt;
&lt;td&gt;99,6%&lt;/td&gt;
&lt;td&gt;≥ 99,5%&lt;/td&gt;
&lt;td&gt;Atendido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latência p99&lt;/td&gt;
&lt;td&gt;405 ms&lt;/td&gt;
&lt;td&gt;790 ms&lt;/td&gt;
&lt;td&gt;&amp;lt; 800 ms (hipótese)&lt;/td&gt;
&lt;td&gt;Atendido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Estado do Circuit Breaker&lt;/td&gt;
&lt;td&gt;Fechado&lt;/td&gt;
&lt;td&gt;Aberto após ~20 s&lt;/td&gt;
&lt;td&gt;Abertura esperada&lt;/td&gt;
&lt;td&gt;Atendido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chamadas atendidas por fallback&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;~9%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Conforme esperado&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ocupação do pool de threads (Tomcat)&lt;/td&gt;
&lt;td&gt;21%&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Normal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fonte: dados ilustrativos elaborados pelo autor.&lt;/p&gt;

&lt;p&gt;Desta vez, o experimento transcorreu durante os 10 minutos previstos sem violar nenhuma condição de aborto. Observei o Circuit Breaker alternar entre os estados aberto e semiaberto conforme o esperado, e a latência p99 manteve-se imediatamente abaixo do limite imposto pelo Time Limiter.&lt;/p&gt;

&lt;p&gt;Faço, porém, uma ressalva: a latência p99 do grupo &lt;em&gt;canary&lt;/em&gt; aumentou de aproximadamente 400 ms para 790 ms. A hipótese foi confirmada, mas o sistema não se tornou imune à falha; passou a degradar de forma controlada e previsível. Considero essa distinção central para a compreensão da resiliência, que não corresponde à ausência de falhas, mas à capacidade de manter o serviço em níveis aceitáveis durante sua ocorrência.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.5 Incorporação ao processo contínuo
&lt;/h3&gt;

&lt;p&gt;Com a hipótese confirmada, incorporei a carta REDE-07 à nossa suíte de experimentos automatizados, e ela passou a ser executada semanalmente no grupo &lt;em&gt;canary&lt;/em&gt;. Dessa forma, eventuais regressões, como a remoção acidental do Time Limiter em uma refatoração futura, serão detectadas antes de se manifestarem em um incidente real. Com essa etapa, atendemos ao quarto princípio do Chaos Engineering, que recomenda a automação contínua dos experimentos.&lt;/p&gt;




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

&lt;p&gt;A experiência relatada neste artigo me mostrou, na prática, que o Chaos Engineering cumpre a função de substituir suposições por evidências. Antes de executarmos a carta REDE-07, eu e minha equipe acreditávamos que o Circuit Breaker protegia o sistema contra a degradação do &lt;code&gt;inventory-service&lt;/code&gt;. O experimento refutou essa crença e revelou um mecanismo de falha em cascata que nossos testes funcionais não teriam identificado.&lt;/p&gt;

&lt;p&gt;Desse experimento, extraio as seguintes lições:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A latência é mais danosa que a indisponibilidade.&lt;/strong&gt; Um serviço indisponível falha rapidamente, enquanto um serviço lento consome recursos de forma silenciosa até comprometer os serviços que dele dependem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A resiliência resulta da combinação de padrões.&lt;/strong&gt; No caso que analisei, o Circuit Breaker sem limite de tempo foi ineficaz contra chamadas lentas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hipóteses refutadas são os resultados de maior valor.&lt;/strong&gt; Experimentos que apenas confirmam o comportamento esperado produzem pouco conhecimento novo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A observabilidade é pré-requisito do experimento.&lt;/strong&gt; Sem a capacidade de medir o estado estável, a injeção de falhas deixa de ser experimentação e passa a ser apenas uma fonte de instabilidade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A delimitação do &lt;em&gt;Blast Radius&lt;/em&gt; viabiliza o aprendizado com baixo risco.&lt;/strong&gt; Um impacto de aproximadamente 0,5% das requisições durante quatro minutos nos permitiu identificar uma falha com potencial de afetar a totalidade do fluxo de pedidos.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No plano organizacional, percebi que o formato de baralho reduziu a percepção da prática como atividade de auditoria e favoreceu a participação conjunta das equipes de desenvolvimento e operações. Esse efeito reforçou, em nossa equipe, três fundamentos da cultura DevOps: a responsabilidade compartilhada, pois quem desenvolve o código passou a participar da análise de como ele falha em produção; o ciclo de retorno rápido, pois passamos a descobrir falhas em sessões controladas, e não durante plantões; e a melhoria contínua, pois cada hipótese refutada gera uma correção, e cada correção passa a ser verificada por um experimento automatizado.&lt;/p&gt;

&lt;p&gt;Para quem pretende iniciar essa prática, recomendo uma abordagem incremental: selecionar uma única dependência crítica, formular uma hipótese no padrão &lt;em&gt;"Se... então... porque..."&lt;/em&gt;, delimitar um &lt;em&gt;Blast Radius&lt;/em&gt; reduzido, definir condições de aborto objetivas e conduzir o primeiro experimento em ambiente de homologação. Como próximos passos, pretendo estender a análise a cartas de maior severidade, como a perda de uma zona de disponibilidade, e avaliar quantitativamente o efeito do programa de experimentos sobre indicadores como o tempo médio de recuperação (MTTR) e a frequência de incidentes.&lt;/p&gt;




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

&lt;p&gt;BASIRI, A. et al. Chaos Engineering. &lt;strong&gt;IEEE Software&lt;/strong&gt;, v. 33, n. 3, p. 35-41, 2016.&lt;/p&gt;

&lt;p&gt;BEYER, B. et al. &lt;strong&gt;Site Reliability Engineering&lt;/strong&gt;: how Google runs production systems. Sebastopol: O'Reilly Media, 2016.&lt;/p&gt;

&lt;p&gt;NYGARD, M. T. &lt;strong&gt;Release It!&lt;/strong&gt;: design and deploy production-ready software. 2. ed. Raleigh: Pragmatic Bookshelf, 2018.&lt;/p&gt;

&lt;p&gt;PRINCIPLES OF CHAOS ENGINEERING. &lt;strong&gt;Principles of Chaos Engineering&lt;/strong&gt;. 2019. Disponível em: &lt;a href="https://principlesofchaos.org/" rel="noopener noreferrer"&gt;https://principlesofchaos.org/&lt;/a&gt;. Acesso em: 15 out. 2026.&lt;/p&gt;

&lt;p&gt;RESILIENCE4J. &lt;strong&gt;Resilience4j documentation&lt;/strong&gt;. 2024. Disponível em: &lt;a href="https://resilience4j.readme.io/" rel="noopener noreferrer"&gt;https://resilience4j.readme.io/&lt;/a&gt;. Acesso em: 15 out. 2026.&lt;/p&gt;

&lt;p&gt;ROSENTHAL, C.; JONES, N. &lt;strong&gt;Chaos Engineering&lt;/strong&gt;: system resiliency in practice. Sebastopol: O'Reilly Media, 2020.&lt;/p&gt;

&lt;p&gt;SHOPIFY. &lt;strong&gt;Toxiproxy&lt;/strong&gt;. 2024. Disponível em: &lt;a href="https://github.com/Shopify/toxiproxy" rel="noopener noreferrer"&gt;https://github.com/Shopify/toxiproxy&lt;/a&gt;. Acesso em: 15 out. 2026.&lt;/p&gt;

</description>
      <category>chaosengineering</category>
      <category>devops</category>
      <category>microservices</category>
      <category>aws</category>
    </item>
    <item>
      <title>Strategy Pattern em Java: Isolando Regras de Cálculo Fiscal em um Sistema B2B</title>
      <dc:creator>Leticia Reis</dc:creator>
      <pubDate>Tue, 08 Sep 2026 13:23:19 +0000</pubDate>
      <link>https://dev.to/leticiareizz/strategy-pattern-em-java-isolando-regras-de-calculo-fiscal-em-um-sistema-b2b-2h4j</link>
      <guid>https://dev.to/leticiareizz/strategy-pattern-em-java-isolando-regras-de-calculo-fiscal-em-um-sistema-b2b-2h4j</guid>
      <description>&lt;p&gt;&lt;strong&gt;Como separar regras de negócio que mudam em ritmos diferentes — e por que o &lt;code&gt;switch&lt;/code&gt; é o lugar errado para elas.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;O &lt;strong&gt;Strategy&lt;/strong&gt; é um Padrão de Projeto &lt;strong&gt;Comportamental&lt;/strong&gt;, catalogado originalmente pela Gang of Four. Padrões comportamentais tratam de como objetos se comunicam e distribuem responsabilidades entre si — diferente dos criacionais, que tratam de como objetos são instanciados, e dos estruturais, que tratam de como objetos se compõem.&lt;/p&gt;

&lt;p&gt;A definição formal é curta: o Strategy encapsula uma família de algoritmos intercambiáveis, cada um em sua própria classe, e permite que o algoritmo varie independentemente do cliente que o utiliza.&lt;/p&gt;

&lt;p&gt;A definição prática é ainda mais curta: &lt;strong&gt;é o padrão que transforma a pergunta "qual regra eu aplico agora?" de uma estrutura condicional em uma escolha de objeto.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  O problema: o &lt;code&gt;switch&lt;/code&gt; que ninguém quer tocar
&lt;/h2&gt;

&lt;p&gt;Todo sistema que cresce acumula um método específico. Ele começa com dois casos, ganha um terceiro em uma sprint apertada e, alguns anos depois, tem centenas de linhas e um comentário do tipo &lt;code&gt;// não mexer sem falar com o time de faturamento&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O sintoma visível é feio, mas o sintoma não é o problema. O problema real é &lt;strong&gt;acoplamento temporal&lt;/strong&gt;: regras que mudam em cadências independentes foram colocadas fisicamente na mesma unidade de código.&lt;/p&gt;

&lt;p&gt;Quando a regra A muda, você é obrigado a abrir, recompilar e reimplantar o mesmo arquivo que executa a regra B — mesmo que B não tenha mudado nada.&lt;/p&gt;

&lt;p&gt;Isso transforma cada alteração pequena em risco grande. E risco grande produz um comportamento defensivo previsível: ninguém quer mexer no método, então as pessoas contornam com condicionais extras em vez de corrigir a estrutura, e o método piora a cada iteração.&lt;/p&gt;

&lt;p&gt;O Strategy ataca exatamente esse acoplamento. Ele separa &lt;strong&gt;o que varia&lt;/strong&gt; do &lt;strong&gt;que permanece estável&lt;/strong&gt;, colocando cada variação em uma classe própria.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conceito: a analogia da fonte de energia
&lt;/h2&gt;

&lt;p&gt;Pense em um notebook e nas tomadas do mundo. O notebook não tem, internamente, uma estrutura condicional perguntando "estou no Brasil? estou no Reino Unido? estou no Japão?" para decidir como converter a energia. Se tivesse, cada país novo exigiria um firmware novo no notebook.&lt;/p&gt;

&lt;p&gt;O que existe é um &lt;strong&gt;contrato&lt;/strong&gt;: a fonte entrega uma tensão estável ao notebook. Como essa tensão foi obtida — de 127V, 220V ou 240V — é problema de quem implementa o contrato, não de quem o consome.&lt;/p&gt;

&lt;p&gt;O Strategy é isso em código:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;strong&gt;contrato&lt;/strong&gt; é uma interface.&lt;/li&gt;
&lt;li&gt;Cada &lt;strong&gt;variação do algoritmo&lt;/strong&gt; é uma classe que implementa essa interface.&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;contexto&lt;/strong&gt; (o notebook) conhece apenas a interface, nunca as implementações concretas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A consequência importante: a lógica que decide &lt;em&gt;como&lt;/em&gt; calcular fica isolada da lógica que decide &lt;em&gt;quando&lt;/em&gt; calcular.&lt;/p&gt;




&lt;h2&gt;
  
  
  Estudo de caso: motor de cálculo fiscal em um sistema B2B
&lt;/h2&gt;

&lt;p&gt;Para demonstrar o padrão em um contexto mais próximo dos desafios encontrados em sistemas corporativos, vamos utilizar como exemplo um motor de cálculo fiscal em uma plataforma B2B.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Aviso:&lt;/strong&gt; Os valores, alíquotas e fórmulas apresentados neste artigo são simplificados e possuem finalidade exclusivamente didática. Eles não devem ser utilizados para cálculo tributário real ou tomada de decisão fiscal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  O sistema legado
&lt;/h3&gt;

&lt;p&gt;A plataforma emite notas para clientes de perfis diferentes, e o valor dos tributos depende do &lt;strong&gt;regime tributário&lt;/strong&gt; do cliente: Simples Nacional, Lucro Presumido ou Lucro Real. O código original concentrava tudo em um único método:&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="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;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&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="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&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;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRegime&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="s"&gt;"SIMPLES"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// faixas de receita, parcela a deduzir, alíquota efetiva&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="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRegime&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="s"&gt;"PRESUMIDO"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// alíquotas fixas sobre a receita&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="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRegime&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="s"&gt;"REAL"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// alíquotas maiores, com desconto de créditos apropriados&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;total&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;
  
  
  Por que isso é um problema de engenharia, e não só código feio
&lt;/h3&gt;

&lt;p&gt;Três características desse domínio tornam o acoplamento caro:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. As regras mudam em datas diferentes e por motivos diferentes.&lt;/strong&gt; Cada regime segue sua própria trilha legislativa. Uma alteração em um não tem relação nenhuma com o outro, mas ambos vivem no mesmo arquivo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Os algoritmos consomem entradas diferentes.&lt;/strong&gt; O Simples precisa da receita bruta acumulada do cliente para descobrir em qual faixa ele está. O Lucro Real precisa dos créditos apropriados no período. O Lucro Presumido não usa nenhum dos dois. Não existe "extrair um método comum" aqui, porque os &lt;em&gt;inputs&lt;/em&gt; divergem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. O raio de explosão de um erro é o faturamento inteiro.&lt;/strong&gt; Uma regressão introduzida ao ajustar a faixa do Simples pode derrubar a emissão de notas dos clientes de Lucro Real, porque compartilham o mesmo caminho de execução.&lt;/p&gt;

&lt;p&gt;Esse é o formato clássico de problema que o Strategy resolve: &lt;strong&gt;variação de algoritmo, com cadência de mudança independente e alto custo de erro.&lt;/strong&gt; A partir daqui, o foco é o padrão; a parte fiscal existe apenas para dar peso realista ao cenário.&lt;/p&gt;

&lt;h3&gt;
  
  
  Escopo do exemplo
&lt;/h3&gt;

&lt;p&gt;Para manter o artigo focado no padrão, as alíquotas e faixas são constantes dentro de cada estratégia. Em um sistema real elas viriam de configuração versionada com data de vigência — uma decisão de infraestrutura ortogonal ao Strategy. Todo o código apresentado abaixo é Java puro e compila sem framework.&lt;/p&gt;




&lt;h2&gt;
  
  
  Representação visual
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Figura 1 — Diagrama UML do Strategy Pattern aplicado ao motor fiscal.&lt;/em&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffmpsfebjytntfw3mq2vy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffmpsfebjytntfw3mq2vy.png" alt="Diagrama UML de classes: a interface CalculadoraImposto, suas três implementações e a agregação com MotorFiscal" width="799" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O diagrama está restrito às classes que compõem o padrão. &lt;code&gt;Pedido&lt;/code&gt;, &lt;code&gt;Cliente&lt;/code&gt; e as exceções aparecem no código como tipos de apoio, mas incluí-los aqui tiraria o foco da estrutura que importa.&lt;/p&gt;

&lt;p&gt;Repare no losango vazio, indicando agregação, entre &lt;code&gt;MotorFiscal&lt;/code&gt; e &lt;code&gt;CalculadoraImposto&lt;/code&gt;: o motor &lt;strong&gt;usa&lt;/strong&gt; as estratégias, mas não as cria. Esse detalhe é o que separa um Strategy real de um &lt;code&gt;switch&lt;/code&gt; disfarçado.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figura 2 — Arquitetura de alto nível do sistema de cálculo fiscal.&lt;/em&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4q6cmscvloifpm17sjtc.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4q6cmscvloifpm17sjtc.png" alt="Diagrama de arquitetura: o Módulo Fiscal entre a camada de API, o banco de dados e o provedor de NF-e" width="800" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dois pontos que este desenho comunica e o UML não:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A consulta ao banco acontece antes do motor.&lt;/strong&gt; É o dado do cliente que determina qual estratégia será executada — a seleção não é uma decisão tomada em código, é uma consequência de dados que chegam em tempo de execução.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O Módulo Fiscal é uma fronteira interna, não um serviço remoto.&lt;/strong&gt; O Strategy aqui é uma decisão de organização interna. Ele não introduz nenhuma chamada de rede, e é importante que isso fique visível: padrões de projeto e padrões de arquitetura distribuída resolvem problemas diferentes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Implementação em Java
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tipos de apoio
&lt;/h3&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="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;RegimeTributario&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;SIMPLES_NACIONAL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;LUCRO_PRESUMIDO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="no"&gt;LUCRO_REAL&lt;/span&gt;
&lt;span class="o"&gt;}&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;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegimeTributario&lt;/span&gt; &lt;span class="n"&gt;regimeTributario&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;receitaBruta12Meses&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;uf&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Pedido&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;valorTotal&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;creditosApropriados&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;RegimeNaoSuportadoException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&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;RegimeNaoSuportadoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegimeTributario&lt;/span&gt; &lt;span class="n"&gt;regime&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nenhuma calculadora registrada para o regime: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;regime&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;LimiteSimplesExcedidoException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&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;LimiteSimplesExcedidoException&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;receita&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Receita acumulada fora das faixas configuradas: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;receita&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;
  
  
  O contrato
&lt;/h3&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;ContextoFiscal&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;valorBruto&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;receitaBruta12Meses&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;creditosApropriados&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;uf&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;static&lt;/span&gt; &lt;span class="nc"&gt;ContextoFiscal&lt;/span&gt; &lt;span class="nf"&gt;de&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="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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ContextoFiscal&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;valorTotal&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;receitaBruta12Meses&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;creditosApropriados&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;uf&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;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;ResultadoImposto&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;total&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;RegimeTributario&lt;/span&gt; &lt;span class="n"&gt;regimeAplicado&lt;/span&gt;&lt;span class="o"&gt;,&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;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;detalhamento&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;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="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;CalculadoraImposto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;ResultadoImposto&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;ContextoFiscal&lt;/span&gt; &lt;span class="n"&gt;contexto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;RegimeTributario&lt;/span&gt; &lt;span class="nf"&gt;getRegime&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 método &lt;code&gt;getRegime()&lt;/code&gt; merece atenção. Ele existe para que &lt;strong&gt;cada estratégia se identifique&lt;/strong&gt;, em vez de alguém externo precisar mapeá-la. É esse detalhe que permite eliminar a estrutura condicional de verdade, em vez de apenas empurrá-la para uma factory.&lt;/p&gt;

&lt;h3&gt;
  
  
  As estratégias
&lt;/h3&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimplesNacionalCalculadora&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CalculadoraImposto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Faixa&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;limite&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;aliquotaNominal&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;parcelaDeduzir&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="c1"&gt;// Tabela reduzida e simplificada para fins didáticos.&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Faixa&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FAIXAS&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;.&lt;/span&gt;&lt;span class="na"&gt;of&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;Faixa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"180000"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;  &lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.0400"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0"&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;Faixa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"360000"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;  &lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.0730"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"5940"&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;Faixa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"720000"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;  &lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.0950"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"13860"&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;Faixa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1800000"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.1070"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bd&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"22500"&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="nc"&gt;ResultadoImposto&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;ContextoFiscal&lt;/span&gt; &lt;span class="n"&gt;contexto&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;receita&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contexto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;receitaBruta12Meses&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;Faixa&lt;/span&gt; &lt;span class="n"&gt;faixa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FAIXAS&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;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;receita&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;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limite&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="na"&gt;findFirst&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;LimiteSimplesExcedidoException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receita&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Alíquota efetiva = (receita x alíquota nominal - parcela a deduzir) / receita&lt;/span&gt;
        &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;aliquotaEfetiva&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;receita&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;faixa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aliquotaNominal&lt;/span&gt;&lt;span class="o"&gt;())&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;faixa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parcelaDeduzir&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;divide&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receita&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RoundingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HALF_UP&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;imposto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contexto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valorBruto&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aliquotaEfetiva&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setScale&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="nc"&gt;RoundingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HALF_UP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResultadoImposto&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="nc"&gt;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SIMPLES_NACIONAL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Map&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="s"&gt;"IMPOSTO_UNIFICADO"&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="s"&gt;"ALIQUOTA_EFETIVA"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aliquotaEfetiva&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;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RegimeTributario&lt;/span&gt; &lt;span class="nf"&gt;getRegime&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;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SIMPLES_NACIONAL&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="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;bd&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;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;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BigDecimal&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;/code&gt;&lt;/pre&gt;

&lt;/div&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LucroPresumidoCalculadora&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CalculadoraImposto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Alíquotas ilustrativas.&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;BigDecimal&lt;/span&gt; &lt;span class="no"&gt;ALIQUOTA_A&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.0065"&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;BigDecimal&lt;/span&gt; &lt;span class="no"&gt;ALIQUOTA_B&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.0300"&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;ResultadoImposto&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;ContextoFiscal&lt;/span&gt; &lt;span class="n"&gt;contexto&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;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contexto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valorBruto&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;tributoA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ALIQUOTA_A&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;setScale&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="nc"&gt;RoundingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HALF_UP&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;tributoB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ALIQUOTA_B&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;setScale&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="nc"&gt;RoundingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HALF_UP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResultadoImposto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;tributoA&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;tributoB&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="nc"&gt;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LUCRO_PRESUMIDO&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Map&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="s"&gt;"TRIBUTO_A"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tributoA&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"TRIBUTO_B"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tributoB&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;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RegimeTributario&lt;/span&gt; &lt;span class="nf"&gt;getRegime&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;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LUCRO_PRESUMIDO&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;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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LucroRealCalculadora&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CalculadoraImposto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Alíquotas ilustrativas.&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;BigDecimal&lt;/span&gt; &lt;span class="no"&gt;ALIQUOTA_A&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.0165"&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;BigDecimal&lt;/span&gt; &lt;span class="no"&gt;ALIQUOTA_B&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.0760"&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;ResultadoImposto&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;ContextoFiscal&lt;/span&gt; &lt;span class="n"&gt;contexto&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;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contexto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valorBruto&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;contexto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;creditosApropriados&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&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;tributoA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ALIQUOTA_A&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;setScale&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="nc"&gt;RoundingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HALF_UP&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;tributoB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ALIQUOTA_B&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;setScale&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="nc"&gt;RoundingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HALF_UP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ResultadoImposto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;tributoA&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;tributoB&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="nc"&gt;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LUCRO_REAL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Map&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="s"&gt;"TRIBUTO_A"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tributoA&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"TRIBUTO_B"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tributoB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                       &lt;span class="s"&gt;"CREDITOS"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contexto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;creditosApropriados&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;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RegimeTributario&lt;/span&gt; &lt;span class="nf"&gt;getRegime&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;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LUCRO_REAL&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;code&gt;LucroRealCalculadora&lt;/code&gt; usa &lt;code&gt;creditosApropriados&lt;/code&gt; e ignora &lt;code&gt;receitaBruta12Meses&lt;/code&gt;; &lt;code&gt;SimplesNacionalCalculadora&lt;/code&gt; faz o oposto.&lt;/p&gt;

&lt;p&gt;Essa assimetria é a justificativa técnica do padrão: &lt;strong&gt;não são parâmetros diferentes do mesmo algoritmo, são algoritmos diferentes.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  O contexto: onde a condicional desaparece
&lt;/h3&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MotorFiscal&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;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CalculadoraImposto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;estrategias&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;MotorFiscal&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;CalculadoraImposto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;calculadoras&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;estrategias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculadoras&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;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;toUnmodifiableMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;CalculadoraImposto:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getRegime&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;Function&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="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;ResultadoImposto&lt;/span&gt; &lt;span class="nf"&gt;calcularPara&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="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="nc"&gt;CalculadoraImposto&lt;/span&gt; &lt;span class="n"&gt;calculadora&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;estrategias&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="n"&gt;cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regimeTributario&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;calculadora&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RegimeNaoSuportadoException&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;regimeTributario&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;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="nc"&gt;ContextoFiscal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;de&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="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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este é o coração do artigo. Duas decisões merecem ser explicadas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Collectors.toUnmodifiableMap&lt;/code&gt; falha na inicialização se houver regime duplicado.&lt;/strong&gt; Se alguém criar por engano uma segunda calculadora para &lt;code&gt;LUCRO_REAL&lt;/code&gt;, o coletor lança &lt;code&gt;IllegalStateException&lt;/code&gt; na construção do objeto. Isso é bem melhor do que descobrir em produção que parte das notas usou a implementação errada.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A escolha entre exceção e valor padrão é uma decisão de domínio, não do padrão.&lt;/strong&gt; Aqui a exceção é deliberada: em cálculo tributário, "não sei calcular" precisa interromper a operação, porque um valor padrão silencioso geraria um documento incorreto. Em outros domínios — formatação de texto, política de desconto — um comportamento padrão neutro seria a escolha certa.&lt;/p&gt;

&lt;p&gt;Vale notar que o construtor recebe uma &lt;code&gt;List&lt;/code&gt; justamente para desacoplar o motor de quem monta as estratégias. Em uma aplicação com injeção de dependência, essa lista é preenchida automaticamente; em Java puro, ela é passada na composição da aplicação. O motor não muda em nenhum dos dois casos.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que realmente muda ao adicionar um regime novo
&lt;/h2&gt;

&lt;p&gt;É comum ler que o Strategy permite estender o sistema "sem alterar nenhuma linha de código existente". Na implementação acima, isso não é literalmente verdade, e vale ser preciso.&lt;/p&gt;

&lt;p&gt;Para adicionar um regime novo, é preciso:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Acrescentar uma constante em &lt;code&gt;RegimeTributario&lt;/code&gt; — uma linha, aditiva.&lt;/li&gt;
&lt;li&gt;Criar uma classe nova implementando &lt;code&gt;CalculadoraImposto&lt;/code&gt; e registrá-la na composição da aplicação.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O que &lt;strong&gt;não&lt;/strong&gt; muda:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MotorFiscal&lt;/code&gt; não é tocado.&lt;/li&gt;
&lt;li&gt;Nenhuma das calculadoras existentes é tocada.&lt;/li&gt;
&lt;li&gt;O código que consome o resultado não é tocado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A diferença em relação ao &lt;code&gt;switch&lt;/code&gt; original é qualitativa, não quantitativa. Lá, você também acrescentaria uma constante — mas depois editaria o mesmo método que executa o cálculo de todos os outros regimes. É essa segunda edição, no código que está em produção e funcionando, que carrega o risco de regressão.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O Strategy não elimina toda alteração; ele elimina a alteração perigosa.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rigorosamente, o enum ainda é um ponto de extensão que exige modificação, e é justo chamar isso de violação parcial do Princípio Aberto/Fechado. Existe alternativa: usar &lt;code&gt;String&lt;/code&gt; como chave do mapa, lida do banco de dados. Isso removeria até essa linha, ao custo de perder a verificação em tempo de compilação. Manter o enum é um trade-off consciente — em domínio fiscal, um regime escrito errado falhando no &lt;em&gt;build&lt;/em&gt; é preferível a falhar em produção.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testes
&lt;/h2&gt;

&lt;p&gt;Cada estratégia é testável isoladamente, sem instanciar as outras. No método monolítico original, testar um regime exigia carregar todos juntos.&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;class&lt;/span&gt; &lt;span class="nc"&gt;MotorFiscalTest&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;MotorFiscal&lt;/span&gt; &lt;span class="n"&gt;motor&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;MotorFiscal&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;.&lt;/span&gt;&lt;span class="na"&gt;of&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;SimplesNacionalCalculadora&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;LucroPresumidoCalculadora&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;LucroRealCalculadora&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;deveSelecionarEstrategiaConformeRegimeDoCliente&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&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="nc"&gt;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LUCRO_PRESUMIDO&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;"500000"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"GO"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&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="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;"10000.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ResultadoImposto&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;motor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcularPara&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="n"&gt;cliente&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;resultado&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualByComparingTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"365.00"&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;resultado&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;regimeAplicado&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LUCRO_PRESUMIDO&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;deveAplicarAliquotaEfetivaNoSimplesNacional&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&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="nc"&gt;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SIMPLES_NACIONAL&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;"500000"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"GO"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&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="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;"10000.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ResultadoImposto&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;motor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcularPara&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="n"&gt;cliente&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;resultado&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;isEqualByComparingTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"672.80"&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;deveFalharQuandoNaoHaEstrategiaParaORegime&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;MotorFiscal&lt;/span&gt; &lt;span class="n"&gt;motorIncompleto&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;MotorFiscal&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;.&lt;/span&gt;&lt;span class="na"&gt;of&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;LucroPresumidoCalculadora&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
        &lt;span class="kt"&gt;var&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="nc"&gt;RegimeTributario&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LUCRO_REAL&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;"500000"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"GO"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&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="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;"10000.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;assertThatThrownBy&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;motorIncompleto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calcularPara&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="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="na"&gt;isInstanceOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegimeNaoSuportadoException&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;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O terceiro teste é o mais interessante: ele documenta o comportamento na ausência de estratégia, que é justamente a decisão de domínio discutida acima.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prós e contras
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Vantagens
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extensão com risco contido.&lt;/strong&gt; Adicionar um regime significa uma constante nova e uma classe nova. Nenhum algoritmo existente é editado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raio de explosão reduzido.&lt;/strong&gt; Uma alteração no cálculo do Simples não pode quebrar o Lucro Real: não compartilham arquivo, estado nem caminho de execução.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testabilidade real.&lt;/strong&gt; Cada algoritmo é uma unidade isolada, com entradas e saídas explícitas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seleção dirigida por dados.&lt;/strong&gt; Como a escolha vem do cadastro do cliente e não de código, fica natural evoluir para cenários como aplicar a regra vigente na data de emissão.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custos e trade-offs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dispersão da lógica.&lt;/strong&gt; Antes, todas as regras estavam em uma tela; agora estão em vários arquivos. Para quem chega no time, "onde o imposto é calculado?" ficou mais difícil de responder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observabilidade vira requisito.&lt;/strong&gt; Com a condicional, bastava ler o código para saber o que executou. Agora é preciso registrar qual implementação atendeu qual pedido — incluir &lt;code&gt;regimeAplicado&lt;/code&gt; no &lt;code&gt;ResultadoImposto&lt;/code&gt; é resposta direta a esse custo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O objeto de contexto tende a inchar.&lt;/strong&gt; &lt;code&gt;ContextoFiscal&lt;/code&gt; carrega a união dos campos que qualquer estratégia possa precisar, então cada implementação ignora parte deles. É um efeito colateral conhecido do Strategy com contexto compartilhado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mais tipos para manter.&lt;/strong&gt; Cinco classes onde havia um método. Em uma base pequena e estável, isso é cerimônia sem retorno.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;E o trade-off mais importante: se a variação for de dados, Strategy é overengineering.&lt;/strong&gt; Uma alíquota que muda por unidade da federação não merece uma classe por estado — isso é tabela de configuração.&lt;/p&gt;

&lt;p&gt;O sinal prático para distinguir: se as implementações diferem apenas por constantes, você quer uma tabela. Se diferem nos campos que consomem e nos passos que executam, você quer Strategy. Foi esse teste que justificou o padrão aqui.&lt;/p&gt;




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

&lt;p&gt;O Strategy não resolve o problema de "código feio com muitas condicionais". Ele resolve um problema arquitetural mais específico: &lt;strong&gt;regras de negócio que evoluem em ritmos independentes acopladas na mesma unidade de código.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No motor fiscal, o ganho não é estético. É transformar uma alteração de alto risco — mexer no cálculo de todos os clientes para atender à mudança de um regime — em uma alteração isolada e testável. O padrão desloca a modificação para o lugar barato, uma constante em um enum, e a tira do lugar caro, o algoritmo em produção.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visão pessoal
&lt;/h3&gt;

&lt;p&gt;Como estudante e desenvolvedora em formação, minha experiência com Padrões de Projeto até a realização deste estudo era majoritariamente teórica. Ao ler a literatura técnica, a princípio, o Strategy pode parecer apenas uma forma desnecessariamente complexa e verbosa de escrever uma estrutura condicional simples.&lt;/p&gt;

&lt;p&gt;No entanto, o exercício de modelar e implementar este cenário de cálculo tributário mudou completamente minha perspectiva. A verdadeira virada de chave foi ver o Princípio Aberto/Fechado funcionando na prática: a compreensão de que podemos expandir as capacidades de um sistema inteiro apenas adicionando novas classes, sem a necessidade de alterar ou arriscar quebrar o código do motor principal.&lt;/p&gt;

&lt;p&gt;Escrever este artigo também me obrigou a ser mais precisa do que eu esperava. Ao revisar a implementação, percebi que a afirmação comum de que o Strategy dispensa qualquer alteração no código existente não se sustenta inteiramente, já que o enum de regimes ainda precisa receber uma constante nova. Entender por que essa alteração é aceitável — e por que ela é qualitativamente diferente de editar o algoritmo em produção — foi provavelmente o que mais me ensinou no processo.&lt;/p&gt;

&lt;p&gt;Ainda que eu não tenha vivenciado o cenário crítico de manter um sistema legado complexo em produção e lidar com as regressões causadas por um método fortemente acoplado, essa imersão prática cumpriu seu objetivo principal. Ela me forneceu a base arquitetural não apenas para entender como resolver esse tipo de problema, mas, principalmente, para evitar que eu construa sistemas com essas falhas de design no futuro.&lt;/p&gt;

&lt;h3&gt;
  
  
  E você?
&lt;/h3&gt;

&lt;p&gt;Fica a pergunta que mais me interessa: &lt;strong&gt;qual foi a estrutura condicional mais assustadora que você já encontrou em produção — e você refatorou ou concluiu que o risco não valia a pena?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Também quero ouvir discordância: em que situação você acha que manter o &lt;code&gt;switch&lt;/code&gt; foi a decisão certa? Comenta aí.&lt;/p&gt;

</description>
      <category>java</category>
      <category>designpatterns</category>
      <category>architecture</category>
      <category>cleancode</category>
    </item>
  </channel>
</rss>
