<?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: Maxwell Anabil</title>
    <description>The latest articles on DEV Community by Maxwell Anabil (@maxwellsilvadev).</description>
    <link>https://dev.to/maxwellsilvadev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4118092%2F27b0b311-e847-4dbe-ac0f-6c7d973e5b0f.png</url>
      <title>DEV Community: Maxwell Anabil</title>
      <link>https://dev.to/maxwellsilvadev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maxwellsilvadev"/>
    <language>en</language>
    <item>
      <title>Sobrevivendo ao Caos: como o ChaosEngineeringMasterDeck testa a resiliência de microsserviços</title>
      <dc:creator>Maxwell Anabil</dc:creator>
      <pubDate>Fri, 23 Oct 2026 23:24:32 +0000</pubDate>
      <link>https://dev.to/maxwellsilvadev/sobrevivendo-ao-caos-como-o-chaosengineeringmasterdeck-testa-a-resiliencia-de-microsservicos-23ik</link>
      <guid>https://dev.to/maxwellsilvadev/sobrevivendo-ao-caos-como-o-chaosengineeringmasterdeck-testa-a-resiliencia-de-microsservicos-23ik</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;E se um serviço ficar lento agora?&lt;/strong&gt; A pergunta importante não é se falhas vão acontecer, mas se a arquitetura consegue absorvê-las sem transformar um problema pequeno em uma indisponibilidade geral.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introdução: por que provocar falhas de propósito?
&lt;/h2&gt;

&lt;p&gt;Em sistemas distribuídos, uma aplicação pode funcionar perfeitamente em condições normais e ainda assim falhar quando uma dependência fica lenta, uma instância desaparece ou uma conexão com o banco de dados é interrompida. Isso acontece porque os serviços não trabalham isoladamente: filas, redes, APIs, caches e bancos de dados criam relações que podem amplificar uma falha inicial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chaos Engineering&lt;/strong&gt;, ou engenharia do caos, é a prática de realizar experimentos controlados para descobrir como um sistema se comporta diante de situações adversas. A ideia não é causar indisponibilidade por diversão, nem testar sem planejamento. É formular uma hipótese, introduzir uma falha limitada, observar o comportamento real e usar as evidências para melhorar a arquitetura. Os princípios da disciplina recomendam medir o estado normal do sistema, experimentar com eventos realistas e procurar diferenças entre o comportamento esperado e o comportamento observado [1].&lt;/p&gt;

&lt;p&gt;Essa abordagem muda a mentalidade da equipe. Em vez de assumir que tudo deve funcionar sempre, partimos do princípio de que componentes podem falhar — e projetamos o sistema para limitar o impacto, continuar oferecendo funções essenciais e se recuperar com segurança.&lt;/p&gt;

&lt;p&gt;Então, por que testar em &lt;em&gt;staging&lt;/em&gt; ou até mesmo em produção? Testes em ambientes de homologação reduzem o risco inicial e são o ponto de partida recomendado. Com maturidade, controles e autorização, experimentos cuidadosamente delimitados em produção podem revelar comportamentos que não aparecem em ambientes artificiais, por exemplo, devido ao tráfego real e às dependências de verdade. &lt;strong&gt;Não se começa derrubando serviços críticos em produção:&lt;/strong&gt; começa-se pequeno, com monitoramento, plano de interrupção e critérios objetivos para interromper o teste. A documentação do AWS Fault Injection Service também recomenda planejar o experimento e começar em ambiente de teste ou pré-produção [2].&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o ChaosEngineeringMasterDeck?
&lt;/h2&gt;

&lt;p&gt;Neste projeto, o &lt;strong&gt;ChaosEngineeringMasterDeck&lt;/strong&gt; é um catálogo versionado de experimentos de resiliência apresentado como um baralho de cartas. Cada carta descreve uma falha possível e transforma essa falha em um experimento repetível, com objetivo, limites, métricas e procedimento de recuperação.&lt;/p&gt;

&lt;p&gt;O formato de baralho torna a prática mais acessível durante revisões de arquitetura, simulações de incidentes e dinâmicas de equipe. Uma carta pode ser sorteada em uma sessão de treinamento, mas sua execução não deve ser improvisada: ela precisa ter sido revisada, aprovada e preparada para o ambiente definido.&lt;/p&gt;

&lt;p&gt;O Deck não substitui ferramentas de injeção de falhas, telemetria ou automação. Ele funciona como uma &lt;strong&gt;camada de padronização e governança&lt;/strong&gt; sobre essas ferramentas, registrando por que o experimento existe, como será executado e quais evidências indicarão sucesso ou falha.&lt;/p&gt;

&lt;h3&gt;
  
  
  O que cada carta contém?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identificação e objetivo:&lt;/strong&gt; nome, serviço-alvo, ambiente e risco que queremos investigar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hipótese:&lt;/strong&gt; o comportamento que esperamos observar depois de introduzir a falha.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estado estável (&lt;em&gt;steady state&lt;/em&gt;):&lt;/strong&gt; indicadores que descrevem o funcionamento normal para o usuário, como latência, taxa de erro e conclusão de operações importantes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variável de caos:&lt;/strong&gt; a condição que será alterada, como latência de rede, indisponibilidade de uma instância ou falha de conexão.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blast radius:&lt;/strong&gt; limites explícitos sobre quais serviços, usuários, requisições e recursos poderão ser afetados.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observabilidade:&lt;/strong&gt; painéis, logs, métricas, rastreamentos distribuídos e alertas que serão consultados.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Critérios de abortagem e recuperação:&lt;/strong&gt; condições para interromper o teste, como restaurar o serviço e como confirmar que tudo voltou ao normal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resultado e aprendizado:&lt;/strong&gt; evidências coletadas, lacunas identificadas e ações corretivas com responsáveis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse modelo impede que a experiência se resuma a “derrubamos alguma coisa e vimos no que deu”. O experimento passa a ter uma hipótese que pode ser confirmada, refutada ou refinada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo de uma carta do Deck
&lt;/h3&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;CE-004&lt;/span&gt;
&lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Latência elevada no serviço de recomendações&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;staging&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;recommendation-service&lt;/span&gt;
&lt;span class="na"&gt;falha&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;atraso_adicional&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;duracao&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5m&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;trafego&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;usuarios-sinteticos&lt;/span&gt;
  &lt;span class="na"&gt;percentual_maximo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10%&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api/recommendations&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;O catálogo continuará respondendo em até 500 ms no p95,&lt;/span&gt;
  &lt;span class="s"&gt;a taxa global de erros ficará abaixo de 1% e a compra&lt;/span&gt;
  &lt;span class="s"&gt;continuará funcionando mesmo sem recomendações personalizadas.&lt;/span&gt;
&lt;span class="na"&gt;abortagem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;taxa_global_de_erros_acima_de&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1%&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;alerta_critico_disparado&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;falha_no_fluxo_de_compra&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os valores do exemplo são parâmetros ilustrativos para o cenário deste artigo. Em uma aplicação real, limites e métricas precisam ser definidos a partir dos SLOs, dos dados históricos e do impacto aceitável para o negócio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estudo de caso: recomendações lentas, catálogo disponível
&lt;/h2&gt;

&lt;p&gt;Imagine uma loja virtual implantada na AWS. A aplicação usa microsserviços Java com Spring Boot e executa tarefas em mais de uma zona de disponibilidade. O balanceador distribui as requisições, e a tela de produtos consulta dois serviços: o &lt;strong&gt;Catálogo&lt;/strong&gt;, responsável pelos dados essenciais dos produtos, e o &lt;strong&gt;Recomendações&lt;/strong&gt;, que personaliza sugestões com base no perfil do cliente.&lt;/p&gt;

&lt;p&gt;A recomendação melhora a experiência, mas não é indispensável para consultar um produto ou concluir uma compra. Se esse serviço ficar lento, o sistema deve continuar útil: a página pode mostrar uma lista popular previamente armazenada em cache, em vez de manter a requisição inteira bloqueada.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Hipótese e estado estável
&lt;/h3&gt;

&lt;p&gt;Antes do experimento, a equipe observa o sistema em condições normais e define o que significa “saudável” do ponto de vista do cliente. Para esta simulação didática, usaremos a seguinte linha de base:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Indicador&lt;/th&gt;
&lt;th&gt;Estado normal ilustrativo&lt;/th&gt;
&lt;th&gt;Limite durante o experimento&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Latência p95 do Catálogo&lt;/td&gt;
&lt;td&gt;210 ms&lt;/td&gt;
&lt;td&gt;Até 500 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Taxa global de erros HTTP&lt;/td&gt;
&lt;td&gt;0,2%&lt;/td&gt;
&lt;td&gt;Abaixo de 1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conclusão do fluxo de compra&lt;/td&gt;
&lt;td&gt;99,7%&lt;/td&gt;
&lt;td&gt;Sem queda relevante atribuível ao teste&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fallback de recomendações&lt;/td&gt;
&lt;td&gt;Não acionado normalmente&lt;/td&gt;
&lt;td&gt;Deve assumir quando necessário&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A hipótese é: &lt;strong&gt;se adicionarmos 800 ms de latência ao serviço de recomendações por cinco minutos, o Catálogo continuará dentro do limite de latência, a taxa global de erros permanecerá abaixo de 1% e o fluxo de compra não será interrompido.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A hipótese é mensurável. Assim, a equipe não depende de impressões como “pareceu rápido” ou “ninguém percebeu nada”.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Execução controlada e Blast Radius
&lt;/h3&gt;

&lt;p&gt;O experimento começa em &lt;em&gt;staging&lt;/em&gt;, com dados de teste e geração de tráfego sintético. A falha é aplicada somente ao caminho de comunicação com o serviço de recomendações, por meio de um proxy de teste ou ferramenta de injeção de falhas. Apenas até 10% das requisições sintéticas entram nesse caminho, e a duração máxima é de cinco minutos.&lt;/p&gt;

&lt;p&gt;Esse limite é o &lt;strong&gt;Blast Radius&lt;/strong&gt;, ou raio de explosão: a área potencialmente afetada caso algo saia do previsto. Neste caso, ele exclui o serviço de pagamentos, o banco de dados de pedidos e o tráfego de clientes reais. O time também define antecipadamente quem pode iniciar o experimento, quem acompanha os painéis e quem pode encerrá-lo.&lt;/p&gt;

&lt;p&gt;O teste é cancelado automaticamente ou manualmente se a taxa global de erros superar 1%, se o fluxo de compra falhar ou se um alerta crítico for acionado. Ao terminar, a injeção de latência é removida e a equipe verifica a recuperação. Esses limites são essenciais porque ferramentas como o AWS Fault Injection Service executam ações reais sobre recursos selecionados; por isso, a seleção dos alvos e os controles devem ser revisados antes da execução [2].&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Quais padrões de resiliência esperamos observar?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Timeouts:&lt;/strong&gt; a chamada ao serviço de recomendações tem um limite de espera. Sem timeout, uma chamada lenta poderia ocupar conexões e threads por tempo excessivo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Circuit Breaker:&lt;/strong&gt; quando as chamadas falham ou ultrapassam os limites configurados, o disjuntor abre temporariamente e impede novas chamadas repetidas ao serviço degradado. Isso reduz a chance de que uma dependência lenta consuma os recursos do restante da aplicação. Em projetos Spring Boot, bibliotecas como Resilience4j oferecem suporte a Circuit Breaker, Retry, Bulkhead e TimeLimiter [3].&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fallback:&lt;/strong&gt; com o serviço de recomendações indisponível, a aplicação utiliza uma lista de produtos populares armazenada em cache. O fallback não deve fabricar resultados críticos nem declarar uma operação financeira como concluída; ele só substitui a funcionalidade opcional de personalização.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bulkhead:&lt;/strong&gt; limites de concorrência isolam os recursos usados pelas chamadas de recomendação, reduzindo o risco de que elas esgotem as threads ou conexões necessárias ao Catálogo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retries limitados:&lt;/strong&gt; novas tentativas, quando necessárias, usam limite e intervalo de espera. Repetir chamadas indefinidamente pode amplificar uma falha e gerar uma tempestade de retries. Em uma dependência já lenta, pode ser melhor falhar rápido e acionar o fallback.&lt;/p&gt;

&lt;p&gt;O escalonamento automático pode ajudar quando o problema é falta de capacidade, mas &lt;strong&gt;não corrige automaticamente toda falha&lt;/strong&gt;. Se a causa for uma dependência travada, aumentar a quantidade de instâncias pode não resolver — e, em alguns casos, até aumentar a pressão sobre essa dependência.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Observabilidade: como sabemos se funcionou?
&lt;/h3&gt;

&lt;p&gt;Durante o teste, o time acompanha um painel com métricas e sinais correlacionados:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Métricas:&lt;/strong&gt; latência p50/p95/p99, taxa de erros, volume de requisições, timeouts, estado do Circuit Breaker, uso de CPU e memória e taxa de acionamento do fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs estruturados:&lt;/strong&gt; registros com identificador de correlação, para encontrar uma requisição ao longo dos serviços sem expor dados sensíveis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rastreamento distribuído:&lt;/strong&gt; &lt;em&gt;traces&lt;/em&gt; para confirmar em qual dependência o tempo foi consumido e se o atraso se propagou ao Catálogo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alertas:&lt;/strong&gt; notificações sobre violações dos limites definidos e sinais de degradação do fluxo de compra.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A equipe deve monitorar tanto o serviço atingido quanto a experiência do usuário. Uma queda no consumo de CPU, por exemplo, não prova que o sistema está saudável: o serviço pode estar recusando requisições. Da mesma forma, a aplicação pode continuar respondendo com HTTP 200, mas entregar uma experiência lenta ou incompleta. Por isso, indicadores técnicos precisam estar ligados a resultados observáveis para o cliente. Os princípios de Chaos Engineering destacam latência, vazão e taxa de erros como medidas possíveis do estado estável [1].&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Resultados ilustrativos da simulação
&lt;/h3&gt;

&lt;p&gt;Como este artigo descreve um cenário didático, os números a seguir são &lt;strong&gt;resultados hipotéticos de referência, não medições de um experimento real&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Indicador&lt;/th&gt;
&lt;th&gt;Exemplo de resultado&lt;/th&gt;
&lt;th&gt;Interpretação&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Latência p95 do Catálogo&lt;/td&gt;
&lt;td&gt;285 ms&lt;/td&gt;
&lt;td&gt;Abaixo do limite de 500 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Taxa global de erros HTTP&lt;/td&gt;
&lt;td&gt;0,6%&lt;/td&gt;
&lt;td&gt;Abaixo do limite de 1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recomendações personalizadas&lt;/td&gt;
&lt;td&gt;Degradadas durante a injeção&lt;/td&gt;
&lt;td&gt;Falha isolada na funcionalidade opcional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fallback&lt;/td&gt;
&lt;td&gt;Acionado com sucesso&lt;/td&gt;
&lt;td&gt;Página continuou oferecendo sugestões genéricas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fluxo de compra&lt;/td&gt;
&lt;td&gt;Sem interrupção atribuível ao teste&lt;/td&gt;
&lt;td&gt;Função essencial preservada&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nesse resultado ilustrativo, a hipótese seria aceita: a falha local não comprometeu o caminho crítico. Ainda assim, o teste não provaria que o sistema está preparado para todo tipo de incidente. Ele mostraria apenas que um tipo específico de latência, dentro dos limites definidos, foi absorvido de forma aceitável.&lt;/p&gt;

&lt;p&gt;Caso os indicadores ultrapassassem os limites, isso não seria simplesmente um “teste fracassado”. Seria uma evidência útil: talvez o timeout estivesse alto demais, o Circuit Breaker abrisse tarde, o fallback dependesse da mesma infraestrutura degradada ou a concorrência das chamadas não estivesse isolada. A equipe registraria a descoberta, corrigiria a arquitetura e repetiria o mesmo experimento para confirmar a melhoria.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como ampliar o Deck com segurança
&lt;/h2&gt;

&lt;p&gt;Depois de validar experimentos menores, o catálogo pode incluir cartas para cenários mais amplos, como falha de conexão com o banco, indisponibilidade de uma instância, esgotamento de recursos ou perda de uma zona de disponibilidade. A AWS, por exemplo, documenta um cenário de interrupção de energia de uma Availability Zone para avaliar aplicações distribuídas em múltiplas zonas [4]. Esse tipo de teste tem raio de impacto muito maior e exige revisão específica de alvos, permissões, dependências, capacidade de recuperação e plano de interrupção.&lt;/p&gt;

&lt;p&gt;Uma progressão sensata é:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Começar em ambiente de teste&lt;/strong&gt;, com um alvo e uma falha simples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conferir observabilidade e abortagem&lt;/strong&gt; antes de aumentar o alcance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatizar a execução e a coleta de resultados&lt;/strong&gt;, evitando depender de memória individual.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repetir após mudanças relevantes&lt;/strong&gt;, como alterações de arquitetura, infraestrutura ou bibliotecas de resiliência.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avançar para ambientes mais representativos gradualmente&lt;/strong&gt;, incluindo produção somente quando houver maturidade operacional, autorização e limites seguros.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O Deck também deve guardar o que foi aprendido: hipótese inicial, configuração aplicada, horário, métricas antes/durante/depois, alarmes acionados, incidentes observados e ações corretivas. Assim, um resultado deixa de ser uma experiência isolada e passa a fortalecer o conhecimento coletivo da equipe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão: resiliência se demonstra, não se presume
&lt;/h2&gt;

&lt;p&gt;Nenhuma arquitetura distribuída elimina todas as falhas. O objetivo da engenharia de resiliência é evitar que uma falha localizada se transforme em um problema sistêmico, proteger os fluxos essenciais e recuperar o serviço dentro de limites aceitáveis.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;ChaosEngineeringMasterDeck&lt;/strong&gt; organiza essa prática em experimentos repetíveis e compreensíveis: cada carta descreve uma hipótese, limita o Blast Radius, define métricas de controle e registra o aprendizado. No estudo de caso, a latência é aplicada a uma funcionalidade opcional para verificar se o Catálogo e o fluxo de compra continuam operando.&lt;/p&gt;

&lt;p&gt;A principal lição é cultural: confiabilidade não é responsabilidade exclusiva de uma equipe de infraestrutura nem uma etapa realizada somente antes do lançamento. Desenvolvimento, operações, arquitetura e produto precisam compartilhar hipóteses, dados e decisões. Quando o caos é introduzido com método e segurança, ele deixa de ser apenas uma ameaça e se torna uma oportunidade de aprender — antes que uma falha real ensine a mesma lição aos clientes.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Principles of Chaos Engineering.&lt;/strong&gt; Fundamentos de estado estável, hipóteses, eventos realistas e minimização do Blast Radius. &lt;a href="https://principlesofchaos.org/" rel="noopener noreferrer"&gt;https://principlesofchaos.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS — Planning your AWS FIS experiments.&lt;/strong&gt; Recomendações para planejar experimentos, definir o estado estável, formular hipóteses e começar em ambientes de teste. &lt;a href="https://docs.aws.amazon.com/fis/latest/userguide/getting-started-planning.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/fis/latest/userguide/getting-started-planning.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilience4j — Getting Started.&lt;/strong&gt; Biblioteca de tolerância a falhas com Circuit Breaker, Retry, Bulkhead, Cache e TimeLimiter. &lt;a href="https://resilience4j.readme.io/docs/getting-started" rel="noopener noreferrer"&gt;https://resilience4j.readme.io/docs/getting-started&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS — AZ Availability: Power Interruption.&lt;/strong&gt; Cenário para avaliar os efeitos de uma interrupção em uma zona de disponibilidade. &lt;a href="https://docs.aws.amazon.com/fis/latest/userguide/az-availability-scenario.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/fis/latest/userguide/az-availability-scenario.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft Azure Well-Architected Framework — Reliability testing strategy.&lt;/strong&gt; Conceitos de resiliência, recuperação, injeção de falhas e testes de confiabilidade. &lt;a href="https://learn.microsoft.com/en-us/azure/well-architected/reliability/reliability-test" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/well-architected/reliability/reliability-test&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Nota sobre o estudo de caso:&lt;/strong&gt; a arquitetura e os resultados numéricos deste artigo são ilustrativos e foram incluídos para demonstrar como estruturar um experimento. Eles não representam uma execução real nem resultados observados em um ambiente de produção.&lt;/p&gt;

</description>
      <category>chaosengineering</category>
      <category>devops</category>
      <category>aws</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Adapter Pattern em Java: integrando novas transportadoras sem quebrar um sistema legado</title>
      <dc:creator>Maxwell Anabil</dc:creator>
      <pubDate>Wed, 09 Sep 2026 19:29:59 +0000</pubDate>
      <link>https://dev.to/maxwellsilvadev/adapter-pattern-em-java-integrando-novas-transportadoras-sem-quebrar-um-sistema-legado-4a8g</link>
      <guid>https://dev.to/maxwellsilvadev/adapter-pattern-em-java-integrando-novas-transportadoras-sem-quebrar-um-sistema-legado-4a8g</guid>
      <description>&lt;p&gt;&lt;strong&gt;Maxwell Anabil Macabeu da Silva&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Bacharelado em Engenharia de Software — UniEvangélica&lt;br&gt;&lt;br&gt;
Anápolis — Goiás — Brasil&lt;/p&gt;
&lt;h2&gt;
  
  
  Resumo
&lt;/h2&gt;

&lt;p&gt;Sistemas de e-commerce dependem de integrações com serviços externos, como gateways de pagamento, plataformas de logística e transportadoras. Um problema recorrente aparece quando cada fornecedor disponibiliza uma API diferente, com métodos, formatos de dados e estruturas de resposta incompatíveis com o sistema existente.&lt;/p&gt;

&lt;p&gt;Neste artigo apresento a aplicação do &lt;strong&gt;Adapter Pattern&lt;/strong&gt;, um padrão estrutural do catálogo GoF, em um cenário de integração de transportadoras dentro de um sistema de e-commerce desenvolvido em Java.&lt;/p&gt;

&lt;p&gt;A proposta é criar uma interface padrão utilizada pelo sistema e implementar adaptadores responsáveis por traduzir a comunicação com diferentes APIs externas. Dessa forma, o sistema principal não precisa conhecer os detalhes específicos de cada transportadora.&lt;/p&gt;

&lt;p&gt;Além da explicação do padrão, será apresentado um estudo de caso, um diagrama UML de classes, uma visão de arquitetura, uma implementação em Java e uma análise das vantagens e dos trade-offs envolvidos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Palavras-chave:&lt;/strong&gt; Adapter Pattern; Design Patterns; Java; Engenharia de Software; APIs; Integração de Sistemas; E-commerce.&lt;/p&gt;


&lt;h1&gt;
  
  
  1. Base Fundamental
&lt;/h1&gt;
&lt;h2&gt;
  
  
  1.1 O que são Design Patterns?
&lt;/h2&gt;

&lt;p&gt;Durante o desenvolvimento de software, alguns problemas aparecem repetidamente em diferentes projetos.&lt;/p&gt;

&lt;p&gt;Como organizar a criação de objetos? Como permitir que comportamentos sejam alterados sem modificar várias partes do sistema? Como integrar sistemas que possuem interfaces incompatíveis?&lt;/p&gt;

&lt;p&gt;Os &lt;strong&gt;Design Patterns&lt;/strong&gt;, ou padrões de projeto, representam soluções conhecidas e reutilizáveis para problemas recorrentes de design de software.&lt;/p&gt;

&lt;p&gt;Eles não são códigos prontos que simplesmente copiamos para o projeto. Na realidade, são maneiras de estruturar classes e responsabilidades para resolver determinados tipos de problema.&lt;/p&gt;

&lt;p&gt;Os padrões originalmente apresentados pelo chamado &lt;strong&gt;Gang of Four (GoF)&lt;/strong&gt; são geralmente divididos em três grupos:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Categoria&lt;/th&gt;
&lt;th&gt;Objetivo&lt;/th&gt;
&lt;th&gt;Exemplos&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Criacionais&lt;/td&gt;
&lt;td&gt;Organizam a criação de objetos&lt;/td&gt;
&lt;td&gt;Factory Method, Builder, Singleton&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Estruturais&lt;/td&gt;
&lt;td&gt;Organizam como objetos e classes se relacionam&lt;/td&gt;
&lt;td&gt;Adapter, Decorator, Facade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comportamentais&lt;/td&gt;
&lt;td&gt;Organizam responsabilidades e comportamentos&lt;/td&gt;
&lt;td&gt;Strategy, Observer, Command&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O padrão abordado neste artigo é o &lt;strong&gt;Adapter Pattern&lt;/strong&gt;, pertencente à categoria dos padrões &lt;strong&gt;estruturais&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  1.2 O problema: quando cada API fala uma língua diferente
&lt;/h2&gt;

&lt;p&gt;Imagine um sistema de e-commerce que possui um módulo responsável por calcular o valor do frete de um pedido.&lt;/p&gt;

&lt;p&gt;Inicialmente, a empresa utilizava apenas uma transportadora. O código poderia ser semelhante a:&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShippingService&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;LegacyCarrierClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;calculateShipping&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;originZip&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;destinationZip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;weightInGrams&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;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;originZip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;destinationZip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;weightInGrams&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;Enquanto existe apenas uma integração, essa estrutura parece suficiente.&lt;/p&gt;

&lt;p&gt;O problema aparece quando a empresa decide oferecer mais opções de entrega. Uma segunda transportadora pode possuir algo semelhante a:&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="n"&gt;fastShipClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRate&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;FastShipPayload&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;weightInKg&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;Observe que as duas APIs não trabalham da mesma maneira.&lt;/p&gt;

&lt;p&gt;Uma pode utilizar peso em gramas, parâmetros separados e valor retornado em centavos. Outra pode utilizar peso em quilogramas, um objeto de requisição e valor retornado como &lt;code&gt;BigDecimal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O sistema começa então a acumular verificações:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;carrier&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;"LEGACY"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// chama API da primeira transportadora&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;carrier&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;"FAST_SHIP"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// converte peso&lt;/span&gt;
    &lt;span class="c1"&gt;// cria payload&lt;/span&gt;
    &lt;span class="c1"&gt;// chama outra API&lt;/span&gt;
    &lt;span class="c1"&gt;// converte resposta&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;carrier&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;"OUTRA_TRANSPORTADORA"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// outra implementação&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quanto mais integrações surgem, maior fica esse código.&lt;/p&gt;

&lt;p&gt;Além disso, o &lt;code&gt;ShippingService&lt;/code&gt; passa a conhecer detalhes que não deveriam fazer parte de sua responsabilidade, como formato de requisição de cada fornecedor, unidades de medida, nomes de métodos externos, estruturas de resposta e tratamento específico de cada API.&lt;/p&gt;

&lt;p&gt;É exatamente nesse tipo de situação que o &lt;strong&gt;Adapter Pattern&lt;/strong&gt; pode ajudar.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.3 Como funciona o Adapter Pattern?
&lt;/h2&gt;

&lt;p&gt;A palavra &lt;em&gt;adapter&lt;/em&gt; significa &lt;strong&gt;adaptador&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Uma analogia simples é um adaptador de tomada. Você possui um dispositivo com um padrão de tomada, mas chega a um local onde a tomada possui outro formato. Em vez de modificar o aparelho ou a instalação elétrica, coloca um adaptador entre os dois.&lt;/p&gt;

&lt;p&gt;No desenvolvimento de software, a ideia é semelhante:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sistema existente
       ↓
Interface conhecida pelo sistema
       ↓
Adapter
       ↓
API externa incompatível
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Adapter recebe uma chamada utilizando o formato esperado pelo sistema e realiza a tradução necessária para o formato exigido pelo serviço externo.&lt;/p&gt;

&lt;p&gt;Normalmente temos três participantes principais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target:&lt;/strong&gt; interface que o sistema gostaria de utilizar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapter:&lt;/strong&gt; implementa essa interface e converte a chamada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptee:&lt;/strong&gt; classe ou API existente que possui uma interface incompatível.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No nosso exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target
ShippingProvider

Adapters
LegacyCarrierAdapter
FastShipAdapter

Adaptees
LegacyCarrierClient
FastShipClient
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim, o restante do sistema trabalha apenas com &lt;code&gt;ShippingProvider&lt;/code&gt; e não precisa saber qual API realmente está por trás daquele objeto.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.4 Adapter não é Strategy
&lt;/h2&gt;

&lt;p&gt;Os dois padrões podem parecer semelhantes porque ambos utilizam interfaces e composição. Porém, resolvem problemas diferentes.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;Strategy Pattern&lt;/strong&gt; normalmente é utilizado quando existem diferentes algoritmos capazes de executar uma mesma tarefa.&lt;/p&gt;

&lt;p&gt;Já o &lt;strong&gt;Adapter Pattern&lt;/strong&gt; é utilizado principalmente quando queremos tornar &lt;strong&gt;interfaces incompatíveis compatíveis&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No nosso cenário, nossa aplicação espera:&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="n"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShippingRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mas uma API externa oferece:&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="n"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;originZip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destinationZip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weightGrams&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e outra oferece:&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="n"&gt;getRate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FastShipPayload&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Adapter cria uma camada de tradução entre essas interfaces.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Desenvolvimento
&lt;/h1&gt;

&lt;h2&gt;
  
  
  2.1 Cenário do Mundo Real
&lt;/h2&gt;

&lt;p&gt;Considere um e-commerce que vende produtos para diferentes regiões e precisa calcular o frete durante o checkout.&lt;/p&gt;

&lt;p&gt;O fluxo é aproximadamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cliente seleciona os produtos
          ↓
Informa o endereço
          ↓
Sistema solicita cotações
          ↓
Transportadoras calculam o frete
          ↓
Sistema apresenta preço e prazo
          ↓
Cliente escolhe a opção
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inicialmente, o sistema possuía integração apenas com uma transportadora. Com o crescimento da operação, surgiu a necessidade de conectar novos provedores logísticos.&lt;/p&gt;

&lt;p&gt;Porém, cada fornecedor possuía sua própria API.&lt;/p&gt;

&lt;p&gt;Um deles trabalhava com peso em &lt;strong&gt;gramas&lt;/strong&gt;, enquanto outro utilizava &lt;strong&gt;quilogramas&lt;/strong&gt;. Um retornava valores em &lt;strong&gt;centavos&lt;/strong&gt;, enquanto outro retornava &lt;code&gt;BigDecimal&lt;/code&gt;. Um utilizava vários parâmetros no método, enquanto outro esperava um objeto de requisição.&lt;/p&gt;

&lt;p&gt;Alterar o &lt;code&gt;ShippingService&lt;/code&gt; sempre que uma nova integração fosse adicionada faria com que o serviço se tornasse cada vez mais acoplado às APIs externas.&lt;/p&gt;

&lt;p&gt;A solução escolhida é definir uma interface comum chamada &lt;code&gt;ShippingProvider&lt;/code&gt;. Cada API externa recebe então seu próprio Adapter.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.2 Diagrama UML de Classes
&lt;/h2&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%2Fnt8nyk8eipwa54pyc8kd.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%2Fnt8nyk8eipwa54pyc8kd.png" alt="Diagrama UML do Adapter Pattern aplicado ao serviço de fretes" width="800" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figura 1 — Diagrama UML do Adapter Pattern aplicado ao serviço de fretes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O ponto mais importante do diagrama é observar que o &lt;code&gt;ShippingService&lt;/code&gt; depende apenas de &lt;code&gt;ShippingProvider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ele não conhece diretamente &lt;code&gt;LegacyCarrierClient&lt;/code&gt; nem &lt;code&gt;FastShipClient&lt;/code&gt;. Esses detalhes ficam escondidos dentro dos adapters.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.3 Arquitetura de Software
&lt;/h2&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%2Fm46ixn36y26drsace521.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%2Fm46ixn36y26drsace521.png" alt="Arquitetura de alto nível do sistema de cotação de fretes" width="799" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figura 2 — Arquitetura de alto nível do sistema de cotação de fretes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O cliente não entra em contato diretamente com as transportadoras.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;Order Service&lt;/code&gt; solicita ao &lt;code&gt;Shipping Service&lt;/code&gt; uma cotação. Dentro do &lt;code&gt;Shipping Service&lt;/code&gt;, os adapters ficam responsáveis por conversar com cada API externa.&lt;/p&gt;

&lt;p&gt;Essa separação é importante porque uma alteração realizada por uma transportadora afeta principalmente seu Adapter, em vez de espalhar modificações pelo restante da aplicação.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  2.4.1 Representando a solicitação de frete
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Objects&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;ShippingRequest&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;originZip&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;destinationZip&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;weightKg&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;ShippingRequest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;originZip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destinationZip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requireNonNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weightKg&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;weightKg&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="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="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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="s"&gt;"O peso deve ser maior que zero."&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;p&gt;Independentemente da transportadora utilizada, nosso sistema trabalhará internamente com peso em quilogramas.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4.2 Representando a resposta
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&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;ShippingQuote&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;provider&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;price&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;deliveryDays&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;Agora qualquer transportadora utilizada pelo sistema deverá fornecer nome do provedor, preço e prazo de entrega.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4.3 Criando a interface padrão
&lt;/h3&gt;

&lt;p&gt;Este é o nosso &lt;strong&gt;Target&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ShippingProvider&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;ShippingQuote&lt;/span&gt; &lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShippingRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;ShippingService&lt;/code&gt; conhecerá somente essa interface.&lt;/p&gt;

&lt;p&gt;Ele não precisa conhecer nenhuma API externa diretamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4.4 API da primeira transportadora
&lt;/h3&gt;

&lt;p&gt;Imagine que uma integração antiga utiliza esta interface:&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="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;LegacyCarrierClient&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;LegacyCarrierResponse&lt;/span&gt; &lt;span class="nf"&gt;calculate&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;originZip&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;destinationZip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;weightInGrams&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;E retorna:&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;LegacyCarrierResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;priceInCents&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;estimatedDays&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;Nosso sistema trabalha com quilogramas e &lt;code&gt;BigDecimal&lt;/code&gt;, enquanto essa integração utiliza gramas e centavos.&lt;/p&gt;

&lt;p&gt;As interfaces são incompatíveis.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4.5 Criando o primeiro Adapter
&lt;/h3&gt;

&lt;p&gt;É aqui que entra o padrão:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&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;LegacyCarrierAdapter&lt;/span&gt;
        &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ShippingProvider&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;LegacyCarrierClient&lt;/span&gt; &lt;span class="n"&gt;client&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;LegacyCarrierAdapter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;LegacyCarrierClient&lt;/span&gt; &lt;span class="n"&gt;client&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&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;ShippingQuote&lt;/span&gt; &lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;ShippingRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;weightInGrams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;weightKg&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="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;intValueExact&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;LegacyCarrierResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;originZip&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;destinationZip&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                        &lt;span class="n"&gt;weightInGrams&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;price&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;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;priceInCents&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;movePointLeft&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ShippingQuote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"Legacy Carrier"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;estimatedDays&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;p&gt;Perceba que toda a incompatibilidade ficou dentro dessa classe.&lt;/p&gt;

&lt;p&gt;O Adapter realiza as conversões necessárias e transforma a resposta externa em um &lt;code&gt;ShippingQuote&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O restante do sistema não precisa conhecer nenhuma dessas conversões.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4.6 Integrando uma segunda transportadora
&lt;/h3&gt;

&lt;p&gt;Agora imagine uma API mais moderna:&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="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FastShipClient&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;FastShipRate&lt;/span&gt; &lt;span class="nf"&gt;getRate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;FastShipPayload&lt;/span&gt; &lt;span class="n"&gt;payload&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;Seu payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&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;FastShipPayload&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;from&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;to&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;weight&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;E sua resposta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&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;FastShipRate&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;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;businessDays&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;Novamente, podemos criar um Adapter:&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FastShipAdapter&lt;/span&gt;
        &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ShippingProvider&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;FastShipClient&lt;/span&gt; &lt;span class="n"&gt;client&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;FastShipAdapter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;FastShipClient&lt;/span&gt; &lt;span class="n"&gt;client&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&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;ShippingQuote&lt;/span&gt; &lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;ShippingRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;FastShipPayload&lt;/span&gt; &lt;span class="n"&gt;payload&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;FastShipPayload&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;originZip&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;destinationZip&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;weightKg&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;FastShipRate&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&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;ShippingQuote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"Fast Ship"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;businessDays&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;p&gt;Apesar de as duas APIs externas serem diferentes, para o restante do sistema elas agora possuem exatamente o mesmo contrato:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ShippingQuote&lt;/span&gt; &lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ShippingRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse é o principal benefício do Adapter Pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4.7 O ShippingService
&lt;/h3&gt;

&lt;p&gt;Agora podemos criar um serviço que recebe diversas implementações de &lt;code&gt;ShippingProvider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Comparator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&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;ShippingService&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ShippingProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;providers&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;ShippingService&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;ShippingProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;providers&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;providers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;providers&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;ShippingQuote&lt;/span&gt; &lt;span class="nf"&gt;bestQuote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;ShippingRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                        &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comparing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="nl"&gt;ShippingQuote:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;
                    &lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;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="nf"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="s"&gt;"Nenhuma transportadora disponível."&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;p&gt;Observe que não existe um &lt;code&gt;if&lt;/code&gt; ou &lt;code&gt;switch&lt;/code&gt; para tratar cada transportadora.&lt;/p&gt;

&lt;p&gt;O serviço simplesmente sabe que possui objetos capazes de executar &lt;code&gt;quote(request)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A implementação específica deixa de ser responsabilidade dele.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4.8 Utilizando o serviço
&lt;/h3&gt;

&lt;p&gt;Um exemplo simplificado seria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&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;CheckoutDemo&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;ShippingProvider&lt;/span&gt; &lt;span class="n"&gt;legacyProvider&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;LegacyCarrierAdapter&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;LegacyCarrierClientImpl&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ShippingProvider&lt;/span&gt; &lt;span class="n"&gt;fastShipProvider&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;FastShipAdapter&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;FastShipClientImpl&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ShippingService&lt;/span&gt; &lt;span class="n"&gt;shippingService&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;ShippingService&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="n"&gt;legacyProvider&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                &lt;span class="n"&gt;fastShipProvider&lt;/span&gt;
                        &lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ShippingRequest&lt;/span&gt; &lt;span class="n"&gt;request&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;ShippingRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="s"&gt;"75000-000"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="s"&gt;"74000-000"&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;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2.5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ShippingQuote&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="n"&gt;shippingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bestQuote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"Transportadora: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"Frete: R$ "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"Prazo: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deliveryDays&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;" dias"&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;Se uma terceira transportadora for adicionada posteriormente, podemos criar outra implementação de &lt;code&gt;ShippingProvider&lt;/code&gt; e registrá-la no serviço, sem reescrever a lógica de cálculo existente.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.5 Testabilidade
&lt;/h2&gt;

&lt;p&gt;Outra vantagem dessa estrutura aparece nos testes.&lt;/p&gt;

&lt;p&gt;Podemos testar cada Adapter isoladamente:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LegacyCarrierAdapterTest&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;deveConverterQuilogramasParaGramas&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;LegacyCarrierClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LegacyCarrierClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"75000-000"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"74000-000"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;2500&lt;/span&gt;
            &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LegacyCarrierResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="mi"&gt;1890&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;4&lt;/span&gt;
            &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;LegacyCarrierAdapter&lt;/span&gt; &lt;span class="n"&gt;adapter&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;LegacyCarrierAdapter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ShippingRequest&lt;/span&gt; &lt;span class="n"&gt;request&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;ShippingRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="s"&gt;"75000-000"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;"74000-000"&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;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2.5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;ShippingQuote&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="n"&gt;adapter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;assertEquals&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;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"18.90"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deliveryDays&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;p&gt;O teste consegue verificar a lógica do Adapter sem precisar executar todo o checkout.&lt;/p&gt;

&lt;p&gt;Isso facilita encontrar erros em conversões e integrações.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.6 Boas práticas aplicadas
&lt;/h2&gt;

&lt;p&gt;Além do Adapter Pattern, algumas decisões ajudam a manter o projeto organizado.&lt;/p&gt;

&lt;p&gt;A aplicação utiliza &lt;strong&gt;injeção de dependência&lt;/strong&gt;, pois os clientes das transportadoras são recebidos pelo construtor dos Adapters em vez de serem criados internamente.&lt;/p&gt;

&lt;p&gt;Também existe uma separação entre os objetos do domínio e os objetos utilizados pelas APIs externas.&lt;/p&gt;

&lt;p&gt;Por exemplo, &lt;code&gt;ShippingRequest&lt;/code&gt; pertence à aplicação, enquanto &lt;code&gt;FastShipPayload&lt;/code&gt; pertence à integração externa.&lt;/p&gt;

&lt;p&gt;Essa separação evita que alterações realizadas por uma transportadora contaminem diretamente os modelos internos do sistema.&lt;/p&gt;

&lt;p&gt;Outro ponto importante é o uso de &lt;code&gt;BigDecimal&lt;/code&gt; para representar valores monetários, evitando problemas comuns de precisão que podem ocorrer com tipos de ponto flutuante.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.7 Prós e Contras do Adapter Pattern
&lt;/h2&gt;

&lt;p&gt;Como qualquer decisão arquitetural, o Adapter Pattern possui benefícios e custos.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Reduz o acoplamento com bibliotecas e APIs externas.&lt;/li&gt;
&lt;li&gt;Permite manter uma interface consistente dentro da aplicação.&lt;/li&gt;
&lt;li&gt;Facilita a substituição de fornecedores.&lt;/li&gt;
&lt;li&gt;Melhora a testabilidade das integrações.&lt;/li&gt;
&lt;li&gt;Concentra conversões e adaptações em classes específicas.&lt;/li&gt;
&lt;li&gt;Evita espalhar detalhes de APIs externas pelo sistema.&lt;/li&gt;
&lt;li&gt;Facilita adicionar novas integrações.&lt;/li&gt;
&lt;li&gt;Favorece o princípio de responsabilidade única.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Aumenta o número de classes do projeto.&lt;/li&gt;
&lt;li&gt;Cada API externa exige seu próprio Adapter.&lt;/li&gt;
&lt;li&gt;Mudanças frequentes no fornecedor podem exigir manutenção constante do adaptador.&lt;/li&gt;
&lt;li&gt;Em sistemas muito pequenos, a abstração pode ser desnecessária.&lt;/li&gt;
&lt;li&gt;Uma má implementação pode transformar o Adapter em uma classe com responsabilidades demais.&lt;/li&gt;
&lt;li&gt;O padrão não elimina a complexidade da integração: ele organiza e isola essa complexidade.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Portanto, utilizar Adapter para qualquer integração simples também pode gerar complexidade desnecessária.&lt;/p&gt;

&lt;p&gt;O padrão faz mais sentido quando a interface externa realmente é incompatível com o modelo utilizado pelo restante da aplicação.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. Conclusão
&lt;/h1&gt;

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

&lt;p&gt;O Adapter Pattern apresenta uma solução simples para um problema comum na engenharia de software: integrar componentes que possuem interfaces diferentes.&lt;/p&gt;

&lt;p&gt;No cenário apresentado, cada transportadora possuía sua própria forma de calcular frete.&lt;/p&gt;

&lt;p&gt;Sem uma camada de adaptação, o &lt;code&gt;ShippingService&lt;/code&gt; precisaria conhecer os detalhes de cada API, criando alto acoplamento e dificultando a manutenção do código.&lt;/p&gt;

&lt;p&gt;Com a criação da interface &lt;code&gt;ShippingProvider&lt;/code&gt;, o sistema passou a trabalhar com um único contrato.&lt;/p&gt;

&lt;p&gt;As classes &lt;code&gt;LegacyCarrierAdapter&lt;/code&gt; e &lt;code&gt;FastShipAdapter&lt;/code&gt; passaram a ser responsáveis por traduzir a comunicação entre o domínio da aplicação e os serviços externos.&lt;/p&gt;

&lt;p&gt;O resultado é uma arquitetura mais desacoplada, extensível e testável.&lt;/p&gt;

&lt;h2&gt;
  
  
  3.2 Visão Pessoal
&lt;/h2&gt;

&lt;p&gt;Ao estudar o Adapter Pattern, o que mais me chamou atenção foi perceber que um Design Pattern não precisa obrigatoriamente envolver uma solução extremamente complexa.&lt;/p&gt;

&lt;p&gt;A ideia do Adapter é relativamente simples: criar uma camada de tradução entre duas interfaces incompatíveis.&lt;/p&gt;

&lt;p&gt;Mesmo sendo simples, essa decisão pode ter um impacto grande na organização de um projeto.&lt;/p&gt;

&lt;p&gt;Antes de estudar esse padrão, seria natural pensar em adaptar cada nova API diretamente dentro do serviço principal utilizando condicionais e conversões.&lt;/p&gt;

&lt;p&gt;Porém, com o Adapter, fica mais claro que os detalhes de integração pertencem a uma classe específica.&lt;/p&gt;

&lt;p&gt;Também percebi que padrões de projeto não devem ser aplicados apenas porque existem. Eles precisam resolver um problema real.&lt;/p&gt;

&lt;p&gt;Se o sistema possuir apenas uma integração simples e que dificilmente será alterada, talvez criar vários níveis de abstração não seja necessário.&lt;/p&gt;

&lt;p&gt;Por outro lado, quando diferentes APIs precisam conviver dentro de um mesmo sistema, o Adapter pode reduzir bastante o acoplamento e tornar futuras alterações mais seguras.&lt;/p&gt;

&lt;p&gt;Para mim, esse foi um dos principais aprendizados: &lt;strong&gt;Design Patterns não servem apenas para deixar o código mais sofisticado, mas para tornar determinadas mudanças mais fáceis de realizar.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3.3 E você?
&lt;/h2&gt;

&lt;p&gt;Você já precisou integrar uma API que possuía uma estrutura completamente diferente da utilizada pelo seu sistema?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usaria o Adapter Pattern nesse cenário ou escolheria outra abordagem?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compartilhe sua opinião nos comentários.&lt;/p&gt;




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

&lt;p&gt;GAMMA, Erich; HELM, Richard; JOHNSON, Ralph; VLISSIDES, John. &lt;strong&gt;Design Patterns: Elements of Reusable Object-Oriented Software.&lt;/strong&gt; Boston: Addison-Wesley, 1994.&lt;/p&gt;

&lt;p&gt;FOWLER, Martin. &lt;strong&gt;Refactoring: Improving the Design of Existing Code.&lt;/strong&gt; 2. ed. Boston: Addison-Wesley, 2018.&lt;/p&gt;

&lt;p&gt;FREEMAN, Eric; ROBSON, Elisabeth. &lt;strong&gt;Head First Design Patterns.&lt;/strong&gt; 2. ed. Sebastopol: O'Reilly Media, 2020.&lt;/p&gt;

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