<?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: Kauê Gatto</title>
    <description>The latest articles on DEV Community by Kauê Gatto (@kauegatto).</description>
    <link>https://dev.to/kauegatto</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1104706%2F447e224f-06ca-4b4d-bfa7-1771b551e8a4.jpg</url>
      <title>DEV Community: Kauê Gatto</title>
      <link>https://dev.to/kauegatto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kauegatto"/>
    <language>en</language>
    <item>
      <title>O teorema CAP não é a ferramenta ideal para você! (E pra ninguém)</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Fri, 25 Apr 2025 21:10:48 +0000</pubDate>
      <link>https://dev.to/kauegatto/o-teorema-cap-nao-e-a-ferramenta-ideal-para-voce-4ehi</link>
      <guid>https://dev.to/kauegatto/o-teorema-cap-nao-e-a-ferramenta-ideal-para-voce-4ehi</guid>
      <description>&lt;h1&gt;
  
  
  Contexto
&lt;/h1&gt;

&lt;p&gt;Esse texto não tem como propósito apresentar o teorema CAP de maneira aprofundada, e sim promover reflexões e um olhar crítico usando artigos, teoremas e textos feitos levando em consideração a aplicação do teorema no mundo real.&lt;/p&gt;

&lt;p&gt;Boa parte deste texto na real é baseada no paper &lt;em&gt;A Critique of the CAP Theorem&lt;/em&gt; - de Martin Kleppmann, autor também do livro DDIA. Se este artigo te interessar, recomendo a leitura do material original, mais denso e aprofundado em aspectos científicos.&lt;/p&gt;

&lt;p&gt;Para textos que explicam o conceito do CAP, recomendo o incrível &lt;a href="https://fidelissauro.dev/teorema-cap/" rel="noopener noreferrer"&gt;artigo&lt;/a&gt; do Matheus Fidelis&lt;/p&gt;

&lt;h1&gt;
  
  
  Conceito Original
&lt;/h1&gt;

&lt;p&gt;O CAP é um teorema apresentado para classificar sistemas de banco de dados distribuídos, e foi apresentado originalmente na forma "Consistência, DIsponibilidade (Availability) ou Tolerância à &lt;strong&gt;P&lt;/strong&gt;artições, escolha dois." - Significando que você pode ter CA (Consistência e Disponibilidade), CP (Consistência e Tolerância à Partições) ou AP (Disponibilidade e Tolerância à Partições), mas nunca os três. Esse conceito normalmente é representado por meio de um diagrama de Venn&lt;/p&gt;

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

&lt;p&gt;Debates futuros concluíram que essa formulação não é das melhores, principalmente porquê é difícil distinguir entre CA e CP. Se seu sistema não é resistente à partições de rede, como você pode chamar ele de altamente disponível? Mas, se ele é resistente, ele não pode ser classificado como disponível?&lt;/p&gt;

&lt;h2&gt;
  
  
  Ambiguidades
&lt;/h2&gt;

&lt;p&gt;Hoje em dia, muitos autores preferem formular o CAP da seguinte forma: Se não existe partição de rede, um sistema pode ser Consistente e Disponível. Se existe partição de rede, você tem que escolher entre disponibilidade (AP) ou consistência (CP).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Alguns autores definem um sistema CP como um sistema onde a maior parte dos nós de um lado de uma partição irão continuar operando normalmente,  e um sistema CA como um sistema que pode falhar &lt;strong&gt;catastróficamente&lt;/strong&gt; quando ocorrer uma partição de rede. Essas definições não são necessariamente "concordadas", é contraintuitivo chamar um sistema de "disponível", de maneira categórica, se ele pode falhar de maneira catastrófica sob uma partição de rede, enquanto um sistema que continua funcionando é chamado de "indisponível".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Outro ponto apresentado pelo autor é que chamar um sistema de maneira categórica de "Disponível" ou "Indisponível" não necessariamente tem muito sentido, visto que disponibilidade é algo a ser observado, uma métrica, e nenhum sistema será 100% disponível ou indisponível.&lt;/p&gt;

&lt;p&gt;Desta forma, alguns textos &lt;a href="https://codahale.com/you-cant-sacrifice-partition-tolerance/" rel="noopener noreferrer"&gt;2&lt;/a&gt; defendem que você não deve deixar a resistência à partições de rede de lado, &lt;strong&gt;portanto o CA torna-se inviável em termos realistas.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Tradeoff entre latência e consistência
&lt;/h1&gt;

&lt;p&gt;O Ponto do teorema CAP são os tradeoffs que você deve levar em consideração ao escrever e utilizar software, dependendo da maneira a qual ele deve se comportar. Martin Kleppmann abrange isso de outra forma, em minha opinião, mais simples de entender que o modelo original e melhor formalizada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O teorema CAP é simplista demais e mal compreendido demais para ser útil na caracterização de sistemas. Portanto, peço que retiremos todas as referências ao teorema CAP, paremos de falar sobre ele e o deixemos de lado. Em vez disso, deveríamos usar uma terminologia mais precisa para raciocinar sobre nossas compensações. - Martin Kleppman, em seu blog, no post &lt;strong&gt;# Por favor, pare de chamar os bancos de dados de CP ou AP&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se há um &lt;em&gt;delay&lt;/em&gt; (latência) de rede, você deve esperar pelo menos pelo tempo do delay &lt;strong&gt;&lt;em&gt;d&lt;/em&gt;&lt;/strong&gt; para realizar alguma operação (escrita ou leitura) em um software, esse conceito faz sentido porquê seria impossível escrever e ler antes da rede em si, a menos que você tenha memória compartilhada (atualizada só na leitura, ou só na escrita) ou a menos que tenha uma baixa consistência (casual consistency). Note que aqui, já estamos falando de modelos de consistência de dados, esse é um fator essencial para entender o modelo a seguir.&lt;/p&gt;

&lt;h2&gt;
  
  
  Um novo Modelo: Sensível à Latência
&lt;/h2&gt;

&lt;p&gt;Um ponto importante é considerar que o CAP (Como teorema) não leva em conta fatores importantes ao escrever e avaliar software para o mundo real. Se você responde uma chamada em 10 horas por conta de um problema no seu banco de dados, pode classificá-lo como disponível? Quais são os SLA's que devemos levar em consideração para discutir essas terminologias?&lt;/p&gt;

&lt;p&gt;Aqui, o foco principal do modelo proposto por Kleppmann é a latência. Aplicada ao mundo real.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;To find a replacement for CAP with a latency-centric viewpoint we need to examine how operation latency is affected by network latency at different levels of consistency.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Na hora de classificarmos modelos, usaremos uma notação similar ao Big(O), só que ao invés de ser o tamanho do Input, descrevemos  a latência de uma operação como uma função de uma latência de rede.&lt;/p&gt;

&lt;p&gt;A notação big O para latência operacional ignora fatores constantes, como o número de round-trips que um algorítmo realiza, mas captura a essência do que precisamos saber para construir sistemas que podem tolerar falhas de rede: O que acontece quando a latência da rede piora &lt;strong&gt;drásticamente&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Um exemplo apresentado no artigo, mostra, diferentes níveis de consistência e &lt;strong&gt;como&lt;/strong&gt; cada um deles é afetado por uma latência &lt;em&gt;(d)&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.amazonaws.com%2Fuploads%2Farticles%2Feqp9n0v2hrxnqjny8rcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqp9n0v2hrxnqjny8rcl.png" alt="Image description" width="396" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note que isso não significa que você precisa, para todo banco de dados que for buscar, procurar qual estratégia de consistência e replicação entre bancos é utilizada (embora é isso que eu ache), mas deve, ao menos, saber como ele é afetado pela latência, escolhendo a chave correta para cada parafuso. Apesar disso, recomendo a leitura do paper - &lt;a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2011/10/ConsistencyAndBaseballReport.pdf" rel="noopener noreferrer"&gt;Replicated Data Consistency Explained Through Baseball&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outro ponto importante aqui com o modelo sensível à latência é pararmos de classificarmos sistemas como CP ou AP de maneira simplista &lt;a href="https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html" rel="noopener noreferrer"&gt;4&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dentro de um software, você pode ter diferentes operações com &lt;a href="http://groups.csail.mit.edu/tds/papers/Gilbert/Brewer2.pdf" rel="noopener noreferrer"&gt;características diferentes de consistência&lt;/a&gt;.*&lt;/li&gt;
&lt;li&gt;Dentro de um software, definir consistência pode ser complicado

&lt;ul&gt;
&lt;li&gt;O Apache Zookeper, utiliza, para lidar com replicação, o algorítmo de Consenso, que opta por consistência em prol da disponibilidade.&lt;/li&gt;
&lt;li&gt;Apesar disso, o Zookeeper faz com que cada cliente se conecte em um nó, e cada leitura bata nesse nó, portanto, mesmo que hajam escritas mais atualizadas em outro nó, você não as verá&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Podem existir sistemas que não se enquadram nas características definidas no CAP, e fazem total sentido para seu caso de uso.
Portanto, o modelo sensível à latência é mais um - entenda as possibilidades do seu sistema e pense por você mesmo. O ponto é que chamar um sistema de não consistente por não ser linearizável não é o caminho&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;O modelo de sensibilidade à latência tem como objetivo enfatizar como diferentes níveis de consistência são impactados pela latência, portanto, o seu conhecimento advindo do teorema CAP não estava totalmente incorreto.  Quanto mais latência, mais complicado fica de se manter a consistência, e você começa a sacrificar características importantes de seu modelo, como a capacidade de responder mais rapidamente em certos cenários, e até mesmo responder, como um todo, em outros.  &lt;/p&gt;

&lt;h1&gt;
  
  
  Extra:
&lt;/h1&gt;

&lt;p&gt;A partir de agora, entramos mais no lado científico da coisa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incongruências do CAP
&lt;/h3&gt;

&lt;p&gt;O Teorema foi formalizado por Gilbert e Lynch [25, 26].&lt;br&gt;
O primeiro teorema do cap é:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It is impossible in the asynchronous network model to implement a read/write data object that guarantees the following properties:&lt;br&gt;
• Availability&lt;br&gt;
• Atomic consistency&lt;br&gt;
in all fair executions (including those in which messages are lost&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;O problema é que a formalização de Disponibilidade por parte dos autores é:&lt;br&gt;
&lt;em&gt;"For a distributed system to be continuously available, every request received by a non-failing node in the system must result in a response"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Portanto, se todos os nós de um sistema distribuídos estão com problema, ele está automaticamente Disponível pela definição do CAP. Essas e outras incongruências convergiram para a criação de um novo modelo, fácil de se entender e mais correto, mas que abrangesse as mesmas ideias do CAP.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existem bem mais listadas no artigo original.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Terminologia Proposta
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Availability
&lt;/h3&gt;

&lt;p&gt;Is an empirical metric, not a property of an algorithm. It is defined &lt;strong&gt;as the percentage of successful requests (returning a non-error response within a predefined latency bound)&lt;/strong&gt; over some period of system operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Delay-sensitive
&lt;/h3&gt;

&lt;p&gt;describes algorithms or operations that need to wait for network communication to complete, i.e. which have latency proportional to network delay. The opposite is delay-independent. Systems must specify the nature of the sensitivity (e.g. an operation may be sensitive to intra-datacenter delay but independent of inter-datacenter delay). A fully delay-independent system supports disconnected (offline) operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network faults
&lt;/h3&gt;

&lt;p&gt;encompass packet loss (both transient and long-lasting) and unusually large packet delay. Network partitions are just one particular type of network fault; in most cases, systems should plan for all kinds of network fault, and not only partitions. As long as lost packets or failed requests are retried, they can be modeled as large network delay.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fault tolerance
&lt;/h3&gt;

&lt;p&gt;is used in preference to high availability or partition tolerance. The maximum fault that can be tolerated must be specified (e.g. “the algorithm can tolerate up to a minority of replicas crashing or disconnecting”), and the description must also state what happens if more faults occur than the system can tolerate (e.g. all requests return an error, or a consistency property is violated).&lt;/p&gt;

&lt;h3&gt;
  
  
  Consistency
&lt;/h3&gt;

&lt;p&gt;refers to a spectrum of different consistency models (including linearizability and causal consistency), not one particular consistency model. When a particular consistency model such as linearizability is intended, it is referred to by its usual name. The term strong consistency is vague, and may refer to linearizability, sequential consistency or one-copy serializability.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bibliografia
&lt;/h1&gt;

&lt;p&gt;[0] - &lt;a href="https://fidelissauro.dev/teorema-cap/" rel="noopener noreferrer"&gt;https://fidelissauro.dev/teorema-cap/&lt;/a&gt;&lt;br&gt;
[1] -  Kleppman, Martin. A Critique of the CAP Theorem. &lt;a href="https://arxiv.org/pdf/1509.05393" rel="noopener noreferrer"&gt;https://arxiv.org/pdf/1509.05393&lt;/a&gt;&lt;br&gt;
[2] - &lt;a href="https://codahale.com/you-cant-sacrifice-partition-tolerance/" rel="noopener noreferrer"&gt;https://codahale.com/you-cant-sacrifice-partition-tolerance/&lt;/a&gt;&lt;br&gt;
[3] - Terry, Doug. Replicated Data Consistency Explained Through Baseball &lt;a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2011/10/ConsistencyAndBaseballReport.pdf" rel="noopener noreferrer"&gt;https://www.microsoft.com/en-us/research/wp-content/uploads/2011/10/ConsistencyAndBaseballReport.pdf&lt;/a&gt;&lt;br&gt;
[4] - &lt;a href="https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html" rel="noopener noreferrer"&gt;https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>brdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Arquiteturas Orientadas à Eventos, Microserviços e Monolitos Modulares</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Sat, 15 Feb 2025 19:33:50 +0000</pubDate>
      <link>https://dev.to/kauegatto/arquiteturas-orientadas-a-eventos-microservicos-e-monolitos-modulares-5ed5</link>
      <guid>https://dev.to/kauegatto/arquiteturas-orientadas-a-eventos-microservicos-e-monolitos-modulares-5ed5</guid>
      <description>&lt;p&gt;Esse post surgiu de uma experiências que estou obtendo ao desenvolver um sistema monolítico modular com golang e arquitetura orientada à eventos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kauegatto/modular-ecommerce" rel="noopener noreferrer"&gt;https://github.com/kauegatto/modular-ecommerce&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visite meu blog, onde posto os textos finalizados (tem mais conteúdo lá):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kaue.cat" rel="noopener noreferrer"&gt;kaue.cat&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Arquitetura Orientada à Eventos, Microserviços e Monolitos
&lt;/h1&gt;

&lt;p&gt;Se você é desenvolvedor, é provável que já tenha ouvido falar sobre alguns conceitos comuns: &lt;strong&gt;SOLID&lt;/strong&gt;, &lt;strong&gt;Acoplamento&lt;/strong&gt;, &lt;strong&gt;Coesão&lt;/strong&gt;, etc. Ao trabalhar com sistemas, conhecemos vantagens e desafios de diferentes tipos de arquiteturas à nível de software e solução, e entendemos como esses conceitos impactam a experiência, tempo e qualidade de um software.&lt;/p&gt;

&lt;p&gt;Desde a última década, &lt;strong&gt;Microserviços&lt;/strong&gt; se tornaram um desses conceitos fundamentais, e suas vantagens e desvantagens começaram a ser mais palpáveis conforme a adoção desse tipo de arquitetura em sistemas reais. Sistemas distribuídos orientados à serviços são frequentemente vendidos como a solução ideal para todos os sistemas, enquanto isso, outros autores argumentam exatamente o contrário.&lt;/p&gt;

&lt;p&gt;Sam Newmann, em seu livro "Construindo Microserviços":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Infelizmente as pessoas passaram a ver os sistemas monolíticos como algo a ser evitado, isto é, algo que é inerentemente problemático. Uma arquitetura monolítica é uma opção, e uma opção válida. Eu poderia ir além e dizer que, em minha opinião, é a opção padrão sensata como estilo de arquitetura.&lt;br&gt;
Em outras palavras, estou procurando um motivo para ser convencido a utilizar microserviços, em vez de procurar um motivo para não usar"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No mesmo livro, outras arquiteturas são apresentadas, dentre elas o "Sistema Monolítico Modular":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Para muitas empresas, o sistema monolítico modular pode ser uma excelente opção. Se as fronteiras dos módulos forem bem definidas, é possível ter um grau elevado de paralelismo nos trabalhos, ao mesmo tempo que os problemas da arquitetura de microserviços, mais distribuída, são evitados, pois há uma topologia muito mais simples para implantação. A Shopify é um ótimo exemplo de uma empresa que empregou essa técnica como uma alternativa à decomposição em microserviços e parece fnucionar muito bem para essa empresa"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E então:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Um sistema distribuído é um sistema no qual a falha de um computador que você nem sabia que existia pode deixar seu prório computador inutilizável" - Leslie Lampert&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Um ponto que favorece bastante monolitos modularizados é a fácil capacidade de transformar módulos em serviços independentes (Microserviços), conforme a necessidade passe a existir. Aproveitando o baixo acoplamento entre os módulos, essa alteração se torna mais simples pois evita mexer em outras partes do sistema (No máximo nos &lt;em&gt;adaptadores&lt;/em&gt;, responsáveis por se comunicar com esse novo serviço), visto que módulos agem como uma camada de isolamento.&lt;/p&gt;

&lt;p&gt;De maneira geral, tendo a pensar que para organizações menores, prova de conceitos ou outros casos de uso, microserviços podem não ser o ideal para você, apesar disso, o foco do artigo é menos nesses dois tipos de arquitetura, e sim como ambos podem se beneficiar (ou não) de um sistema de comunicação assí baseado em eventos.&lt;/p&gt;

&lt;p&gt;Independente se você está produzindo seu software em uma arquitetura realmente distribuída ou só modularizada, um ponto importante é garantir o baixo acomplamento e alta coesão desses módulos ou serviços.&lt;/p&gt;

&lt;h1&gt;
  
  
  Protegendo seu código de acoplamento ruim
&lt;/h1&gt;

&lt;p&gt;Acoplamento sempre existirá, livros como &lt;em&gt;&lt;strong&gt;"OOP e Solid para Ninjas"&lt;/strong&gt;&lt;/em&gt; - de Mauricio Aniche e &lt;em&gt;&lt;strong&gt;"Desbravando SOLID"&lt;/strong&gt;&lt;/em&gt; - de Alexandre Aquiles enfatizam isso, mas principalmente, a diferença entre um acoplamento bom e ruim.&lt;/p&gt;

&lt;p&gt;De maneira geral, acoplamento está intrinsecamente relacionado à coesão. Módulos com pouco acoplamento ruim são coesos, se elementos de código mudam em conjunto, eles devem se manter em conjunto, assim, quando algum desses elementos mudar, isso não exige alteração em múltiplas partes de seu sistema de uma vez, o que seria um forte indicativo que a coesão do seu sistema não é das melhores.&lt;/p&gt;

&lt;p&gt;Um exemplo: Regras de negócio de compras devem se manter no módulo e &lt;strong&gt;contexto&lt;/strong&gt; de compras, se esse módulo começar a fazer suposições e uso de partes que não pertencem a esse módulo, isso com certeza não é um acoplamento tão bom. Agora suponha que você está fazendo um código que &lt;strong&gt;com certeza&lt;/strong&gt; não tem perspectivas de mudar de ORM, criar camadas de abstração talvez seja um trabalho desnecessário, que pode inclusive poluir sua base de código.&lt;/p&gt;

&lt;p&gt;Ao desenhar e modelar um Sistema Modular, queremos sempre que os módulos possuam &lt;strong&gt;baixo acoplamento&lt;/strong&gt; entre si. Como isso fica no código? Uma forma interessante é, sempre que possível, expor &lt;strong&gt;contratos&lt;/strong&gt; entre diferentes módulos, evitando uma comunicação direta. Outra maneira de evitar acoplamento é evitar que um módulo acesse recursos como banco de dados de outro sob responsabilidade de outro módulo - isso é frequentemente chamado de &lt;em&gt;database-per-service&lt;/em&gt;- isso provavelmente traria para o módulo consumidor preocupações sobre tratamento de dados que deveriam estar no módulo que é o responsável pelo banco.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modelos de Comunicação Síncronos e Assíncronos
&lt;/h2&gt;

&lt;p&gt;Aqui, entraremos em um debate sobre &lt;strong&gt;padrões de comunicação&lt;/strong&gt; síncronos e assíncronos.&lt;br&gt;
Recomendo a leitura de dois excelentes posts do Matheus Fidelis que se aprofundam bem mais no tema:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://fidelissauro.dev/padroes-de-comunicacao-sincronos/" rel="noopener noreferrer"&gt;https://fidelissauro.dev/padroes-de-comunicacao-sincronos/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fidelissauro.dev/mensageria-eventos-streaming/" rel="noopener noreferrer"&gt;https://fidelissauro.dev/mensageria-eventos-streaming/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Se tratando de Sistemas Modulares (sejam eles Microserviços ou não), um fator principal a ser levado em consideração é o acoplamento entre sistemas. A maneira com que eles se comunicam é um alto contribuínte nessa "métrica":&lt;/p&gt;

&lt;p&gt;De maneira geral, podemos dividir a comunicação em duas grandes categorias:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Padrão síncrono - Request/response&lt;br&gt;
A chamada é feita por um cliente à um servidor, que eventualmente response a chamada pela mesma conexão, que se mantém aberta até a resposta acontecer.&lt;br&gt;
Note que aqui, o protocolo de comunicação é síncrono, mesmo que você crie alguma thread para processar esse tipo de mensagem de forma assíncrona, de maneira não bloqueante, &lt;strong&gt;isso não torna seu protocolo assíncrono, apenas seu processamento.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Padrão de Comunicação Assíncrono&lt;br&gt;
A conexão entre quem pede a mensagem e o servidor não fica aberta esperando pela resposta em um tempo específico. Em algum momento, o servidor notifica o processamento da informação, normalmente o servidor faz a chamada proativa de chamar seus clientes via webhook ou simplesmente publica mensagens ou eventos sem se preocupar com quem e quando essa notificação será processada.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Baseado em Mensagens - Aqui, sabemos qual nosso destinatário, normalmente enviamos &lt;strong&gt;comandos&lt;/strong&gt; para outros serviços, como por exemplo: Atualize o Pedido x. (Figura 1). Existe uma variação assíncrona do modelo Request/Response comummente chamada de request-reply, onde a comunicação entre cliente/servidor se dá por meio de filas.&lt;/li&gt;
&lt;li&gt;Baseado em Eventos - Aqui, sua aplicação notifica eventos, coisas que aconteceram sob seu domínio. Se um pedido é pago, o serviço de pagamentos é responsável por enviar um evento de "Pagamento Concluído", para que &lt;strong&gt;quem necessitar&lt;/strong&gt; dessa informação, use-a. Aqui, a aplicação que propaga eventos não sabe quem irá consumi-los. (Figura 2)

&lt;ol&gt;
&lt;li&gt;Costumamos chamar esses eventos de &lt;em&gt;"Eventos de Integração"&lt;/em&gt;, pois se comunica com um &lt;em&gt;"Bounded Context"&lt;/em&gt; diferente.&lt;/li&gt;
&lt;li&gt;Eventos normalmente são publicados em um sistema apartado, conhecido como Event Bus. Kafka é capaz de realizar a tarefa que um event bus realiza, RabbitMQ é um event bus, NATS.io também.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftleok3v9g8d5j30u5r8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftleok3v9g8d5j30u5r8g.png" alt="Image description" width="719" height="266"&gt;&lt;/a&gt;&lt;br&gt;
*Figura 1. Extraído de &lt;a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/" rel="noopener noreferrer"&gt;.NET Microservices: Architecture for Containerized .NET Applications&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo6ujat3mpsmewd35kq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo6ujat3mpsmewd35kq4.png" alt="Image description" width="800" height="362"&gt;&lt;/a&gt;&lt;br&gt;
Figura 2. Extraído de &lt;a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/" rel="noopener noreferrer"&gt;.NET Microservices: Architecture for Containerized .NET Applications&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sincronismo Vs Assíncronismo
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[❗] NOTA&lt;br&gt;
Ao usar event bus externo com um monolito, fazer chamadas de rede é algo que deve ser evitado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  O Caminho Síncrono
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Uma abordagem popular é implementar microsserviços baseados em HTTP (REST), devido à sua simplicidade. Uma abordagem baseada em HTTP é perfeitamente aceitável; a questão aqui está relacionada a como você a utiliza. Se você usa requisições e respostas HTTP apenas para interagir com seus microsserviços a partir de aplicações cliente ou de API Gateways, tudo bem. Mas se você criar longas cadeias de chamadas HTTP síncronas entre microsserviços, comunicando-se através de suas fronteiras como se os microsserviços fossem objetos em uma aplicação monolítica, sua aplicação eventualmente terá problemas.&lt;br&gt;
 &lt;a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/" rel="noopener noreferrer"&gt;.NET Microservices: Architecture for Containerized .NET Applications&lt;/a&gt; pg.35&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O problema aqui se dá principalmente pela cadeia de serviços, se você se comunica de maneira síncrona com um serviço, ele provavelmente pode se comunicar de maneira síncrona com outro, em uma cadeia que pode ser infinita. Caso um desses sistemas falhe (e eventualmente vão falhar), você terá um problema.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Na verdade, se seus microsserviços internos estão se comunicando criando cadeias de requisições HTTP como descrito, pode-se argumentar que você tem uma aplicação monolítica, mas baseada em HTTP entre processos em vez de mecanismos de comunicação intra-processo.&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/" rel="noopener noreferrer"&gt;.NET Microservices: Architecture for Containerized .NET Applications&lt;/a&gt; pg.35&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Apesar disso, note que programar um serviço síncrono provê código muito mais simples de ser seguido pelo fluxo de execução natural, mais simples de ser desenvolvido, mas provavelmente menos resiliente. Caso queira forçar resiliência em padrões síncronos, com retries com backoff exponencial, circuit breakers, você acaba perdendo o que &lt;em&gt;na minha opinião&lt;/em&gt; é a maior vantagem desse tipo de comunicação, a simplicidade.&lt;/p&gt;

&lt;h3&gt;
  
  
  O Caminho Assíncrono
&lt;/h3&gt;

&lt;p&gt;Um código orientado à eventos possui uma boa quantidade de desafios associados - Consistência Eventual, Duplicação de mensagens, configuração de um serviço externo, &lt;strong&gt;mas oferece mais resiliência de forma que processos assíncronos podem ser feitos em algum momento no futuro, podendo deixar seu sistema &lt;em&gt;parcialmente&lt;/em&gt; operante em casos de falha de alguns módulos.&lt;/strong&gt; Note que isso aqui nos remete fortemente ao teorema CAP, onde temos que escolher entre &lt;em&gt;Consistência&lt;/em&gt; e &lt;em&gt;Disponibilidade&lt;/em&gt;. Não temos como manter nossa aplicação consistente se algum de nossos serviços caiu e precisamos nos comunicar com ele naquele momento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Em um sistema de e-commerce, você não quer que sua aplicação deixe de receber pedidos porquê o adquirente que está integrado caiu, ou porquê seu módulo de processamento está bugado, ao deixar esses eventos / pedidos guardados para reprocessamento no futuro, você evita qualquer perda financeira.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esse texto, como uma explicação para decisões e desafios acerca de um projeto pessoal, reflete minha decisão: Nesse projeto, fui com a arquitetura orientada à eventos principalmente por questões de aprendizado.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conceitos Importantes de uma comunicação assíncrona
&lt;/h1&gt;

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

&lt;p&gt;Revisitando o exemplo anterior do E-commerce, onde você não quer deixar de registrar pedidos:&lt;br&gt;
Supondo que você registre os pedidos, mas por algum tipo de falha, não consiga enviar esse pedido para o &lt;em&gt;Event Bus&lt;/em&gt;, isso significa que outras aplicações não receberão essa notificação que o pedido foi feito, o mesmo pode acontecer para qualquer domínio. &lt;strong&gt;Esse tipo de atraso na atualização de alguns dados é chamado de consistência eventual, o seu sistema, eventualmente, se tornará consistente.&lt;/strong&gt; É importante avisar ao usuário como a consistência eventual pode o impactar, resultando que pedidos pagos não mostrem na hora, que dados salvos em seu perfil não apareçam imediatamente, etc.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[❗] NOTA&lt;br&gt;
Em alguns lugares, é capaz que o termo &lt;em&gt;["Consistência Posterior"&lt;/em&gt;](&lt;a href="https://pt.wikipedia.org/wiki/Consist%C3%AAncia_posterior" rel="noopener noreferrer"&gt;https://pt.wikipedia.org/wiki/Consist%C3%AAncia_posterior&lt;/a&gt;) seja empregado, pela semântica da palavra "Eventual" no português, que está mais próximo do "Ocasionalmente". Quando falamos de consistência "&lt;em&gt;eventual&lt;/em&gt;", o sistema &lt;strong&gt;irá&lt;/strong&gt; ficar consistente em algum momento no futuro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Entregas de Mensagens
&lt;/h2&gt;

&lt;p&gt;Sistemas que tratam envio de mensagens trabalham com diferentes tipos de garantia (que podem, ou não, ser configurados)&lt;/p&gt;

&lt;h3&gt;
  
  
  At Least Once
&lt;/h3&gt;

&lt;p&gt;Em sistemas que garantem entrega "At Least Once", toda mensagem será entregue pelo menos uma vez ao consumidor. Isso significa que, em casos de falha ou timeout, o sistema pode reenviar a mesma mensagem, resultando em possíveis duplicatas. Esse modelo é especialmente útil quando perder uma mensagem é inaceitável - por exemplo, em sistemas de pagamento onde perder uma transação seria catastrófico.&lt;br&gt;
Em um sistema que tenta automaticamente se recuperar de falhas, a mesma mensagem poderia ser enviada múltiplas vezes. Graças à falhas de hardware e rede, o receptor deve ser capaz de implementar uma operação de processamento dessas mensagens que seja idempotente.&lt;/p&gt;

&lt;h3&gt;
  
  
  At Most Once
&lt;/h3&gt;

&lt;p&gt;Na garantia "At Most Once", o sistema garante que uma mensagem será entregue no máximo uma vez. Se houver falha na entrega, a mensagem será perdida ao invés de ser reenviada. Esse modelo é útil em cenários onde duplicatas são mais problemáticas que perdas - como em sistemas de métricas ou logs, onde perder algumas mensagens é aceitável, mas duplicatas poderiam distorcer análises.&lt;/p&gt;

&lt;h3&gt;
  
  
  DEDUP (Deduplicação)
&lt;/h3&gt;

&lt;p&gt;A deduplicação é uma estratégia fundamental, especialmente quando se usa "At Least Once". Deduplicação é exatamente o que seu nome implica, removendo mensagens duplicadas de uma lista.&lt;br&gt;
Existem várias formas de implementar deduplicação, como identificadores únicos para uma mesma mensagem. Note que dedup garante Idempotência, onde diferentes requisições ou eventos com o mesmo conteúdo têm o mesmo resultado. Frequentemente sistemas garantem à você at-least-once, e ter idempotência é uma obrigatoriedade!&lt;br&gt;
A maior parte dos &lt;em&gt;Event Buses&lt;/em&gt; possuem jeitos de lidar com a deduplicação de mensagens, mas também podemos fazer isso no código de destino do seu Microserviço (como verificar um messageId, ou se for um evento de pedido pago, o OrderId, visto que um pedido não pode ser pago mais de uma vez), talvez ter as validações em ambas as pontas seja a melhor opção.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outros Problemas
&lt;/h2&gt;

&lt;p&gt;Outros problemas que podem surgir ao lidar com sistemas assícronos são:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ordenação de mensagens, happens-before. &lt;a href="https://www.youtube.com/watch?v=OKHIdpOAxto" rel="noopener noreferrer"&gt;Vídeo sobre o assunto&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Transações distribuidas. &lt;a href="https://newsletter.simpleaws.dev/p/distributed-transactions-event-driven-architectures" rel="noopener noreferrer"&gt;Artigo sobre o assunto&lt;/a&gt;
# Garantindo a Publicação de Eventos e Consistência&lt;/li&gt;
&lt;li&gt;Ao publicar em um Event Bus, diversos problemas podem acontecer: Partições de rede, indisponibilidade do bus, queda do seu módulo. Todos esses cenários podem resultar na perda de mensagens.&lt;/li&gt;
&lt;li&gt;Outro problema é a alteração no estado interno de um objeto de domínio dentro do seu bounded context ser notificada de maneira errônea&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  E se nossa mensagem nem for enviada?
&lt;/h2&gt;

&lt;p&gt;Outro ponto importante e frequente, que decidi dar um pouco mais de prioridade é: E se nossa mensagem nem for enviada ao event bus? e se ele cair?&lt;/p&gt;

&lt;p&gt;Existem alguns padrões e técnicas que nos permitem lidar com esse tipo de situação, uma delas é o &lt;strong&gt;Outbox&lt;/strong&gt;, onde temos uma &lt;strong&gt;tabela em algum armazenamento persistente (normalmente um banco de dados)&lt;/strong&gt; responsável por informar que um evento está pendente de ser enviado:&lt;br&gt;
Fazemos a alteração da nossa entidade de domínio em uma transação junto com a inserção do evento como "pendente". Caso dê errado, nem nosso objeto nem o evento ficam inconsistentes&lt;/p&gt;

&lt;p&gt;Caso essa transação seja concluída, temos essa tabela, avisando que o evento deve ocorrer, e um outro serviço (normalmente chamado de &lt;em&gt;worker&lt;/em&gt;) processará ele em caso de falhas, reenviando o evento.&lt;/p&gt;

&lt;p&gt;Note que com essa abordagem, você persiste apenas os eventos de &lt;strong&gt;integração&lt;/strong&gt; de origem de cada microserviço. Outras abordagens (Como Event Sourcing - Que não irei abordar aqui), podem necessitar que você armazene mais eventos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo real
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;catalogItem&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;raiseProductPriceChangedEvent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;IntegrationEvent&lt;/span&gt; &lt;span class="n"&gt;priceChangedEvent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;catalogItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;productToUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;raiseProductPriceChangedEvent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raiseProductPriceChangedEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Create event if price has changed&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;oldPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;catalogItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;priceChangedEvent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ProductPriceChangedIntegrationEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;catalogItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;productToUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;oldPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Update current product&lt;/span&gt;
&lt;span class="n"&gt;catalogItem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;productToUpdate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Just save the updated product if the Product's Price hasn't changed.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;raiseProductPriceChangedEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_catalogContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="c1"&gt;// Publish to event bus only if product price changed&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Achieving atomicity between original DB and the IntegrationEventLog&lt;/span&gt;
    &lt;span class="c1"&gt;// with a local transaction&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_catalogContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BeginTransaction&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_catalogContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CatalogItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;catalogItem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_catalogContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_integrationEventLogService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveEventAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priceChangedEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Publish the integration event through the event bus&lt;/span&gt;
    &lt;span class="n"&gt;_eventBus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;priceChangedEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;_integrationEventLogService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MarkEventAsPublishedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;priceChangedEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou seja:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Se o Banco cair?

&lt;ol&gt;
&lt;li&gt;Se essa operação for uma reação à um evento, a mensagem não será processada, para que possa ser processada em um momento futuro. Mantemos consistência e faremos o que for necessário, assim que possível.&lt;/li&gt;
&lt;li&gt;Se for fruto de uma chamada síncrona, podemos retornar um erro. De qualquer forma, o sistema não fica inconsistente.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Se não conseguirmos publicar no event bus?

&lt;ol&gt;
&lt;li&gt;Será publicado depois, teremos um log de que o evento está pronto para a publicação, nosso domínio interno estará atualizado, mas os outros não. Como trabalhamos com consistência eventual, é um cenário completamente ok!&lt;/li&gt;
&lt;li&gt;Se o banco cair na hora de salvarmos como enviado, enviaremos o evento novamente, por isso a importância da idempotência&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Esse tipo de cenário enfatiza como a alta resiliência de uma aplicação pode ser alcançada com mais facilidade usando um padrão de comunicação assíncrono por meio de eventos e mensagens &lt;/p&gt;

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

&lt;p&gt;A função deste texto é dar introdução à arquiteturas síncronas, assíncronas e orientadas à eventos, mostrando vantagens, desafios e técnicas comuns. Os posts posteriores darão mais ênfase na arquitetura à nivel dos módulos - Como desenhar os bounded contexts, quanto de informação colocar nos eventos de integração, etc.&lt;/p&gt;

&lt;p&gt;Espero que tenham gostado!&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Construindo Microserviços - Sam newman&lt;/li&gt;
&lt;li&gt;OOP e SOLID para ninjas&lt;/li&gt;
&lt;li&gt;Desbravando SOLID&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=s8cvn2TUXoM&amp;amp;t=136s" rel="noopener noreferrer"&gt;EVENT STORMING - DOMAIN DRIVEN DESIGN, EVENT SOURCING E CQRS! - YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=bxGkavGaEiM&amp;amp;t=626s" rel="noopener noreferrer"&gt;Message Driven Architecture to DECOUPLE a Monolith - YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=VGShtGU3hOc&amp;amp;t=9s" rel="noopener noreferrer"&gt;Long live the Monolith! Monolithic Architecture != Big Ball of Mud - YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/" rel="noopener noreferrer"&gt;# .NET Microservices: Architecture for Containerized .NET Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://newsletter.simpleaws.dev/p/distributed-transactions-event-driven-architectures" rel="noopener noreferrer"&gt;https://newsletter.simpleaws.dev/p/distributed-transactions-event-driven-architectures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fidelissauro.dev/mensageria-eventos-streaming/" rel="noopener noreferrer"&gt;Mensageria, Eventos, Streaming e Arquitetura Assincrona&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fidelissauro.dev/padroes-de-comunicacao-sincronos/" rel="noopener noreferrer"&gt;Padrões de Comunicação Síncronos&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>brdev</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>1. Concorrência Java: Threads! Processando em Paralelo e Ganhando Throughput</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Fri, 31 May 2024 03:00:00 +0000</pubDate>
      <link>https://dev.to/kauegatto/1-concorrencia-java-threads-processando-em-paralelo-e-ganhando-throughput-426</link>
      <guid>https://dev.to/kauegatto/1-concorrencia-java-threads-processando-em-paralelo-e-ganhando-throughput-426</guid>
      <description>&lt;p&gt;Seja bem vindo, esse daqui é o primeiro de 6 posts sobre concorrência em &lt;/p&gt;

&lt;h1&gt;
  
  
  Contexto
&lt;/h1&gt;

&lt;p&gt;Threads são unidades de execução dentro de um processo. Um processo é um programa em execução que contém pelo menos uma thread. As threads permitem que um programa execute várias tarefas ao mesmo tempo (ou pelo menos aparentemente).&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Vantagens de programar com múltiplas threads:&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Uma das principais razões para usar múltiplas threads é melhorar o desempenho de um programa. Tarefas pesadas e demoradas podem ser divididas em threads separadas, permitindo que diferentes partes do programa sejam executadas em paralelo. Isso pode levar a uma utilização mais eficiente dos recursos da CPU e, consequentemente, a um tempo de resposta mais rápido.&lt;/p&gt;

&lt;p&gt;![[Untitled 109.png|Untitled 109.png]]&lt;br&gt;
No entanto, programar com threads também traz desafios, como a necessidade de lidar com concorrência (quando várias threads tentam acessar ou modificar os mesmos recursos ao mesmo tempo) e a possibilidade de erros difíceis de depurar (como as condições de corrida), pois os resultados de um mesmo código não serão necessariamente os mesmos (não determinísticos).&lt;/p&gt;
&lt;h1&gt;
  
  
  O multithreading ajuda ou não?
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;1. Operações de I/O:&lt;/strong&gt;&lt;br&gt;
Quando um programa precisa realizar operações de entrada/saída -- I/O (e elas são o gargalo), como leitura/gravação de arquivos, comunicação com bancos de dados ou solicitações de rede, há frequentemente momentos em que a CPU fica ociosa, esperando que os dados sejam lidos ou escritos.&lt;br&gt;
Nessa situação, se uma nova thread tomasse conta da situação, ela não seria mais executada pelo processador enquanto estivesse ociosa, pois aconteceria o que chamamos de troca de contexto, que é basicamente fazer com que outra thread seja processada. Isso permite que outras threads que necessitem de processamento real tenham suas operações executadas pelos núcleos da CPU, ou até mesmo lançar (ou usar) mais threads para já lançar outras chamadas que também exigem esse tempo de espera, conhecidas como bloqueantes. Isso ajuda a aproveitar melhor o tempo da CPU, &lt;strong&gt;melhorando a eficiência geral do programa.&lt;/strong&gt;&lt;br&gt;
Imagine um contexto onde você precisa ler dois arquivos .txt, essa operação poderia ser realizada paralelamente se lançássemos duas threads, uma para ler cada arquivo, sendo cada uma processada em um núcleo, diminuindo o tempo de execução essencialmente pela metade&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Código CPU-bound:&lt;/strong&gt;&lt;br&gt;
Quando o programa está executando tarefas intensivas em CPU, como cálculos matemáticos complexos, simulações ou processamento de imagem, uma única thread pode não ser capaz de aproveitar totalmente a capacidade de processamento da CPU. Dividir essas tarefas em threads separadas permite que múltiplos núcleos da CPU trabalhem em paralelo, acelerando o processamento.&lt;br&gt;
Nesse caso, devemos tomar cuidado, pois a quantidade de tarefas que pode ser paralelizada realmente é igual a quantidade de núcleos do seu processador (lógicos + físicos).&lt;/p&gt;

&lt;p&gt;![[Pasted image 20240404211738.png]]&lt;br&gt;
A imagem acima representa a troca de contexto, note que esse processo não é necessariamente instantâneo e resulta em possível perda de cache, o que pode ser agressor à performance - &lt;a href="https://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-05.pdf"&gt;Fonte&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A frequência de trocas de contexto tem impacto na eficiência do sistema operacional: quanto menor o número de trocas de contexto e menor a duração de cada troca, mais tempo sobrará para a execução das tarefas em si. Assim, é possível definir uma medida de eficiência E do uso do processador, em função das durações médias do quantum de tempo &lt;em&gt;t&lt;/em&gt; e da troca de contexto &lt;em&gt;c&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Java: Threads!
&lt;/h1&gt;
&lt;h2&gt;
  
  
  O Objeto Thread
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;O objeto &lt;code&gt;java.lang.Thread&lt;/code&gt; é um &lt;em&gt;wrapper&lt;/em&gt; em cima das threads do sistema operacional&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!important]&lt;br&gt;
Note que as Threads são objetos wrappers em torno das threads do SO, portanto, se essas threads do S.O são pesadas (e são), as Threads em Java também são.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em Java, podemos trabalhar com threads de algumas maneiras, a primeira que veremos é com a classe Thread, essas classes precisam dar o override do método &lt;code&gt;run&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThreadExample&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ThreadExample&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="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;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&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;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nComeçouuu!: %s\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="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;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&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;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="cm"&gt;/* Todo programa em execução é "feito" de threads, esse não é uma exceção*/&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;ThreadExample&lt;/span&gt; &lt;span class="n"&gt;t1&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;ThreadExample&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;ThreadExample&lt;/span&gt; &lt;span class="n"&gt;t2&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;ThreadExample&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'B'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;ThreadExample&lt;/span&gt; &lt;span class="n"&gt;t3&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;ThreadExample&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'C'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&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;![[Untitled 110.png|Untitled 110.png]]&lt;/p&gt;

&lt;p&gt;Pronto! (Só que não) → Note que os objetos thread ainda estão rodando na mesma thread, nesse caso, usar &lt;code&gt;Thread.run()&lt;/code&gt; executa o método run, nao inicia a thread, nesse caso, devemos rodar &lt;code&gt;start()&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Thread01&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="cm"&gt;/* Todo programa em execução é "feito" de threads, esse não é uma exceção*/&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;ThreadExample&lt;/span&gt; &lt;span class="n"&gt;t1&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;ThreadExample&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;ThreadExample&lt;/span&gt; &lt;span class="n"&gt;t2&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;ThreadExample&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'B'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;ThreadExample&lt;/span&gt; &lt;span class="n"&gt;t3&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;ThreadExample&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'C'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&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;![[Untitled 1 70.png|Untitled 1 70.png]]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!question] Reflexão&lt;br&gt;
Criar um objeto do tipo thread faz sentido? Você está especializando uma thread realmente? A herança faz sentido nesse caso? [[2. SOLID]]&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Interface Runnable
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nesse caso, acho válido começar diferente, vamos ler uma parte da javadoc da classe runnable&lt;/p&gt;

&lt;h2&gt;
  
  
  0. Javadoc
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. The class must define a method of no arguments called run.&lt;/p&gt;

&lt;p&gt;In addition, Runnable provides the means for a class to be active while not subclassing Thread. A class that implements &lt;code&gt;Runnable&lt;/code&gt; can run without subclassing Thread by instantiating a Thread instance and passing itself in as the target.&lt;br&gt;
&lt;strong&gt;In most cases, the Runnable interface should be used if you are only planning to override the run() method and no other Thread methods. This is important because classes should not be subclassed unless the programmer intends on modifying or enhancing the fundamental behavior of the class.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A documentação do JAVA responde perfeitamente a reflexão anterior, se você discorda, pode seguir em frente, mas &lt;em&gt;particularmente&lt;/em&gt; acho que é um argumento difícil de rebater.&lt;/p&gt;

&lt;p&gt;Exemplo:&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;ThreadRunnable&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ThreadRunnable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="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;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&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;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nComeçouuu!: %s\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="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;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&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;Thread01&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="cm"&gt;/* Todo programa em execução é "feito" de threads, esse não é uma exceção*/&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&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;t1Runnable&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;ThreadRunnable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'a'&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;t2Runnable&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;ThreadRunnable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'b'&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;t3Runnable&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;ThreadRunnable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'c'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t1&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;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1Runnable&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t2&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;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t2Runnable&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t3&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;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t3Runnable&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&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;![[Untitled 2 56.png|Untitled 2 56.png]]&lt;/p&gt;

&lt;h1&gt;
  
  
  Estados de uma thread
&lt;/h1&gt;

&lt;p&gt;![[Untitled 3 42.png|Untitled 3 42.png]]&lt;br&gt;
É interessante sabermos disso, pois podemos dar dicas para o S.O como dizer para que uma thread running pare, ou notificando que uma thread se tornou &lt;em&gt;Runnable&lt;/em&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Melhorando o Código
&lt;/h1&gt;

&lt;p&gt;Se não precisarmos de construtor! podemos usar uma  lambda, pois Runnable é uma &lt;code&gt;@FunctionalInterface&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="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t1&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;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*codigo*/&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou, um pouco mais verboso:&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;Runnable&lt;/span&gt; &lt;span class="n"&gt;simplerRunnable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="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;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nComeçouuu!: %s\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="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;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prioridade
&lt;/h2&gt;

&lt;p&gt;Prioridades podem ser atribuídas à threads, conforme mostra o código:&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;Thread&lt;/span&gt; &lt;span class="n"&gt;t3&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;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t3Runnable&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"nomeC"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPriority&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MAX_PRIORITY&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;![[Untitled 111.png|Untitled 111.png]]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!important]&lt;br&gt;
Note que prioridades são indicações do que você deseja para o scheduler, uma thread de prioridade 1 pode rodar andar da prioridade 10, você não deve desenvolver um código baseado em prioridade&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Sleep
&lt;/h2&gt;

&lt;p&gt;Imagine que você deseja que uma thread ocorra sem fim, mas rode a cada 2 minutos, como pode fazer isso? 🤔&lt;/p&gt;

&lt;p&gt;Uma das maneiras é usar um &lt;code&gt;Thread.sleep(milis)&lt;/code&gt; e pedir para que a thread pare por algum tempo, note que é importante esse código estar dentro de um try-catch, por sua possibilidade de gerar uma exceção (caso a thread seja interrompida, por exemplo)&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;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&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;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nComeçouuu!: %s\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="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;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&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="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&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;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&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;![[Untitled 1 71.png|Untitled 1 71.png]]&lt;/p&gt;

&lt;h2&gt;
  
  
  Yield
&lt;/h2&gt;

&lt;p&gt;Yield serve para indicarmos / darmos uma &lt;strong&gt;dica&lt;/strong&gt; para o scheduler do JVM faça a thread voltar para Runnable (pare) por um tempo. [[2. Começando com o Código]]&lt;/p&gt;

&lt;p&gt;![[Untitled 2 57.png|Untitled 2 57.png]]&lt;br&gt;
O &lt;em&gt;yield&lt;/em&gt; é um dos principais elementos que permitem a existência de &lt;em&gt;Virtual Threads&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Join
&lt;/h2&gt;

&lt;p&gt;![[Untitled 3 43.png|Untitled 3 43.png]]&lt;br&gt;
Join serve para avisarmos a thread main que ela deve &lt;strong&gt;esperar&lt;/strong&gt; para continuar seu fluxo q uando as operações terminarem&lt;br&gt;
Quando você chama o método &lt;code&gt;join&lt;/code&gt; em uma determinada (thread), você está essencialmente dizendo: "Pera ai, só continua quando essa tarefa terminar". Isso é útil quando você tem partes do programa que precisam estar totalmente prontas antes que outras partes possam prosseguir.&lt;br&gt;
Um exemplo seria um cenário onde você precisa comparar 3 pesquisas de viagem de avião para conseguir ver o preço mais barato, você pode dar o &lt;code&gt;join&lt;/code&gt; nas 3 threads que rodaram essa operação de I/O (a ordem não irá importar, pois estaremos limitados pela última de qualquer jeito) e então depois comparamos os resultados&lt;/p&gt;

&lt;p&gt;Resumidamnete, o &lt;code&gt;join&lt;/code&gt; é especialmente útil quando você precisa garantir a ordem correta das operações ou quando precisa coletar resultados de várias threads antes de prosseguir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// t1 roda antes de t1 e t2&lt;/span&gt;
&lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t1&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;Thread&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;ThreadRunnableYieldJoin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t2&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;Thread&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;ThreadRunnableYieldJoin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'B'&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t3&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;Thread&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;ThreadRunnableYieldJoin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'C'&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&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;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&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;threads&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;t2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Thread:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;start&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;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="c1"&gt;// t1 e t2 em paralelo&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t1&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;Thread&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;ThreadRunnableYieldJoin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t2&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;Thread&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;ThreadRunnableYieldJoin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'B'&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t3&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;Thread&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;ThreadRunnableYieldJoin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'C'&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&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;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&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;h1&gt;
  
  
  Referências
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;[!info] Qual a finalidade do Transient e Volatile no Java?&lt;br&gt;
As vezes quando vou declarar meus atributos noto o transient e o volatile.&lt;br&gt;
&lt;a href="https://pt.stackoverflow.com/a/116080"&gt;https://pt.stackoverflow.com/a/116080&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[!info] Maratona Java Virado no Jiraya&lt;br&gt;
Melhor, maior, e o mais completo curso de Java em português grátis de toda Internet está de volta.&lt;br&gt;
&lt;a href="https://www.youtube.com/playlist?list=PL62G310vn6nFIsOCC0H-C2infYgwm8SWW"&gt;https://www.youtube.com/playlist?list=PL62G310vn6nFIsOCC0H-C2infYgwm8SWW&lt;/a&gt;&amp;gt;)&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>java</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>O que são microserviços? Para que servem e quando usar?</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Wed, 08 May 2024 01:13:21 +0000</pubDate>
      <link>https://dev.to/kauegatto/o-que-sao-microservicos-para-que-servem-e-quando-usar-mb3</link>
      <guid>https://dev.to/kauegatto/o-que-sao-microservicos-para-que-servem-e-quando-usar-mb3</guid>
      <description>&lt;h2&gt;
  
  
  Disclaimer:
&lt;/h2&gt;

&lt;p&gt;Esse artigo é baseado totalmente no Livro &lt;em&gt;Building Microservices&lt;/em&gt;, do Sam Newman!&lt;/p&gt;

&lt;h2&gt;
  
  
  Visão Geral
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Microserviços são partes independentes entre si que são modeladas em torno de uma regra de negócio.&lt;/strong&gt; Um serviço encapsula uma funcionalidade e permite que ela seja acessível por uma rede através de requisições REST.&lt;/p&gt;

&lt;p&gt;Microserviços são um tipo de arquiteturas orientadas a serviço, onde fronteiras entre serviços devem ser traçadas, mas apesar disso o release independente é chave.&lt;/p&gt;

&lt;p&gt;Do lado de fora, um microserviço é uma caixa preta, exceto por seus endpoints expostos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[❗] Importante&lt;/strong&gt;&lt;br&gt;
Como o ideal é que a implementação interna do microserviço seja alheia ao mundo exterior, cada microserviço idealmente deve se importar apenas com sua linguagem de programação, com seu banco de dados e outros detalhes internos de implementação. Não necessariamente isso será a verdade em um mundo real, nesses casos, precisamos nos preocupar principalmente com acessos concorrentes. Locks distribuídos podem ser uma tacada boa para lidar com recursos compartilhados entre múltiplos serviços &lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;h2&gt;
  
  
  Como microserviços se baseiam muito na ocultação de informação, expondo somente o necessário através de interfaces externas, permitem uma maior visão no que pode ou não mudar facilmente. O código interno de um microserviço pode mudar a vontade desde que as interfaces externas não mudem seu comportamento.
&lt;/h2&gt;

&lt;h1&gt;
  
  
  Pontos-Chave sobre microserviços!
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Deploy Independente
&lt;/h2&gt;

&lt;p&gt;Essa é a ideia que conseguimos mudar um microserviço e dar deploy nele sem termos que fazer deploy em qualquer outro microserviço, na realidade, é o jeito que devemos tratar os microserviços, não somente o que podemos fazer.&lt;/p&gt;

&lt;p&gt;Para isso acontecer, devemos ter certeza que nossos microserviços estão pouco acoplados . Isso significa que o contrato entre os serviços devem ser explícitos e estáveis. Algumas escolhas de implementação podem tornar isso inviável, como por exemplo o compartilhamento de banco de dados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modelados ao redor de um domínio do negócio
&lt;/h2&gt;

&lt;p&gt;Microserviços são modelados ao redor de seu domínio, para resolver um problema em específico. Isso ajuda bastante na separação e no entendimento do domínio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Donos de seu próprio estado
&lt;/h2&gt;

&lt;p&gt;Microserviços devem ter dentro de si todos os seus dados importantes, por isso o tópico anterior é importante na hora de delimitar as funções de um microserviço. Um microserviço deve ser capaz de conversar com outro para pedir a ele alguma informação que não possui, isso deve acontecer via a interface externa desse outro microserviço, o que garante o deploy independente desses serviços&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexibilidade
&lt;/h2&gt;

&lt;p&gt;Microserviços te compram opções, no sentido que elas tem um preço. Mais microserviços, na via de regra, te oferecem mais flexibilidade, contudo, também são mais difíceis de manusear. O tamanho dos microserviços não é algo tão importante quanto a pergunta de quantos microserviços você consegue administrar e de que forma você faz isso sem que eles sejam uma bagunça acoplada.&lt;/p&gt;




&lt;h3&gt;
  
  
  Maneira de trabalho com microserviços
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ycgj3wpdmwcgmr7ytvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ycgj3wpdmwcgmr7ytvm.png" alt="Maneira tradicional. Quando não temos um microserviço, uma mudança no back ou no front de uma aplicação monolítica afeta tudo!" width="600" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fulq7ql93xse070dlldal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fulq7ql93xse070dlldal.png" alt="Maneira boa!" width="600" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tecnologias são importantes, mas cuidado
&lt;/h2&gt;

&lt;p&gt;Normalmente é mais produtivo ir incluindo novas tecnologias que dão suporte à microserviços conforme seu sistema cresça e mais serviços apareçam, contudo, algumas ferramentas são essenciais, como por exemplo um agregador de log, ou outras ferramentas que são capazes de visualizar traces entre multiplo serviços, detectar gargalos, etc.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Containers e Kubernetes
&lt;/h2&gt;

&lt;p&gt;Idealmente, cada microserviço deve ser rodado isoladamente, garantindo que um problema em um microserviço não possa afetar outro, por isso, containers são a maneira mais viável de se utilizar os microserviços.&lt;/p&gt;

&lt;p&gt;Depois de implementar os microserviços. provavelmente será dificícil de administrá-los, por isso, é ideal a utilização de ferramentas que servem para a orquestração desses containers, kubernetes é a ferramenta mais conhecida para tal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming
&lt;/h2&gt;

&lt;p&gt;Embora microserviços sejam uma maneira de migrar de bases de dados monolíticas, ainda precisamos encontrar maneiras de transferir informações entre microserviços, ao mesmo tempo que organizações buscam cada vez mais feedbacks em tempo real. Existem muitas ferramentas que ajudam em tal cenário, o apache kafka e rabbitMQ são ferramentas comuns para isso.&lt;/p&gt;

&lt;h1&gt;
  
  
  Vantagens de microserviços
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Tecnologias Heterogêneas
&lt;/h2&gt;

&lt;p&gt;Com um sistema composto por diversas partes que conseguem trabalhar isoladamente e apenas externalizar uma interface, conseguimos programar essas partes com tecnologias totalmente diferentes, desde que o contrato entre os serviços sejam mantidos. Isso nos permite escolher a ferramenta correta para cada serviço.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Robustez
&lt;/h2&gt;

&lt;p&gt;Microserviços são capazes de lidar com falhas em determinados setores específicos sem com que toda a aplicação morra ( o que usualmente acontece em monolitos ). Com os microserviços implementados corretamente, conseguimos lidar com uma falha total em um serviço e apenas fazer com que uma parte do sistema não funcione perfeitamente. Se o sistema de busca da netflix falhar, você ainda é capaz de assistir filmes, criar contas, realizar pagamentos e afins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling
&lt;/h2&gt;

&lt;p&gt;Uma arquitetura baseada em microserviços possibilita o “scaling” de coisas isoladamente, onde podemos dedicar mais hardware a partes que realmente necessitam daquilo, e sistemas mais fracos a grupos de serviços menos utilizados.&lt;/p&gt;

&lt;p&gt;O autor dá um exemplo do marketplace multimilionário focado em modas “Gilt’, e diz que essa foi a principal razão para a Gilt aderir aos microserviços, o mesmo diz que a empresa hoje possui mais de 450 microserviços.&lt;/p&gt;

&lt;h2&gt;
  
  
  Facilidade no Deploy
&lt;/h2&gt;

&lt;p&gt;Uma alteração em uma linha de código em um sistema monolito normalmente pede que o sistema todo passe por um deploy novamente, contudo, graças a característica de deploys independentes, isso não acontece com os microserviços&lt;/p&gt;

&lt;h2&gt;
  
  
  Alinhamento organizacional
&lt;/h2&gt;

&lt;p&gt;Essa questão é óbvia para times grandes de desenvolvimento, separar equipes em partes específicas que trabalham com produtos que podem ser melhorados sem necessitar grande movimentações de outras equipes desde que o contrato pré estabelecido continue sendo respeitado é maravilhoso.&lt;/p&gt;

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

&lt;p&gt;Microserviços podem ser usados em diferentes ambientes e usados em conjuntos para obtermos resultados específicos, ajudam no reúso de código e na eficiência.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Pontos de Dor&lt;/strong&gt; / &lt;em&gt;Fraquezas&lt;/em&gt;
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;[📋 Citação]&lt;br&gt;
&lt;em&gt;We’ll be covering many of these issues in depth throughout the rest of the book—in fact, I’d argue that the bulk of this book is about dealing with the pain, suffering, and horror of owning a microservice architecture.”&lt;/em&gt; - Autor do Livro Building Microservices, usado como base.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Experiência do Desenvolvedor.
&lt;/h2&gt;

&lt;p&gt;Quando você vai incluindo mais serviços, cria-se uma situação mais complexa para rodar os serviços em máquinas locais, 5/6/7 serviços baseados em JVM podem rodar, mas quando chegamos nas dezenas, a situação é mais trabalhosa, inclusive com runtimes que são menos taxativos que a JVM.&lt;/p&gt;

&lt;p&gt;Outro ponto importante é que mudanças em charts, terraform, vulnerabilidades que devem ser aplicadas em múltiplos serviços podem ser uma dor de se administrar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sobrecarga de tecnologias
&lt;/h2&gt;

&lt;p&gt;Não é porque microserviços te dão a opção de rodar diferentes tecnologias, bancos, linguagens que você deve fazê-lo, são possibilidades, não requisitos.&lt;/p&gt;

&lt;p&gt;Além disso, diversas empresas, equipes ou desenvolvedores individuais desenvolvem um amor por novas tecnologias que às vezes não valem a pena, que servirão apenas para incluir mais complexidade em um escopo definido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Report de Dados
&lt;/h2&gt;

&lt;p&gt;Report de dados com microserviços são mais complicados, principalmente pelo fato de termos (idealmente) banco de dados quebrados em diferentes partes, onde uma simples operação de join não resolve as coisas de uma vez.&lt;/p&gt;

&lt;h3&gt;
  
  
  Segurança, Monitoramento, Testes
&lt;/h3&gt;

&lt;p&gt;São basicamente a mesma coisa, temos diversos microserviços conversando entre si, vários fluxos a serem monitorados, os testes e2e ficam muito difíceis. Esses assuntos vao ser tratados com mais detalhes depois.&lt;/p&gt;

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

&lt;p&gt;Respeitar a consistência de dados em um sistema muito mais distribuído, com muitos processos independentes, que muitas vezes cuidam de uma base de dados única é difícil. Transações distribuídas existem mas costumam ser problemáticas, o ideal é utilizarmos tecnologias como sagas.&lt;/p&gt;

&lt;h1&gt;
  
  
  Onde é complicado usar?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Empresas que possuem times excessivamente pequenos&lt;/li&gt;
&lt;li&gt;Empresas que não conseguem arcar com os custos iniciais de colocar diversas máquinas na cloud rodando serviços&lt;/li&gt;
&lt;li&gt;Empresas as quais o produto não está pensado, está muito sucetível a mudanças

&lt;ul&gt;
&lt;li&gt;Vai lascar bastante com os boundaries&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Microservices need to talk to each other through n/w packets. Monolith is mostly IPC and hence faster.&lt;/li&gt;
&lt;li&gt;Monitoring all the Microservices (100s) and checking their health to ensure smooth running is a pain.&lt;/li&gt;
&lt;li&gt;Monolith need not worry about consistency since they primarily operate on the same data store.&lt;/li&gt;
&lt;li&gt;Monolith in general have better latency since the non-determinism of microservices is not present&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Onde eles funcionam bem?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Empresas com diversos desenvolvedores

&lt;ul&gt;
&lt;li&gt;Permite que um dev ou um time não entre no caminho do outro;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Empresas que possuem um aporte inicial bom de dinheiro&lt;/li&gt;
&lt;li&gt;Software que precisa da possibilidade de escalar, e idealmente para diversas regiões do mundo&lt;/li&gt;
&lt;li&gt;Softwares que precisam de flexibilidade.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Virtual Threads em Java - O Java que voa!</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Mon, 01 Apr 2024 20:24:01 +0000</pubDate>
      <link>https://dev.to/kauegatto/virtual-threads-em-java-o-java-que-voa-1j0k</link>
      <guid>https://dev.to/kauegatto/virtual-threads-em-java-o-java-que-voa-1j0k</guid>
      <description>&lt;p&gt;Opa, só passando para avisar que esse post veio originalmente do meu blog, se puderem dar uma força lá, vai ser muito bom :)&lt;br&gt;
&lt;a href="https://www.kaue.cat/posts/virtual-threads/"&gt;https://www.kaue.cat/posts/virtual-threads/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outro aviso é que o post está em progresso, acho que está bom o suficiente para ser lançado, mas vocês provavelmente vão encontrar alguns problemas, mas um conteúdo bem rico!&lt;/p&gt;
&lt;h1&gt;
  
  
  O Artigo
&lt;/h1&gt;

&lt;p&gt;Primeiro, vamos estabelecer objetivos desse artigo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ Objetivos &lt;/p&gt;

&lt;p&gt;Dar uma breve Introdução à Programação Concorrente e Paralela&lt;br&gt;
Explicar o histórico da programação concorrente no JAVA&lt;br&gt;
Mostrar brevemente como o problema de throughput era resolvido no JAVA&lt;br&gt;
Explicar Virtual Threads&lt;br&gt;
Mostrar exemplos práticos do uso de Virtual Threads&lt;br&gt;
Mostrar concorrência estruturada&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❌ Não Objetivos&lt;/p&gt;

&lt;p&gt;Não é objetivo explicar em detalhes mecanismos de programação concorrente &amp;amp; paralela, para isso, recomendo fortemente &lt;a href="https://fidelissauro.dev/concorrencia-paralelismo/"&gt;esse artigo&lt;/a&gt; do Matheus Fidelis&lt;br&gt;
Não é objetivo explicar em detalhes como a programação reativa e multithreaded é feita em JAVA  (sem ser com Virtual Threads)&lt;br&gt;
Entrar em detalhe sobre assuntos específicos do pacote &lt;code&gt;java.util.concurrent&lt;/code&gt; - &lt;code&gt;Futures&lt;/code&gt;, &lt;code&gt;Executors&lt;/code&gt;, &lt;code&gt;Synchronizers&lt;/code&gt;,  Coleções &lt;em&gt;Thread-Safe&lt;/em&gt;, etc. Para isso, recomendo o&lt;a href="https://www.youtube.com/watch?v=VKjFuX91G5Q&amp;amp;list=PL62G310vn6nFIsOCC0H-C2infYgwm8SWW"&gt;curso gratuito de Java&lt;/a&gt; do DevDojo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Virtual Threads
&lt;/h1&gt;

&lt;p&gt;Virtual Threads é uma feature que está disponível para uso em um LTS desde o Java 21, também chamado de project loom, é o projeto de integrar maneiras mais fáceis de escrever programas concorrentes e reativos em JAVA,  a fim de misturar performance e usabilidade&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔑 &lt;strong&gt;&lt;a href="https://cr.openjdk.org/~rpressler/loom/loom/sol1_part1.html"&gt;Pontos Chave&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A virtual thread is a &lt;code&gt;Thread&lt;/code&gt; — in code, at runtime, in the debugger and in the profiler.&lt;/li&gt;
&lt;li&gt;A virtual thread is not a wrapper around an OS thread, but a Java entity.&lt;/li&gt;
&lt;li&gt;Creating a virtual thread is cheap — have millions, and don’t pool them!&lt;/li&gt;
&lt;li&gt;Blocking a virtual thread is cheap — be synchronous!&lt;/li&gt;
&lt;li&gt;No language changes are needed.&lt;/li&gt;
&lt;li&gt;Pluggable schedulers offer the flexibility of asynchronous programming.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;&lt;a href="https://openjdk.org/jeps/444"&gt;Objetivos&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable server applications written in the simple thread-per-request style to scale with near-optimal hardware utilization.&lt;/li&gt;
&lt;li&gt;Enable existing code that uses the java.lang.Thread API to adopt virtual threads with minimal change.&lt;/li&gt;
&lt;li&gt;Enable easy troubleshooting, debugging, and profiling of virtual threads with existing JDK tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;p&gt;❌ &lt;strong&gt;&lt;a href="https://openjdk.org/jeps/444"&gt;Não Objetivos&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is not a goal to remove the traditional implementation of threads, or to silently migrate existing applications to use virtual threads.&lt;/li&gt;
&lt;li&gt;It is not a goal to change the basic concurrency model of Java.&lt;/li&gt;
&lt;li&gt;It is not a goal to offer a new data parallelism construct in either the Java language or the Java libraries. The &lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/package-summary.html"&gt;Stream API&lt;/a&gt; remains the preferred way to process large data sets in parallel.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Conceitos
&lt;/h1&gt;

&lt;p&gt;De maneira geral, usamos as virtual threads por um motivo: Aumentar o throughput (vazão) da nossa aplicação (não velocidade, que está relacionado à latência. Por enquanto, a maneira mais comum é uma: &lt;a href="https://en.wikipedia.org/wiki/Reactive_programming"&gt;Programação Reativa&lt;/a&gt;, vamos entender como a programação reativa  era no passado, e como vamos implementá-la com as virtual threads.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Throughput?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Throughput diz  respeito à quantidade de elementos que você processa por uma medida de tempo (exemplo: Requests/Segundo em uma aplicação HTTP, Mensagens Processadas por Segundo em um message broker).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Programação Assíncrona e Concorrente
&lt;/h2&gt;

&lt;p&gt;A maior parte do código que escrevemos é síncrono, isso significa que o código vai ser executado imediatamente quando chegar naquela instrução, o código assíncrono é um código que vai ser executado, em algum momento no futuro, como uma promessa de execução.&lt;br&gt;
Códigos assíncronos não significam a mesma coisa que concorrentes, um forEach assínrono, por exemplo, roda na thread principal de um programa, um código concorrente significa que ele vai ser executado em outra thread!&lt;/p&gt;

&lt;p&gt;Podemos criar tarefas (&lt;strong&gt;Tasks&lt;/strong&gt;) para rodarem em Threads, e para criarmos uma Thread, temos duas maneiras:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Criar uma Thread a partir de seu construtor, e passar à ela sua Task&lt;/li&gt;
&lt;li&gt;Usar uma pool (piscina) de Threads e deixar com que o executor entregue a tarefa à uma thread disponível (se ela existir)

&lt;ol&gt;
&lt;li&gt;Essa Abordagem é muito comum pois Threads são recursos limitados que não são leves de criar e destruir&lt;/li&gt;
&lt;li&gt;Conexões de Banco de dados também passam ficam em um "Pool" quando usamos frameworks como o Spring, a biblioteca que cuida da criação de um Pool de Conexões é o &lt;a href="https://github.com/brettwooldridge/HikariCP"&gt;Hikari&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Nesse cenário, vamos criar uma task, submetê-la ao Executor, e receberemos uma promessa de execução, por esse ponto de vista, essa tarefa é assíncrona pois será executada no futuro, mas também é concorrente, pois será executada em uma thread diferente. Aqui os conceitos se encontram, &lt;a href="https://sci-hub.se/10.1145/2846680.2846687"&gt;mas não são a mesma coisa código concorrente é assíncrono, mas nem todo código assíncrono é concorrente!&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Execução Bloqueante
&lt;/h2&gt;

&lt;p&gt;Uma execução bloqueante significa que uma instrução está sendo executada pela sua CPU (ou  por um core dela) e que &lt;strong&gt;nenhuma outra instrução irá ocorrer enquanto a anterior ainda estiver acontecendo, mesmo que sua CPU não esteja sendo utilizada&lt;/strong&gt;, normalmente em uma espera de I/O ou para entrar em um bloco de código sincronizado.&lt;br&gt;
Nesse cenário irá ocorrer uma troca de contexto, um processo relativamente "caro" para sua CPU que basicamente desaloca o processo até que ele exija algo novamente da CPU, por sua vez, o código não bloqueante garante que sua CPU evite trocas de contextos e esteja sempre sendo utilizada.&lt;/p&gt;
&lt;h1&gt;
  
  
  O Cenário Atual - Por quê usar Virtual Threads?
&lt;/h1&gt;

&lt;p&gt;Primeiro, analise o código JAVA que faz uma chamada HTTP padrão para um servidor:&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="no"&gt;URI&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://mydata.com/data"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;HttpClient&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;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;HttpRequest&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;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="na"&gt;build&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;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;send&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;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Aqui, podemos ver que nossa CPU só é realmente utilizada de maneira eficiente durante  200 nano segundos, e fica ociosa a maior parte do tempo, esperando a resposta da chamada.&lt;/p&gt;

&lt;p&gt;Como podemos arrumar isso?&lt;/p&gt;

&lt;h2&gt;
  
  
  0. O Patinho lento - One Request Per Thread
&lt;/h2&gt;

&lt;p&gt;A primeira ideia é irmos no aspecto concorrente, quando sua thread estiver esperando, o Task Scheduler vai remover ela do núcleo que está rodando (Context Switching) e coloca outra thread no lugar, executar uma request em cada thread (One-Request-Per-Thread) é a maneira convencional, que vêm sido utilizada há bons anos.&lt;/p&gt;

&lt;p&gt;Nesse cenário, precisaríamos de 500 mil de threads - advindo da proporção entre tempo ocioso e trabalhado. 100ms/200ns - (requests) nesse núcleo para alcançarmos o uso de 100% de CPU, garantindo que sua CPU não fique ociosa. Isso definitivamente não boa bom, né?&lt;br&gt;
As threads no JAVA encapsula uma thread do Sistema Operacional, também chamada de Platform Thread ou Kernel Thread, o problema é que o custo de criação de criação de uma Thread em JAVA, é o mesmo de criar uma Thread no SO, que é relativamente caro&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlf4nnyggvqgc1pe8lak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlf4nnyggvqgc1pe8lak.png" alt="Image description" width="518" height="379"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://app.pluralsight.com/library/courses/java-concurrent-programming-virtual-threads/table-of-contents"&gt;Fonte&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recursos caros como threads são colocados em "Pools" para lidar com eles de maneiras mais eficientes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❝ ❞ &lt;/p&gt;

&lt;p&gt;Developers sometimes use thread pools to limit concurrent access to limited resources. For example, if a service cannot handle more than 20 concurrent requests then making all requests to the service via tasks submitted to a thread pool of size 20 will ensure that. This idiom has become ubiquitous because the high cost of platform threads has made thread pools ubiquitous&lt;br&gt;
Fonte: &lt;a href="https://openjdk.org/jeps/444"&gt;https://openjdk.org/jeps/444&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Perfeito, mas voltando ao exemplo anterior, precisamos de 500.000 threads, quanto isso vai nos custar?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Memória: 500.000Mb
Tempo de início: 500 Segundos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, entendemos que o modelo One Request Per Thread não é mais viável:&lt;br&gt;
O artigo &lt;a href="https://repositorio-aberto.up.pt/bitstream/10216/98156/2/31853.pdf"&gt;Transformation patterns for a reactive application, de Bruno Miguel Mendonça Maia&lt;/a&gt; pontua como característica desses sistemas :&lt;/p&gt;
&lt;h3&gt;
  
  
  Pontos Negativos
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;( – ) Concurrency&lt;/strong&gt;. Synchronous programming is not the best suited model for dealing with concurrency as the execution will start and block the current thread while waiting for the result.&lt;br&gt;
&lt;strong&gt;( – ) Throughput&lt;/strong&gt;. While a thread waits for the expensive execution to return its result, the OS can exchange active threads to promote concurrency, &lt;strong&gt;but this has overhead costs and hinders throughput due to thread context switching and cache invalidation.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;( – ) Latency&lt;/strong&gt;. Thread blocking on execution and the lower throughput due to the OS exchanging active threads and consequently cache invalidation leads to poorer latency.&lt;/p&gt;
&lt;h3&gt;
  
  
  Pontos Positivos
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(+) Ease of use&lt;/strong&gt;. The synchronous sequential model and its typical imperative programming style provides a familiar thinking model that results in ease of use.&lt;br&gt;
&lt;strong&gt;(+) Maintainability&lt;/strong&gt;. Synchronous programming and its sequential execution model provides an easy to reason with concept that in turn increase maintainability. Furthermore, error handling in sequential execution is easier to tackle.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. O patinho feio - Processar múltiplos requests em uma Thread
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Essa abordagem é a abordagem Reativa&lt;/strong&gt;. A abordagem reativa tem um princípio simples de dividir uma request em pequenas porções e nenhuma porção pode conter código bloqueantes:&lt;/p&gt;

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

&lt;p&gt;Aqui dividimos as etapas como foi acordado anteriormente (exceto pelo fato de que a step2 pode bloquear a CPU)&lt;br&gt;
Com isso, precisamos usar um framework reativo que permita que usemos essas lambdas (aqui o exemplo é completableFuture, que faz a mesma coisa, mas usando a pool de threads, mas serve bem para explicar.):&lt;/p&gt;

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

&lt;p&gt;Seu framework de execução terá a responsabilidade de conectar as lambdas para que o resultado delas seja passado para a próxima função corretamente, é seu trabalho não escrever código bloqueante nesse caso. &lt;strong&gt;Como seu framework vai ter pouquíssimas threads (talvez só uma por núcleo), e muitas requests vão ser processadas em uma mesma thread, escrever código bloqueante vai impactar MUITO sua performance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nesse caso em específico, a thread não será bloqueada pois CompletableFuture conhece o HttpRequest.send() e registra um callback, que será executado quando a função terminar de rodar.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pontos Negativos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Código difícil de ler&lt;/li&gt;
&lt;li&gt;Código difícil de dar manutenção&lt;/li&gt;
&lt;li&gt;É fácil de arruinar a performance com um pedaço de código bloqueante.&lt;/li&gt;
&lt;li&gt;Difícil de testar&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  2. O Patinho que Existe - Futures e Callback Hell
&lt;/h2&gt;

&lt;p&gt;Aqui, usamos ainda do One Request Per Thread, mas com estratégias um pouco diferentes, usamos &lt;code&gt;Futures&lt;/code&gt; para escrever código paralelizável e concorrente, ganhando performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u2kplp87s53uxo6t209.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u2kplp87s53uxo6t209.png" alt="Image description" width="800" height="286"&gt;&lt;/a&gt;&lt;br&gt;
Fonte &lt;a href="https://blog.soaresdev.com/funcoes-callback-em-javascript/"&gt;https://blog.soaresdev.com/funcoes-callback-em-javascript/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O post &lt;a href="https://blogs.oracle.com/javamagazine/post/virtual-threads-futures"&gt;Virtual threads: Are futures a thing of the past?&lt;/a&gt;, na Java Magazine, retrata a história do código concorrente em Java. Lá, é retratado o uso de Futures para colocar suas Threads para  rodar porções bloqueantes em paralelo:&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Socket&lt;/span&gt; &lt;span class="n"&gt;socket&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;request&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;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&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;futureWeather&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Weather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec2&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;futureRestaurants&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Restaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec2&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;futureTheaters&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Theaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec2&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;Page&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="na"&gt;setWeather&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureWeather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRestaurants&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureRestaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTheaters&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureTheaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&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;A ordem em que as três tasks esperam pelo resultado não importa, a thread coloca os 3 Jobs para rodar, e depois bloqueia (espera) até que elas tenham terminado. Mas pera, "e depois bloqueia (espera) até que elas tenham terminado"... Exato, ainda podemos melhorar isso bastante, bloquear Threads tem um custo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://blogs.oracle.com/javamagazine/post/virtual-threads-futures"&gt;Esse blocking traz a possibilidade de deadlocks acontecerem&lt;/a&gt;. Aqui, teremos uma pool para computar recursos e para lidar com requests.&lt;/li&gt;
&lt;li&gt;Bloquear e desbloquear threads traz perda de performance. Claramente sua CPU não vai ficar  2 Segundos esperando a sua resposta de I/O e vai colocar outra thread para trabalhar nesse meio termo, apesar disso, existe um custo não só para fazer a troca de contexto, mas isso também irá causar perda de dados em cache no processador, resultando em &lt;em&gt;cache misses&lt;/em&gt; quando a thread estiver de volta.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Podemos "resolver" isso usando callbacks!&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;Server&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;ServerSocket&lt;/span&gt; &lt;span class="n"&gt;server&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;ServerSocket&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&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;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isClosed&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;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&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;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Socket&lt;/span&gt; &lt;span class="n"&gt;socket&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;request&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;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&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;futureWeather&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Weather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec&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;futureRestaurants&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Restaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec&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;futureTheaters&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Theaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec&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;page&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;Page&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;futureWeather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAccept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;futureRestaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAccept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;restaurants&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;futureTheaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAccept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theaters&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setWeather&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRestaurants&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;restaurants&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTheaters&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theaters&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&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;Future.thenAccept recebe como argumento um consumer, que irá consumir o resultado dessa future, a invocação de thenAccept só registra o código para uma execução futura, ele não espera o código ser completado, registrando um callback.&lt;br&gt;
Nesse cenário, as threads nunca são bloqueadas e uma única pool não muito vasta pode ser  usada. O código também está livre de deadlocks.&lt;/p&gt;

&lt;p&gt;Callbacks são difíceis de escrever e de debugar, você pode ter percebido que nesse simples evento, já temos 3 níveis de aninhamento de código, podemos melhorar isso usando outras features para lidar com futures de maneira não bloqueantes,  como usando &lt;code&gt;thenCombine&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Socket&lt;/span&gt; &lt;span class="n"&gt;socket&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;request&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;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&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;futureWeather&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Weather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec&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;futureRestaurants&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Restaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec&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;futureTheaters&lt;/span&gt; &lt;span class="o"&gt;=&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="nc"&gt;Theaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;exec&lt;/span&gt;&lt;span class="o"&gt;);&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Page&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="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureWeather&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setWeather&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureRestaurants&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setRestaurants&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureTheaters&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setTheaters&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAccept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;send&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;Nesse cenário, o único processamento que a thread que lida com as conexões performa é a criação da página base, mas isso também poderia ser assíncrono:&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;Server&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;ServerSocket&lt;/span&gt; &lt;span class="n"&gt;server&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;ServerSocket&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&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;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isClosed&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;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Socket&lt;/span&gt; &lt;span class="n"&gt;socket&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;futureRequest&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;exec&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;futureWeather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Weather:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exec&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;futureRestaurants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Restaurants:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exec&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;futureTheaters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Theaters:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;futureRequest&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureWeather&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setWeather&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureRestaurants&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setRestaurants&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureTheaters&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setTheaters&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAccept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;send&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;
  
  
  3. O Patinho bonito - Construir uma thread virtual, mais leve que Platform Threads.
&lt;/h3&gt;

&lt;p&gt;As virtual threads são exatamente isso, conseguimos performance, simplicidade e boa capacidade de manutenção evitando códigos reativos e sem ter medo de códigos bloqueantes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❝ ❞ Implicações&lt;/p&gt;

&lt;p&gt;Virtual threads are cheap and plentiful, and thus &lt;strong&gt;should never be pooled&lt;/strong&gt;: A new virtual thread should be created for every application task. &lt;strong&gt;Most virtual threads will thus be short-lived and have shallow call stacks, performing as little as a single HTTP client call or a single JDBC query.&lt;/strong&gt; Platform threads, by contrast, are heavyweight and expensive, and thus often must be pooled. They tend to be long-lived, have deep call stacks, and be shared among many tasks.&lt;br&gt;
&lt;strong&gt;In summary, virtual threads preserve the reliable thread-per-request style that is harmonious with the design of the Java Platform while utilizing the available hardware optimally.&lt;/strong&gt; Using virtual threads does not require learning new concepts, though it may require unlearning habits developed to cope with today's high cost of threads.&lt;br&gt;
Virtual threads will not only help application developers — they will also help framework designers provide easy-to-use APIs that are compatible with the platform's design without compromising on scalability.&lt;/p&gt;

&lt;p&gt;❗ Reforçando!&lt;/p&gt;

&lt;p&gt;Não crie  pools de threads virtuais!&lt;/p&gt;
&lt;h1&gt;
  
  
  Escrevendo Virtual Threads
&lt;/h1&gt;

&lt;p&gt;As maneiras que podemos criar virtual são simples:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Via factory
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofVirtual&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread virtual!"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Thread.startVirtualThread(task)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
&lt;span class="n"&gt;t4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Usando um executorService (com o método &lt;code&gt;newVirtualThreadPerTaskExecutor&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;execute&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;set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConcurrentHashMap&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;newKeySet&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  

    &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;set&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="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;  

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;N_TASKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  

    &lt;span class="k"&gt;try&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;executorService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;N_TASKS&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
            &lt;span class="n"&gt;executorService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
        &lt;span class="o"&gt;}&lt;/span&gt;  
    &lt;span class="o"&gt;}&lt;/span&gt;  

    &lt;span class="nc"&gt;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;"# threads used = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Como Virtual Threads funcionam
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Uma virtual thread é executada em cima de uma platform thread, que chamamos de Carrier Thread.&lt;/strong&gt; Essas carrier threads são organizadas em uma única &lt;code&gt;ForkJoinPool&lt;/code&gt;, onde cada Platform (também carrier) terá uma waitlist de virtual threads associadas à ela.&lt;/p&gt;

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

&lt;p&gt;Para evitar &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Starvation_(computer_science)"&gt;Starvation&lt;/a&gt;&lt;/strong&gt; das threads do Sistema Operacional, se uma waitlist de uma Platform Thread zerar, ela vai "roubar" tarefas de outras threads.&lt;br&gt;
Com isso, percebemos que executar um "runnable" em uma virtual thread, na realidade roda ele em uma thread real, portanto, se formos executar uma operação completamente não bloqueante, virtual threads são mais caras, é um overhead, se for o caso, rode-as diretamente na thread comum. &lt;strong&gt;Virtual Threads são feitas para executar códigos bloqueantes!&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Aviso&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Virtual Threads não são feitas para rodar operações em memória!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Quando operações bloqueantes rodam em virtual threads, elas se separam de sua Carrier Thread&lt;/strong&gt;, usando "yield" para basicamente suspender a execução desse código, &lt;strong&gt;liberando a thread principal para trabalhar com outras coisas&lt;/strong&gt;, então essa virtual thread é guardada na memória principal (heap) e quando estiver pronta, é colocada de novo na waitlist das threads principais, através de um callback, mas isso tudo é feito de maneira transparente!&lt;/p&gt;

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

&lt;p&gt;Note que &lt;code&gt;Continuation.yield()&lt;/code&gt; responsável por garantir esse processo para que a thread principal não seja bloqueada, precisa ser implementado em operações bloqueantes (isso já está feito).&lt;/p&gt;

&lt;p&gt;Por exemplo, nessa linha de código:&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;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;future1&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;future2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essas operações vão fazer com que a thread virutal monte e desmonte de sua &lt;em&gt;carrier thread&lt;/em&gt; diversas vezes, provavelmente uma para cada call para &lt;code&gt;get()&lt;/code&gt;e possívelmente muitas outras vezes ao longo da execução de .send() graças às operações de I/O.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplos
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Exemplo usando um executor que cria uma virtual thread para cada task bloqueante.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&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;Response&lt;/span&gt; &lt;span class="n"&gt;response&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;url1&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;url2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;try&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;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&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;future1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&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;fetchURL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url1&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;future2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&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;fetchURL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url2&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;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;future1&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;future2&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="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExecutionException&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&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;fail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;fetchURL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URL&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&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;in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;openStream&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;String&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readAllBytes&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTF_8&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;ol&gt;
&lt;li&gt;Mesmo procedimento usado no capítulo [[#2. O Patinho que Existe - Futures e Callback Hell]], mas usando virtual threads, que não bloqueiam sua CPU!
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Socket&lt;/span&gt; &lt;span class="n"&gt;socket&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;request&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;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&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;futureWeather&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;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Weather&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;futureRestaurants&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;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Restaurants&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;futureTheaters&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;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Theaters&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;();&lt;/span&gt;

  &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&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;futureWeather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Weather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&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;futureRestaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Restaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&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;futureTheaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Theaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Page&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="na"&gt;setWeather&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureWeather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRestaurants&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureRestaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTheaters&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureTheaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&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;ol&gt;
&lt;li&gt;Parecido com o exemplo 2, mas com um aroma mais funcional (Considerando que o executorService provê virtual threads.)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Socket&lt;/span&gt; &lt;span class="n"&gt;socket&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;futureRequest&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;exec&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;futureWeather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Weather:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exec&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;futureRestaurants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Restaurants:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exec&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;futureTheaters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;futureRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Theaters:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;futureRequest&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApplyAsync&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureWeather&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setWeather&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureRestaurants&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setRestaurants&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenCombine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futureTheaters&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;setTheaters&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAccept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Page:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;send&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;ol&gt;
&lt;li&gt;Uma maneira imperativa, sem o uso de futures
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Socket&lt;/span&gt; &lt;span class="n"&gt;socket&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;request&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;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&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;page&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;Page&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;Thread&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&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;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setWeather&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Weather&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;Thread&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&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;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRestaurants&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Restaurants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;Thread&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&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;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setTheaters&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Theaters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&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;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&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;Um ponto negativo aqui é que a Pagina  deve ser thread safe e deve ser construída antes do uso dos fetches pois todos esses métodos podem alterar e acessar esse recurso ao mesmo tempo.&lt;br&gt;
Nesse caso, algum tipo de sincronização ou lock terá de ocorrer (&lt;em&gt;pinning&lt;/em&gt; nesse caso não soa tão ruim pelo contexto que a criação/set de um objeto Page é rápido)&lt;/p&gt;

&lt;p&gt;Mais uma imagem de exemplo:&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;⚠️ Aviso&lt;/p&gt;

&lt;p&gt;Como movemos coisas para a memória e trazemos-as de volta, teremos problemas se estivermos usando ponteiros diretamente, mas você provavelmente não vai fazer isso em JAVA.&lt;br&gt;
Apesar disso, o bloco "synchronized", faz isso, e quando isso acontece, a task executa de maneira bloqueante na platform thread, sem ir para a heap memory como as virtual threads fazem, ou seja, o &lt;code&gt;yield&lt;/code&gt; não acontece.&lt;br&gt;
Chamamos isso de &lt;strong&gt;pinning&lt;/strong&gt;, se você precisar usar "synchronized" em um bloco que leva uma quantidade considerável de tempo (milisegundos), refatore-o para usar &lt;strong&gt;ReentrantLock&lt;/strong&gt;, senão você vai bloquear sua pequena quantidade de platform threads por bastante tempo :(&lt;/p&gt;

&lt;p&gt;Adicionalmente, você pode observar com facilidade os &lt;em&gt;pinnings&lt;/em&gt; de platform threads: New diagnostics assist in migrating code to virtual threads and in assessing whether you should replace a particular use of &lt;code&gt;synchronized&lt;/code&gt; with a &lt;code&gt;java.util.concurrent&lt;/code&gt; lock:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A JDK Flight Recorder (JFR) event is emitted when a thread blocks while pinned (see &lt;a href="https://openjdk.org/jeps/444#JDK-Flight-Recorder-JFR"&gt;JDK Flight Recorder&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Habilitando no Spring
&lt;/h2&gt;

&lt;p&gt;Para habilitar virtual threads no SPRING, use:&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;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;threads&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;virtual&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="c1"&gt;## ou&lt;/span&gt;
&lt;span class="s"&gt;spring.threads.virtual.enabled=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa alteração já fará com que seu servidor deixe de trabalhar com o antigo cenário de uma thread por request, possívelmente melhorando sua performance, mesmo sem muitas alterações (No caso, isso provavelmente só ocorrerá se você já estiver recebendo uma quantidade de chamadas o suficiente para esgotar sua pool de platform threads, que é 200).&lt;/p&gt;

&lt;h1&gt;
  
  
  Concorrência Estruturada  -  Feature Preview
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/453"&gt;A feature de Concorrência Estruturada&lt;/a&gt;, tem como foco a escrita simples de códigos&lt;br&gt;
concorentes, usando o paradigma imperativo.&lt;/p&gt;

&lt;p&gt;Em um passado distante, os códigos que eram escritos eram recheados de "go-tos", o que dificultava muito o custo de manutenção pela dificuldade de entender o fluxo de execução do  programa, estar dentro de um else não significava necessariamente, que seu &lt;em&gt;if&lt;/em&gt; falhou.&lt;/p&gt;

&lt;p&gt;O problema disso é que código concorrente, em sua forma atual é como usar um go-to, você não consegue saber quem invocou a instrução que está rodando na thread.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ &lt;a href="https://bugs.openjdk.org/browse/JDK-8306641"&gt;Objetivos&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Promover um estilo de programação concorrente que pode evitar riscos comuns associados  ao uso de códigos concorrentes e paralelizado&lt;/li&gt;
&lt;li&gt;Melhorar a observabilidade desse tipo de código&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ Não-Objetivos&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Substituir maneiras de  trabalhar com código concorrente, como :  &lt;code&gt;ExecutorService&lt;/code&gt; e &lt;code&gt;Future&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Definir a API definitiva de Concorrência Estruturada para a plataforma java, permitindo que outras formas surjam em novas  bibliotecas ou releases da JDK&lt;/li&gt;
&lt;li&gt;Definir maneiras de compartilhar &lt;em&gt;streams&lt;/em&gt; de dados entre diferentes threads (exemplo: canais)&lt;/li&gt;
&lt;li&gt;Substituir o mecanismo de interrupção de thread já existente, mas pode ser no futuro.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;⚡☠️ Structured Concurrency é uma Feature Preview no JAVA 21&lt;/p&gt;

&lt;p&gt;Ou seja, essa API pode sofrer alterações ao longo do tempo, e para utilizá-la, precisamos explicitamente liberar seu uso.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Com structured concurrency, criamos um escopo onde tarefas irão rodar de maneira  assíncrona com fork e join, e depois retornamos o resultado dessas operações&lt;/p&gt;

&lt;h1&gt;
  
  
  Papos Técnicos para nerds
&lt;/h1&gt;

&lt;h2&gt;
  
  
  O Fork-Join-Pool das Threads que as Virtuals usam
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Comentamos anteriormente como as Virtual Threads funcionavam em cima de threads reais: O scheduler de virtual threads é um 'work-stealing' &lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/ForkJoinPool.html"&gt;&lt;code&gt;ForkJoinPool&lt;/code&gt;&lt;/a&gt; que opera usando FIFO mode. O &lt;em&gt;paralelismo&lt;/em&gt; padrão do scheduler é a quantidade padrão de &lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Runtime.html#availableProcessors()"&gt;processadores  (ou quantidade de threads dos seus processadores :)&lt;/a&gt; que sua máquina  tem. Dá para alterar isso na prop: &lt;code&gt;jdk.virtualThreadScheduler.parallelism&lt;/code&gt;. Esse &lt;code&gt;ForkJoinPool&lt;/code&gt; especificamente é tunado de uma maneira diferente de um &lt;a href="[common%20pool](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/ForkJoinPool.html#commonPool())"&gt;pool normal&lt;/a&gt;, que opera usando LIFO.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mais
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/444"&gt;JEP 444: Virtual Threads&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cr.openjdk.org/~rpressler/loom/loom/sol1_part1.html"&gt;State of Loom&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://er.ucu.edu.ua/bitstream/handle/1/4470/Petro%20Karabyn.pdf?sequence=1"&gt;Performance and scalability analysis of Java IO and NIO based server models, their implementation and comparison, Karabyn Petro. 2019&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogs.oracle.com/javamagazine/post/virtual-threads-futures"&gt;Virtual threads: Are futures a thing of the past? - Java Magazine&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.rockthejvm.com/ultimate-guide-to-java-virtual-threads"&gt;The Ultimate Guide to Java Virtual Threads - Rock the JVM Blog&lt;/a&gt;/&lt;/p&gt;

&lt;p&gt;&lt;a href="https://davidvlijmincx.com/posts/virtual-threads-with-completablefuture"&gt;CompletableFuture with Virtual threads&lt;/a&gt;/&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/codex/java-virtual-threads-9fad6c362890"&gt;Java Virtual Threads&lt;/a&gt; - Esse não foi usado diretamente no texto, mas foi uma boa fonte de conhecimentos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=YQ6EpIk7KgY"&gt;https://www.youtube.com/watch?v=YQ6EpIk7KgY&lt;/a&gt; - Pelo engenheiro chefe responsável pela concepção da JEP das virtual threads.&lt;/p&gt;

</description>
      <category>java</category>
      <category>braziliandevs</category>
      <category>backend</category>
    </item>
    <item>
      <title>Arquitetura de Software para devs: MVC, Hexagonal, DDD</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Mon, 13 Nov 2023 17:28:49 +0000</pubDate>
      <link>https://dev.to/kauegatto/arquitetura-a-nivel-de-software-para-devs-mvc-hexagonal-ddd-4on3</link>
      <guid>https://dev.to/kauegatto/arquitetura-a-nivel-de-software-para-devs-mvc-hexagonal-ddd-4on3</guid>
      <description>&lt;h1&gt;
  
  
  Arquitetura à nível de Software:
&lt;/h1&gt;

&lt;p&gt;Refere-se à organização e definição de regras a serem seguidas no seu projeto em si, seja ele um microserviço, monolito ou qualquer outra parte de uma solução maior, nossa ênfase está no nível do seu serviço, um serviço seu pode seguir à risca SOLID, arquitetura hexagonal e uma PoC pode seguir o famoso: faz rápido e funcionando.&lt;/p&gt;

&lt;p&gt;De outro lado, cuidando e decidindo se temos SOA, Microserviços, Monolitos ou qual protocolo de comunicação usamos, temos a arquitetura de soluções, o que não é o foco do artigo&lt;/p&gt;

&lt;h2&gt;
  
  
  Modelo Baseado em Camadas
&lt;/h2&gt;

&lt;p&gt;É bem comum dividirmos nosso software em camadas, é o que fazemos na maior parte das arquiteturas de software modernas, essa divisão tem como objetivo separar partes do código que não devem interagir muito entre si exceto por alguns pontos de contato (que podem ser outras camadas), e também garantir que exista um “meio de campo” entre certas camadas, ou seja, a interface não vai falar diretamente com o banco de dados, existe um caminho para isso. &lt;/p&gt;

&lt;p&gt;Um dos pontos negativos desses modelos é que eles não costumam definir a obrigação ou sugestão de interfaces para comunicação com serviços externos, normalmente services são totalmente acoplados à infraestrutura, em alguns casos, até mesmo temos DAO’s que implementam regras de persistência na camada de modelo. O problema disso é claro, nossas regras de negócio muitas vezes acabam acopladas à meras ferramentas, trocar o banco de dados exige que você mexa em um pedaço que deveria representar sua regra de negócio, o que não acontece em outros modelos como arquitetura hexagonal (a menos que você adapte seu padrão em camadas para ter abstrações significativas, o que é totalmente válido 🙂). &lt;/p&gt;

&lt;h3&gt;
  
  
  MVC
&lt;/h3&gt;

&lt;p&gt;O MVC (Model-View-Controller) é um pattern arquitetural usado como um molde pra distribuição de responsabilidades em trechos de código que tratam de interfaces com o usuário (UI). Há três responsabilidades pre-estabelecidas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View: contém a lógica que monta a UI (telas ou equivalente) e que trata a entrada de dados, recebendo eventos do usuário (clique, digitação etc.). As do usuário são repassadas para o Controller. A View pode buscar dados diretamente do Model para exibição na UL&lt;/li&gt;
&lt;li&gt;Controller. o "meio de campo", recebe interações do usuário da View e colabora com o Model para enviar e obter dados, que são repassados para a View.&lt;/li&gt;
&lt;li&gt;Model: o resto do código, que não tem a ver com UI. Realiza cálculos, regras de negócio, persistência, integrações com outros sistemas etc. Há diversas variações como MVP, MVVM, entre outros.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Outros exemplos → &lt;strong&gt;MVVM&lt;/strong&gt;&lt;br&gt;
The main thrust of the Model/View/ViewModel architecture seems to be that on top of the data (”the Model”), there’s another layer of non-visual components (”the ViewModel”) that map the concepts of the data more closely to the concepts of the view of the data (”the View”). It’s the ViewModel that the View binds to, not the Model directly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Arquitetura Hexagonal - Ports And Adapters
&lt;/h2&gt;

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

&lt;p&gt;A arquitetura hexagonal é uma proposta de arquitetura de software que segue lógicas de desenvolvimento de software que pensam em acoplamento e coesão, basicamente, módulos de alto nível (que possuem regras de negócio) não devem depender de implementações de módulos de baixo nível (frameworks, bibliotecas de terceiros, et cetera.). Tudo que acessa o coração / domínio / regra de negócio da sua aplicação deve passar por portas, que são basicamente interfaces que representam o que aquela biblioteca fará para você, chamamos a implementação dessas interfaces de adaptadores. &lt;/p&gt;

&lt;p&gt;Ou seja, em um sistema de login, podemos disparar um evento em uma fila de mensagens RabbitMQ que será consumido por um outro serviço de notificação, pensando em um nível um pouco mais abstrato, esquecendo bibliotecas ou ferramentas, podemos criar uma interface de publicador de eventos e dizer que vamos usar ela, ou seja, nossa lógica de negócio precisa enviar uma notificação de cadastro e um payload, independente se rabbitMQ, kafka ou outra porta está sendo usada:&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;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Notifier&lt;/span&gt; &lt;span class="n"&gt;messagePublisher&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;TicketService&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;Ticket&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Ticket&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;messagePublisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Notify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TicketEventsEnum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TICKET_CREATED&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;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;strong&gt;service&lt;/strong&gt;, a regra de negócio de criação de um ticket é exatamente essa, note que não estou usando uma regra de rabbitMQ necessariamente, nem mesmo o seu vocabulário (normalmente usaríamos publish) o importante para a regra de criação, é enviar uma notificação!&lt;/p&gt;

&lt;p&gt;A dependência Notifier é na realidade uma interface própria, que representa o que necessitamos, o envio de uma notificação, é uma porta.&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;Notifier&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Notify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;message&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 Adaptador, que é basicamente uma das opções de notificadores que vc tem é a implementação real, você poderia trocar os adaptadores e ainda assim não ter problemas no seu domínio, tendo em vista que todo adaptadores respeita a mesma interface (porta).&lt;/p&gt;

&lt;p&gt;Imagine que você está indo viajar, o núcleo da aplicação é o conteúdo essencial da sua mala - os itens vitais que você não pode deixar para trás. Os adaptadores são os diversos compartimentos e bolsos especializados na mala, cada um projetado para acomodar diferentes necessidades, você tem um plugue para tomadas da europa, outros para os estados unidos e outra que suporta o padrão adotado na ásia (não sei nem se é diferente). Da mesma forma, os adaptadores na arquitetura hexagonal conectam o núcleo da aplicação a interfaces externas variadas, como bancos de dados, interfaces de usuário e serviços externos, esses adaptadores permitem que a aplicação funcione em ambientes diversos. &lt;/p&gt;

&lt;h2&gt;
  
  
  Clean Architecture
&lt;/h2&gt;

&lt;p&gt;Não entrarei em detalhes pela sua complexidade e individualidades, mas saiba que tanto a clean architecture quanto a onion se baseiam no mesmo fundamento, de proteger a camada de domínio, com os mesmos princípios de abstração por interfaces, e adaptadores implementando-as&lt;/p&gt;

&lt;h1&gt;
  
  
  DDD - Isso não é sobre DDD
&lt;/h1&gt;

&lt;p&gt;O Deisgn orientado à Domínio (Domain Driven Design / DDD) é um conceito extenso e vai além de um sugestões sobre como dividir seu código em camadas (esse nem é o foco), comentando a maneira com que o software é escrito, a linguagem utilizada no processo de fabricação, o que são as fronteiras entre suas entidades e regras de negócio e como elas devem ser implementadas, realmente fazendo com que a preocupação de domínio seja a central na construção de software. &lt;/p&gt;

&lt;p&gt;Encare o DDD como uma &lt;em&gt;prescrição de metodologia e **processo&lt;/em&gt;** para o desenvolvimento de sistemas complexos cujo foco é mapear atividades, tarefas, eventos e dados dentro de um  domínio de problema nos artefatos de tecnologia de um domínio de solução.&lt;/p&gt;

&lt;p&gt;Apesar disso, &lt;strong&gt;Evans em seu livro deu diversas sugestões arquiteturais, como por exemplo, os services,&lt;/strong&gt; muitas vezes, mal utilizados ou interpretados. Veremos agora algumas sugestões e pontos do autor.&lt;/p&gt;

&lt;h2&gt;
  
  
  DDD - Sugestões Arquiteturais → e de design de código
&lt;/h2&gt;

&lt;p&gt;Antes de tudo, acho importante definir o que é o domínio de uma aplicação:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Domínio:&lt;/strong&gt;&lt;br&gt;
No contexto de Engenharia de Software é o “conhecimento” utilizado em uma determinada área de aplicação, um campo específico para qual o sistema foi desenvolvido, ou seja, os problemas, regras e soluções que envolvem uma parte da aplicação, apesar disso, muitas vezes nos referimos ao domínio de negócio (núcleo de regras e conhecimentos que envolvem o negócio) somente como domínio, leve isso em consideração, porém tenha em mente que uma aplicação tem diversos domínios.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quando o código relacionado &lt;strong&gt;ao domínio&lt;/strong&gt; é distribuído por uma porção tão grande de outros códigos (espalhado), torna-se extremamente difícil distingui-los e raciocinar. Alterações superficiais na interface do usuário podem realmente alterar a lógica de negócios (alterações vazam para onde não devem). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assim sendo:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Isole o modelo do domínio e a lógica de negócios e elimine qualquer dependência que eles possam ter na infraestrutura, na interface do usuário ou mesmo na lógica do aplicativo que não seja lógica de negócios. &lt;br&gt;
Particione um programa complexo em camadas. Desenvolva um design dentro de cada camada que seja coeso e que dependa apenas das camadas abaixo.&lt;/strong&gt; Concentre todo o código relacionado ao modelo do domínio em uma camada e isole-o do código da interface do usuário, do aplicativo e da infraestrutura. Os objetos de domínio, livres da responsabilidade de se exibir, de se armazenar, de gerenciar tarefas do aplicativo, e assim por diante, podem se concentrar em expressar o modelo do domínio. Isso permite que um modelo evolua para se tornar rico e limpo o suficiente para capturar o conhecimento essencial do negócio e colocá-lo para funcionar, sempre que uma regra de negócio surgir, o modelo de domínio deve ser o necessário por implementá-la, quem deve se adaptar às regras de negócio é a implementação, e nunca o contrário.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Dito isso, colocar as responsabilidades certas no domínio não significa que o modelo deve ser anêmico, o modelo pode (e deve) manter regras e formas para que seu escopo seja válido. Ou seja, fazemos o possível para que uma entidade de domínio nasça e continue sempre de acordo com suas regras de negócio.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Modelos Anêmicos - Um problema
&lt;/h2&gt;

&lt;p&gt;Conceito muito difundido no artigo &lt;strong&gt;Anemic Domain Model, de Martin Fowler.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Quando falamos de modelos de domínio anêmicos dizemos de modelos onde as regras de negócio associadas à uma entidade é externa à própria entidade. Temos uma classe pedido mas o método para verificar se o pedido contém itens ou não está em um “service”, que acaba sendo uma classe que possui regras que poderiam existir dentro de uma própria entidade (se contiver somente o seu comportamento). &lt;/p&gt;

&lt;p&gt;Classes que possuem somente atributos são classes de domínio anêmicas, idealmente, uma classe deve conter comportamento e atributos.&lt;/p&gt;

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

&lt;p&gt;Podemos chamar classes JAVA ou C# que são totalmente desacoplada de outras bibliotecas ou framewrks de POCO (no C#) ou POJO (no JAVA). Por serem códigos puros escritos em java ou  c#, que não deviram de uma classe base e nem retornam ou utilizam de tipos especiais, ou seja, são classes simples que sabem apenas de seu domínio, &lt;strong&gt;devemos sempre seguir os princípios da &lt;a href="https://ayende.com/blog/3137/infrastructure-ignorance" rel="noopener noreferrer"&gt;ignorância da infraestrutura&lt;/a&gt; e &lt;a href="https://deviq.com/principles/persistence-ignorance" rel="noopener noreferrer"&gt;ignorância da persistência&lt;/a&gt; para essas classes.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Portanto, as entidades não devem ser associadas aos modos de exibição do cliente pois, no nível da interface do usuário, alguns dados podem ainda não ter sido validados. É por esse motivo que o ViewModel existe. O ViewModel é um modelo de dados exclusivamente para necessidades de camada de apresentação. As entidades de domínio não pertencem diretamente ao ViewModel. Em vez disso, você precisa converter entre entidades de domínio e ViewModels e vice-versa. - *&lt;strong&gt;&lt;em&gt;Projetar um microsserviço orientado a DDD, Microsoft&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Refatorando um Domínio anêmico
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Atributos distantes do comportamento
&lt;/h3&gt;

&lt;p&gt;Para começar, recomendo ler o caso 1 de &lt;a href="https://www.notion.so/3-Refatora-o-Casos-Usuais-03076ae1673a41a39e0c8182df7b230c?pvs=21" rel="noopener noreferrer"&gt;3. Refatoração → Casos Usuais&lt;/a&gt;, depois volte aqui.  De maneira geral, classes devem guardar dentro de si atributos e comportamentos, se você possui comportamentos que agem sobre os atributos de uma classe específica, costuma fazer sentido encapsulá-los dentro da classe.&lt;/p&gt;

&lt;p&gt;Exemplo:&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;Class&lt;/span&gt; &lt;span class="nc"&gt;ComprarIngressoService&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;comprar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="n"&gt;pessoa&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Evento&lt;/span&gt; &lt;span class="n"&gt;evento&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pessoa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
            &lt;span class="c1"&gt;// menor de idade&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;pessoa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCadastro&lt;/span&gt;&lt;span class="o"&gt;()==&lt;/span&gt;&lt;span class="s"&gt;"ativo"&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
            &lt;span class="c1"&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;Esse tipo de validação é aparentemente inofensiva, contudo, frágil,  pode causar diversas repetições no código e aumentar pontos de contato para uma possível alteração, em alguns casos, esse tipo de erro piora muito a leitura. Faz sentido que a classe Pessoa cuide de propriedades das pessoas, logo, a refatoração a seguir é possível:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Class&lt;/span&gt; &lt;span class="nc"&gt;ComprarIngressoService&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;comprar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="n"&gt;pessoa&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Evento&lt;/span&gt; &lt;span class="n"&gt;evento&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pessoa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maiorDeIdade&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
            &lt;span class="c1"&gt;// menor de idade&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;pessoa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;estaAtiva&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
            &lt;span class="c1"&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;h3&gt;
  
  
  Construtores, Builders e falta de amor aos erros de compilação
&lt;/h3&gt;

&lt;p&gt;Um grande motivo para escrevermos códigos que são fortemente tipados é a possibilidade de perceber erros em tempo de compilação, erros que impedem que façamos coisas que não fazem sentido dado o contexto do que estamos tentando fazer, a semântica de string, por exemplo, entendida como cadeia de caracteres, não permite a soma de números a ela (&lt;strong&gt;Some&lt;/strong&gt; um à kaue).&lt;/p&gt;

&lt;p&gt;Dito isto, grande parte das classes de domínio não validam seu estado, muitas vezes nem em sua criação. É comum ver por ai classes com construtores vazios e códigos setters públicos (pois getters e setters &lt;strong&gt;teoricamente&lt;/strong&gt; protegem o encapsulamento) isso por si só não garante que uma classe irá ser usada como esperada, veja o exemplo a seguir.&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;Pessoa&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Pessoa&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="c1"&gt;// construtor vazio, no java é opcional    &lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@Getter&lt;/span&gt;
    &lt;span class="nd"&gt;@Setter&lt;/span&gt; &lt;span class="c1"&gt;// simulando o lombok, mas pode imaginar que são métodos getter e setters públicos&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;  &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Getter&lt;/span&gt;
    &lt;span class="nd"&gt;@Setter&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Getter&lt;/span&gt;
    &lt;span class="nd"&gt;@Setter&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// em algum outro lugar:&lt;/span&gt;
&lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="n"&gt;kaue&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;Pessoa&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;kaue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;kaue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kaue"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;kaue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPeso&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// teoricamente kaue está tranquilo levando em conta que todos os campos foram preenchidos, mas e o seguinte?&lt;/span&gt;
&lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="n"&gt;douglas&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;Pessoa&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;douglas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPeso&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não existe erro de compilação e nem de execução (POR ENQUANTO) aqui. &lt;/p&gt;

&lt;p&gt;É óbvio que os setters deveriam validar se os campos foram preenchidos de seguindo um certo padrão e que faltam métodos para lidar com o objeto pessoa como indicado no ponto anterior, o modelo está anêmico, mas esse não é o foco, criamos um objeto de uma Pessoa chamado douglas, que possui apenas seu peso definido, o que provavelmente não faz sentido quando pensamos na criação de uma pessoa em um sistema, deveríamos (dependendo do negócio) ao menos forçar o preenchimento de id e nome. &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;Pessoa&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Pessoa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// único construtor recebendo os campos opcionais.&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@Getter&lt;/span&gt;
    &lt;span class="c1"&gt;// setter não existe mais&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Getter&lt;/span&gt;
    &lt;span class="c1"&gt;// setter pode até existir, mas nesse caso não vou criar.&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Getter&lt;/span&gt;
    &lt;span class="nd"&gt;@Setter&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="n"&gt;peso&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// em algum outro lugar:&lt;/span&gt;
&lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="n"&gt;kaue&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;Pessoa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"kaue"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;kaue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPeso&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="n"&gt;douglas&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;Pessoa&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// erro&lt;/span&gt;
&lt;span class="n"&gt;douglas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPeso&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas e classes builders? Também não é incomum ver builders que esquecem de implementar os campos obrigatórios, para nossa felicidade, é algo simples de ser resolvido.&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;PessoaBuilder&lt;/span&gt; &lt;span class="n"&gt;pessoaBuilder&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;PessoaBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"kaue"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// construtor do BUILDER tem em si os parâmetros necessários para criar a classe que constrói&lt;/span&gt;
&lt;span class="c1"&gt;// se o método para pegar o builder for um método estático, só passar em seu parâmetro&lt;/span&gt;
&lt;span class="nc"&gt;Pessoa&lt;/span&gt; &lt;span class="n"&gt;kaue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pessoaBuilder&lt;/span&gt;
                                             &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withPeso&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usando o lombok  &lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;, podemos fazer:&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;lombok.Builder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builderMethodName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hiddenBuilder"&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;Person&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;surname&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;PersonBuilder&lt;/span&gt; &lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;hiddenBuilder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;// o nome desse builder interno é arbitrário&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Kaue"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;surname&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Surname"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa tática, usando o lombok ou não, tem alguns problemas e normalmente não faz sentido em classes que tem muitos parâmetros obrigatórios e até mesmo em algumas classes simples, pois depreca, mesmo que um pouco, uma das grandes vantagens que a classe builder tem, a visibilidade, imagine isso:&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;Endereco&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Endereco&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Osvaldo Albherto"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Parque Bitaru"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"42"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Abilio"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;complemento&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ap 1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maisInformacoes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pode entregar pro vizinho"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Somente lendo esse código, você só consegue ter certeza do complemento e maisInformacoes, os outros campos não são tão visíveis, ainda assim, como opinião pessoal, prefiro por ter esse código, que se torna um pouco menos visível mas garante o uso correto da classe, mostrando erros de compilação na própria IDE caso os atributos obrigatórios não estejam preenchidos. &lt;/p&gt;

&lt;h2&gt;
  
  
  Modelos Ricos: como lidar com dependências excessivas
&lt;/h2&gt;

&lt;p&gt;Se sua classe POJO de domínio necessitar de bibliotecas ou outras dependências (faça-as serem interfaces 🙏), instanciá-la ficará extremamente inconveniente, para isso existe o &lt;strong&gt;Design Pattern: Factory&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Pattern: Factory
&lt;/h3&gt;

&lt;p&gt;F*&lt;em&gt;actories são métodos (ou classes) que possuem como retorno a criação de um outro objeto&lt;/em&gt;*, em casos mais simples, podem ser métodos estáticos dentro da própria classe, em casos mais complexos, onde teremos diferentes dependências a serem injetadas nas classes de domínio atráves de  um framework ou container de injeção de dependência, como o Spring faz, podemos usar classes.&lt;/p&gt;

&lt;p&gt;Imagine a existência de uma classe usuário, que necessita que seu próprio email seja validado, e para isso, você quer usar uma biblioteca x ou y, você, respeitando princípios básicos, criará uma interface a qual Usuário dependerá, e fará com que a injeção de dependência passe a você uma instância do validador em algum momento, isso irá se tornar &lt;strong&gt;extremamente&lt;/strong&gt; inconveniente muito rápido, portanto, podemos fazer:&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;Usuario&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&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;EmailValidator&lt;/span&gt; &lt;span class="n"&gt;emailValidator&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;Usuario&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;EmailValidator&lt;/span&gt; &lt;span class="n"&gt;emailValidator&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emailValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emailValidator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isEmailValid&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;emailValidator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Outros métodos da classe Usuario&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;UsuarioFactory&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;EmailValidator&lt;/span&gt; &lt;span class="n"&gt;emailValidator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Construtor com injeção de dependência!&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UsuarioFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EmailValidator&lt;/span&gt; &lt;span class="n"&gt;emailValidator&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;emailValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emailValidator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Método para criar instância de Usuario usando o validador de e-mail fornecido pelo Spring (ou pelo seu framework de DI)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Usuario&lt;/span&gt; &lt;span class="nf"&gt;createUsuario&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Usuario&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;emailValidator&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  E os Services?
&lt;/h2&gt;

&lt;p&gt;Evans Descreve em seu livro três tipos de services:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application Service&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fornece para o usuário operações que o seu software pode executar, e controla a execução dessas operações através de chamadas a métodos de objetos das outras camadas (domínio, infraestrutura, etc.). &lt;strong&gt;É importante dizer que a Application Service não contém regras de negócios ou conhecimento do domínio&lt;/strong&gt;, sendo assim, ela apenas coordena as chamadas a métodos de outras camadas e mantém o estado que reflete o progresso de uma operação para o usuário.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Application Layer: Defines the jobs the software is supposed to do and directs the expressive domain objects to work out problems. The tasks this layer is responsible for are meaningful to the business or necessary for interaction with the application layers of other systems. This layer is kept thin. It does not contain business rules or knowledge, but only coordinates tasks and delegates work to collaborations of domain objects in the next layer down. It does not have state reflecting the business situation, but it can have state that reflects the progress of a task for the user or the program.  - Evans DDD&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Domain Services&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fornece para a &lt;strong&gt;Application Service&lt;/strong&gt; métodos que permitam a execução de operações sobre os objetos de Domínio (camada mais interna). &lt;strong&gt;Embora seja comum representar grande parte dos conceitos e regras principais do negócio aqui, o ideal é que esses detalhes sejam representados diretamente nos Domain Models.&lt;/strong&gt; Sendo assim, o Domain Service deve chamar e controlar a execução de métodos dos objetos do Domain Model &lt;strong&gt;quando não é trivial ou lógico declarar um método diretamente no modelo de domínio&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;As vezes, a situação simplesmente não se trata de uma coisa.&lt;/p&gt;

&lt;p&gt;Alguns conceitos do domínio não são naturais para serem modelados na forma de objetos.&lt;/p&gt;

&lt;p&gt;Forçar a funcionalidade do domínio necessária para que ela seja a responsabilidade de uma Entidade ou Objeto de Valor distorce a definição de um objeto baseado em modelos ou adiciona objetos artificiais sem sentido.&lt;/p&gt;

&lt;p&gt;Assim sendo:&lt;/p&gt;

&lt;p&gt;Quando um processo ou transformação significativa no domínio não é uma responsabilidade natural de uma Entidade ou Objeto de Valor, adicione uma operação no modelo como uma interface autônoma declarada como Serviço. Defina um contrato de serviço, um conjunto de asserções sobre interações com o Serviço. (Veja “asserções”) Torne essas asserções participantes da Linguagem Onipresente de um Contexto Delimitado específico. Dê um nome ao Serviço, que também se torne parte da Linguagem Onipresente.&lt;br&gt;
Evans - DDD&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure Services&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fornece métodos que permitem a execução de operações sobre a infraestrutura na qual o software está sendo executado. Isso significa que esses serviços tem conhecimento sobre detalhes das implementações concretas da infraestrutura tais como: acesso a bancos de dados, acesso a rede, controle de operações de IO, acesso a hardware etc. Geralmente esse service é utilizado pelos Application Services para complementar e auxiliar suas operações, por exemplo, fornecer um método que permita a criação e controle de um buffer para realizar download de arquivos.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Contrapontos:
&lt;/h2&gt;

&lt;p&gt;💡 &lt;strong&gt;&lt;em&gt;Regardless, if your microservice or Bounded Context is very simple (a CRUD service), the anemic domain model in the form of entity objects with just data properties might be good enough, and it might not be worth implementing more complex DDD patterns. In that case, it will be simply a persistence model, because you have intentionally created an entity with only data for CRUD purposes.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/microservice-domain-model" rel="noopener noreferrer"&gt;Design a microservice domain model&lt;/a&gt;&lt;/strong&gt; - Microsoft&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Some people say that the anemic domain model is an anti-pattern. It really depends on what you are implementing. If the microservice you are creating is simple enough (for example, a CRUD service), following the anemic domain model it is not an anti-pattern. However, if you need to tackle the complexity of a microservice’s domain that has a lot of ever-changing business rules, the anemic domain model might be an anti-pattern for that microservice or Bounded Context. In that case, designing it as a rich model with entities containing data plus behavior as well as implementing additional DDD patterns (aggregates, value objects, etc.) might have huge benefits for the long-term success of such a microservice.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft resource&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aqui entendemos uma coisa que deve ser clara, não existe bala de prata na computação, faz sentido abstraírmos o SPRING,  Controllers, Services e outras funcionalidades ou entedemos que nossa aplicação nasce acoplada ao SPRING e morre com ele? &lt;/p&gt;

&lt;p&gt;Aqui, tudo cabe à você entender pontos, contrapontos e o seu contexto, no seu caso. Se sua aplicação só existe junto à infraestrutura de uma biblioteca, talvez não haja motivo para desacoplá-la, se você não vê perspectivas para deixar de usar lombok, não necessariamente precisa fazer seu modelo de domínio POJOS realmente puras use seu lombok, e seja feliz. Um projeto simples ou que necessita ser entregue muito rapidamente não usar de conceitos como Arquitetura Hexagonal, DDD, CQRS ou qualquer outro pattern não se traduz emprojeto simples ou que significa código ruim.&lt;/p&gt;

&lt;h1&gt;
  
  
  Referências:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://herbertograca.com/2017/07/03/the-software-architecture-chronicles/" rel="noopener noreferrer"&gt;The Software Architecture Chronicles&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esse blog, essa crônica em específico - é maravilhosa!! Se estiver off, procure no wayback machine.&lt;/p&gt;

&lt;p&gt;Domain Driven Design, Eric Evans&lt;/p&gt;

&lt;p&gt;&lt;a href="https://martinfowler.com/bliki/AnemicDomainModel.html" rel="noopener noreferrer"&gt;Anemic Domain Model, Martin Fowler (Cosigned by Evans)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sumário de Padrões e Definições do DDD - Traduzido por Ricardo Pereira Dias&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/pt-br/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/ddd-oriented-microservice" rel="noopener noreferrer"&gt;Projetando um microsserviço orientado a DDD&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=1Lcr2c3MVF4" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=1Lcr2c3MVF4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://deviq.com/principles/persistence-ignorance" rel="noopener noreferrer"&gt;Persistence Ignorance | DevIQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ayende.com/blog/3137/infrastructure-ignorance" rel="noopener noreferrer"&gt;Infrastructure Ignorance&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.baeldung.com/hexagonal-architecture-ddd-spring" rel="noopener noreferrer"&gt;Hexagonal Architecture, DDD, and Spring | Baeldung&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>java</category>
      <category>architecture</category>
      <category>beginners</category>
    </item>
    <item>
      <title>RabbitMQ Com Java e Spring : Parte 2</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Mon, 13 Nov 2023 13:37:07 +0000</pubDate>
      <link>https://dev.to/kauegatto/rabbitmq-com-java-e-spring-parte-2-39eg</link>
      <guid>https://dev.to/kauegatto/rabbitmq-com-java-e-spring-parte-2-39eg</guid>
      <description>&lt;h3&gt;
  
  
  Nota:
&lt;/h3&gt;

&lt;p&gt;Nesse momento, entraremos um pouco mais em detalhes sobre como o protocolo AMQP funciona e sobre a biblioteca de AMQP do spring, escrevi um “guia” bem básico sobre propriedades do protocolo, se quiser conferir, pode ver aqui :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://prod-files-secure.s3.us-west-2.amazonaws.com/f9f3aa45-f67b-42fb-a9fd-ab2167038212/299d79c0-36e3-442a-a6bf-3cdf3d4e5a1a/mensageria.pdf"&gt;mensageria.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ou &lt;a href="https://drive.google.com/drive/folders/1PcESYtUyQ6O9QZun67YhjYXFjJSoCLZq?usp=sharing"&gt;nesse link&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contexto
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;Spring AMQP&lt;/code&gt; consiste em dois módulos principais: &lt;code&gt;spring-amqp&lt;/code&gt; e &lt;code&gt;spring-rabbit&lt;/code&gt;. O ‘spring-amqp’ contém o pacote &lt;code&gt;org.springframework.amqp.core&lt;/code&gt;, que trata das principais abstrações definidas no protocolo AMQP (RabbitMQ é um broker, que implementa esse protocolo), esse pacote não se baseia em nenhuma biblioteca de clientes nem implementação de broker.&lt;/p&gt;

&lt;p&gt;Essas abstrações então são implementadas pelos módulos específicos dos brokers (&lt;code&gt;spring-rabbit&lt;/code&gt;). &lt;a href="https://docs.spring.io/spring-amqp/reference/html/#amqp-abstractions"&gt;Teoricamente, como o AMQP é opera em nível de protocolo, você poderia utilizar o cliente do rabbit com outro broker, mas isso não é oficialmente suportado&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A mensagem
&lt;/h2&gt;

&lt;p&gt;A mensagem ****definida no protocolo amqp é um conjunto de bytes e propriedades, passados separadamente. Para tornar o uso mais fácil, dentro do java juntamos isso em uma abstração chamada &lt;code&gt;Message&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Message&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;MessageProperties&lt;/span&gt; &lt;span class="n"&gt;messageProperties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;body&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;Message&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MessageProperties&lt;/span&gt; &lt;span class="n"&gt;messageProperties&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&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;messageProperties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messageProperties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;getBody&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;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;MessageProperties&lt;/span&gt; &lt;span class="nf"&gt;getMessageProperties&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;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;messageProperties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A exchange
&lt;/h2&gt;

&lt;p&gt;A exchange é uma outra abstração simples, é basicamente o centro de distribuição de mensagens, que envia as mensagens de acordo com suas diretrizes:&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;Exchange&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getExchangeType&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isDurable&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isAutoDelete&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;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getArguments&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;Os tipos básicos de exchange são: &lt;code&gt;direct&lt;/code&gt;, &lt;code&gt;topic&lt;/code&gt;, &lt;code&gt;fanout&lt;/code&gt; e &lt;code&gt;headers&lt;/code&gt;. Você pode encontrar implementações para cada um dos tipos no pacote core.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &lt;code&gt;Topic&lt;/code&gt; exchange supports bindings with routing patterns that may include the '*' and '#' wildcards for 'exactly-one' and 'zero-or-more', respectively. The &lt;code&gt;Fanout&lt;/code&gt; exchange publishes to all queues that are bound to it without taking any routing key into consideration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;💡 A especificação AMQP define uma exchange padrão não nomeada, todas as queues sem exchange vinculadas são automaticamente vinculadas à ela, com seus nomes como routing keys&lt;/p&gt;

&lt;h2&gt;
  
  
  Queues
&lt;/h2&gt;

&lt;p&gt;A classe &lt;code&gt;Queue&lt;/code&gt; também representa uma abstração desse tipo no protocolo:&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;Queue&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;durable&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;volatile&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;exclusive&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;volatile&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;autoDelete&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;volatile&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * The queue is durable, non-exclusive and non auto-delete.
     *
     * @param name the name of the queue.
     */&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Getters e Setters omitidos&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bindings
&lt;/h2&gt;

&lt;p&gt;Bindings são a relação entre filas e exchanges!&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;new&lt;/span&gt; &lt;span class="nc"&gt;Binding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someQueue&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;someDirectExchange&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"foo.bar"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// direct exchange, routing keys fixas&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Binding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someQueue&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;someTopicExchange&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"foo.*"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// topic exchange, usando wildcard&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Binding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someQueue&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;someFanoutExchange&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// fanout&lt;/span&gt;
&lt;span class="nc"&gt;Binding&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BindingBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someQueue&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someTopicExchange&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"foo.*"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
&lt;span class="c1"&gt;// BindingBuilder é a maneira bonitinha, eu gosto, mas importa estático!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 Uma instância de uma &lt;code&gt;Binding&lt;/code&gt; não trará alterações reais por ela mesma, para isso, deveremos usar a classe &lt;code&gt;AmqpAdmin&lt;/code&gt; ou definir as bindings usando a anotação &lt;code&gt;@Bean&lt;/code&gt;, é o que veremos a seguir&lt;/p&gt;

&lt;h1&gt;
  
  
  Definindo Exchanges e Bindings customizadas
&lt;/h1&gt;

&lt;p&gt;Já vimos nos exemplos anteriores como as exchanges, bindings e queues são criadas, a partir de agora, só criar!&lt;/p&gt;

&lt;p&gt;Nossas configurações, ao invés de só possuir bean de &lt;code&gt;Queue&lt;/code&gt;, agora incluirão &lt;code&gt;Exchanges&lt;/code&gt;e &lt;code&gt;Bindings&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="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RabbitMqConfiguration&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;TicketQueueProperties&lt;/span&gt; &lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Bean&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt; &lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Looking for queue: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&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;Queue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nd"&gt;@Bean&lt;/span&gt; &lt;span class="nc"&gt;Exchange&lt;/span&gt; &lt;span class="nf"&gt;ticketDirectExchange&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;EXCHANGE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ticket"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Creating exchange: ticket-exchange"&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;DirectExchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;EXCHANGE_NAME&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nd"&gt;@Bean&lt;/span&gt; &lt;span class="nc"&gt;Binding&lt;/span&gt; &lt;span class="nf"&gt;ticketBinding&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Create ticket binding"&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;BindingBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticketDirectExchange&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;noargs&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;💡 Para fazer direito, provavelmente também faríamos o refactor da nossa &lt;code&gt;TicketQueueProperties&lt;/code&gt;, provavelmente teríamos um &lt;code&gt;RabbitMqProperties&lt;/code&gt;, onde deixaríamos configurações de filas, exchanges e bindings de maneira mais organizada!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1NHTDa-j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pa9zvwka9l93aimns0bf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1NHTDa-j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pa9zvwka9l93aimns0bf.png" alt="exchange" width="800" height="727"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perfeito, já vimos nossa exchange funcionando bonito! Tudo pronto!&lt;/p&gt;

&lt;p&gt;Só que não! Lembre-se que o nosso publisher está enviando mensagens com a routing key correta, mas para a exchange errada, vamos mudar o código para o seguinte:&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;rabbitTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;convertAndSend&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"direct.ticket"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Aqui deveríamos puxar esse nome da nossa ideal &lt;code&gt;TicketQueueProperties&lt;/code&gt; :) para evitar esse spaghetti&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Passando Objetos - Message Converters
&lt;/h1&gt;

&lt;p&gt;O &lt;strong&gt;&lt;code&gt;AmqpTemplate&lt;/code&gt;&lt;/strong&gt; também define vários métodos para enviar e receber mensagens que, no fim das contas, delegam tarefas para um &lt;strong&gt;&lt;code&gt;MessageConverter&lt;/code&gt;&lt;/strong&gt;. O &lt;strong&gt;&lt;code&gt;MessageConverter&lt;/code&gt;&lt;/strong&gt; fornece um método único para cada direção: um para converter para um &lt;strong&gt;&lt;code&gt;Message&lt;/code&gt;&lt;/strong&gt; e outro para converter a partir de um &lt;strong&gt;&lt;code&gt;Message&lt;/code&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Definição da interface &lt;strong&gt;&lt;code&gt;MessageConverter&lt;/code&gt;&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;MessageConverter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="nf"&gt;toMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MessageProperties&lt;/span&gt; &lt;span class="n"&gt;messageProperties&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;MessageConversionException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;fromMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;MessageConversionException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  SimpleMessageConverter
&lt;/h2&gt;

&lt;p&gt;A implementação padrão do strategy &lt;strong&gt;&lt;code&gt;MessageConverter&lt;/code&gt;&lt;/strong&gt; é chamada de &lt;strong&gt;&lt;code&gt;SimpleMessageConverter&lt;/code&gt;&lt;/strong&gt;. Este é o conversor usado por uma instância de &lt;strong&gt;&lt;code&gt;RabbitTemplate&lt;/code&gt;&lt;/strong&gt; se você não configurar explicitamente uma alternativa. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Converts a String to a &lt;code&gt;[TextMessage](https://jakarta.ee/specifications/platform/9/apidocs/jakarta/jms/TextMessage.html)&lt;/code&gt;, a byte array to a &lt;code&gt;[BytesMessage](https://jakarta.ee/specifications/platform/9/apidocs/jakarta/jms/BytesMessage.html)&lt;/code&gt;, a Map to a &lt;code&gt;[MapMessage](https://jakarta.ee/specifications/platform/9/apidocs/jakarta/jms/MapMessage.html)&lt;/code&gt;, and a Serializable object to a &lt;code&gt;[ObjectMessage](https://jakarta.ee/specifications/platform/9/apidocs/jakarta/jms/ObjectMessage.html)&lt;/code&gt; (or vice versa).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Trocando o Conversor
&lt;/h2&gt;

&lt;p&gt;Para trabalhar com objetos serializados e desserializados para JSON, vamos usar o &lt;code&gt;Jackson2JsonMessageConverter&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="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;MessageConverter&lt;/span&gt; &lt;span class="nf"&gt;messageConverter&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;Jackson2JsonMessageConverter&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;Colocaremos isso tanto no consumer quanto no producer :)&lt;/p&gt;




&lt;h1&gt;
  
  
  Declarables, Definição Dinâmica e Declarativa de Filas
&lt;/h1&gt;

&lt;p&gt;Falamos anteriormente do nosso&lt;code&gt;TicketQueueProperties&lt;/code&gt; , que poderíamos melhorá-lo, é o que vamos fazer, na realidade, vamos substituí-lo.&lt;/p&gt;

&lt;p&gt;Primeiro de tudo, vamos definir um formato declarativo para filas, exchanges e bindings que nos agrade, para mim:&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;broker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;queues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ticket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default.ticket&lt;/span&gt;
    &lt;span class="na"&gt;exchanges&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ticket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;direct.ticket&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;direct&lt;/span&gt;
    &lt;span class="na"&gt;bindings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ticket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;direct.ticket&lt;/span&gt;
            &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default.ticket&lt;/span&gt;
            &lt;span class="na"&gt;routingKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default.ticket&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Criando um ConfigurationProperties adequado
&lt;/h2&gt;

&lt;p&gt;A partir disso, vamos mapear essas propriedades em classes de uma maneira adequada. Chamarei a classe de &lt;code&gt;BrokerConfigurationProperties&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;package&lt;/span&gt; &lt;span class="nn"&gt;com.kaue.ticketservice.infrastructure.properties&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;jakarta.validation.constraints.NotEmpty&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.springframework.boot.context.properties.ConfigurationProperties&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.springframework.context.annotation.Configuration&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.Map&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;lombok.Data&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"broker"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BrokerConfigurationProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;QueueProperties&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;queues&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExchangeProperties&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exchanges&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BindingProperties&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bindings&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Data&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueueProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Data&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExchangeProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Data&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BindingProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;routingKey&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;ul&gt;
&lt;li&gt;Possuímos 3 maps, estruturas que linkam uma chave à sua correspondente configuração, &lt;code&gt;Queue&lt;/code&gt;, &lt;code&gt;Exchange&lt;/code&gt; ou &lt;code&gt;Binding&lt;/code&gt; Properties.&lt;/li&gt;
&lt;li&gt;Fazemos o mapeamento padrão, usando : &lt;code&gt;@ConfigurationProperties(prefix = "broker")&lt;/code&gt;, até aqui, sem segredos 🙂&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Transformando as propriedades em objetos!
&lt;/h2&gt;

&lt;p&gt;A partir de agora, o terceiro passo pode parecer simples, devemos criar beans a partir das propriedades, isso não é um problema, pelo menos não se quisermos definir os Beans da maneira que fizemos antes, apesar disso, se quisermos definir uma lista de Queues, Exchanges e Bindings, devemos usar a classe &lt;code&gt;Declarables&lt;/code&gt;, e prover um bean para ela.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://docs.spring.io/spring-amqp/api/org/springframework/amqp/core/Declarables.html"&gt;Declarables: &lt;em&gt;“…Used to declare multiple objects on the broker using a single bean declaration for the collection.”&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Declarables&lt;/span&gt; &lt;span class="nf"&gt;es&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;Declarables&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;DirectExchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"e2"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&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;DirectExchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"e3"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Declarables&lt;/span&gt; &lt;span class="nf"&gt;qs&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;Declarables&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;Queue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"q2"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"q3"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Declarables&lt;/span&gt; &lt;span class="nf"&gt;bs&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;Declarables&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;Binding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"q2"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DestinationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;QUEUE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"e2"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"k2"&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Binding&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"q3"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DestinationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;QUEUE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"e3"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"k3"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O exemplo acima, &lt;a href="https://docs.spring.io/spring-amqp/reference/html/#collection-declaration"&gt;da documentação de referência do spring&lt;/a&gt;, é uma boa forma de exemplificar o uso mais simples de Declarables, vamos ver minha implementação em particular, que adiciona declarables de acordo com a &lt;code&gt;BrokerConfigurationProperties&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;package&lt;/span&gt; &lt;span class="nn"&gt;com.kaue.ticketservice.infrastructure.configuration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ... ommitted&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * This classes creates all queues, exchanges and bindings based on application.yaml when they're needed (called by a consumer or posted a message into).
 */&lt;/span&gt;
&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RabbitMqConfiguration&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;BrokerConfigurationProperties&lt;/span&gt; &lt;span class="n"&gt;brokerConfig&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;Queue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;definedQueues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;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;Exchange&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;definedExchanges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@Bean&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Declarables&lt;/span&gt; &lt;span class="nf"&gt;queues&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brokerConfig&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;brokerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getQueues&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Declarables&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Return an empty list if no queues are configured&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;queueList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;brokerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getQueues&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;values&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="nl"&gt;Objects:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;nonNull&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;queueProperties&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;Queue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;definedQueues&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queueList&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Declared queues"&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;Declarables&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queueList&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nd"&gt;@Bean&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Declarables&lt;/span&gt; &lt;span class="nf"&gt;exchanges&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brokerConfig&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;brokerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExchanges&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Declarables&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Return an empty list if no exchanges are configured&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;exchangesList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;brokerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExchanges&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;values&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="nl"&gt;Objects:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;nonNull&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;exchangeProperties&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;DirectExchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchangeProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="c1"&gt;// todo use correct exchange type&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;definedExchanges&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchangesList&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Declared exchanges"&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;Declarables&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchangesList&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nd"&gt;@Bean&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Declarables&lt;/span&gt; &lt;span class="nf"&gt;bindings&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brokerConfig&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;brokerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBindings&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Declarables&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;bindingsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;brokerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBindings&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;values&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;bindingProperties&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Creating binding between exchange {} and queue {} with routing key {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;bindingProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExchange&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;bindingProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getQueue&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;bindingProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRoutingKey&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
          &lt;span class="nc"&gt;Queue&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findQueueByName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bindingProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getQueue&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
          &lt;span class="nc"&gt;Exchange&lt;/span&gt; &lt;span class="n"&gt;exchange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findExchangeByName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bindingProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExchange&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;BindingBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bindingProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRoutingKey&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;noargs&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;toList&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;Declarables&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bindingsList&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;Queue&lt;/span&gt; &lt;span class="nf"&gt;findQueueByName&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;queueName&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;definedQueues&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;queue&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;queueName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&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;orElse&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="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Exchange&lt;/span&gt; &lt;span class="nf"&gt;findExchangeByName&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;exchangeName&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;definedExchanges&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;exchange&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exchangeName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&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;orElse&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Embora grande, a implementação é relativamente simples, usamos streams para transformar as propriedades em classes reais e retornamos o Declarable como um &lt;code&gt;Bean&lt;/code&gt;, um objeto gerenciado pelo spring.&lt;/p&gt;

&lt;h1&gt;
  
  
  Poderes de RabbitListener
&lt;/h1&gt;

&lt;p&gt;No Spring, quando um método anotado como listener joga uma exception, as mensagens podem ser inseridas novamente na fila e reprocessadas, descartadas ou colocadas em uma Dead Letter Queue. Nada é devolvido ao emissor da mensagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Handling
&lt;/h2&gt;

&lt;p&gt;Na versão 2.0 do Spring AMQP em diante, @RabbitLisetener tem 2 atributos: &lt;code&gt;errorHandler&lt;/code&gt; e&lt;code&gt;returnExceptions&lt;/code&gt;, mas eles não são configurados por padrão.&lt;/p&gt;

&lt;p&gt;Você pode usar o &lt;code&gt;errorHandler&lt;/code&gt; para prover um Bean de &lt;code&gt;RabbitListenerErrorHandler&lt;/code&gt;. Essa interface funcional tem um 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="nd"&gt;@FunctionalInterface&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;RabbitListenerErrorHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="n"&gt;amqpMessage&lt;/span&gt;&lt;span class="o"&gt;,&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;springframework&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;messaging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
              &lt;span class="nc"&gt;ListenerExecutionFailedException&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui, por exemplo, poderíamos dizer que exceções de serviço ou fatais jogam exceções &lt;strong&gt;&lt;code&gt;AmqpRejectAndDontRequeueException&lt;/code&gt;,&lt;/strong&gt; para evitar requeue.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As you can see, you have access to the raw message received from the container, the spring-messaging &lt;code&gt;Message&amp;lt;?&amp;gt;&lt;/code&gt; object produced by the message converter, and the exception that was thrown by the listener (wrapped in a &lt;code&gt;ListenerExecutionFailedException&lt;/code&gt;). The error handler can either return some result (which is sent as the reply) or throw the original or a new exception (which is thrown to the container or returned to the sender, depending on the &lt;code&gt;returnExceptions&lt;/code&gt; setting).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A citação acima comenta uma maneira de enviar exceptions de volta ao sender,  se te interessar, pode &lt;a href="https://docs.spring.io/spring-amqp/docs/current/reference/html/#annotation-error-handling"&gt;ver aqui&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Retries!
&lt;/h2&gt;

&lt;p&gt;Podemos customizar e modificar configurações de retry indicadas dentro do nosso projeto, para isso usaremos o projeto &lt;code&gt;spring-retry&lt;/code&gt;, vamos ver uma configuração simples no &lt;code&gt;Bean&lt;/code&gt; do &lt;code&gt;RabbitTemplate&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="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RabbitTemplate&lt;/span&gt; &lt;span class="nf"&gt;rabbitTemplate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;RabbitTemplate&lt;/span&gt; &lt;span class="n"&gt;template&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;RabbitTemplate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionFactory&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="nc"&gt;RetryTemplate&lt;/span&gt; &lt;span class="n"&gt;retryTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RetryTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fixedBackoff&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;retryOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RemoteAccessException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;retryTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// ... do something&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRetryTemplate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retryTemplate&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;template&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;Para mais informações, veja o &lt;code&gt;[spring-retry](https://github.com/spring-projects/spring-retry#using-retrytemplate)&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Dead Letters
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;When a listener throws an exception, it is wrapped in a &lt;code&gt;ListenerExecutionFailedException&lt;/code&gt;. Normally the message is rejected and requeued by the broker. Setting &lt;code&gt;defaultRequeueRejected&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; causes messages to be discarded (or routed to a dead letter exchange).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vamos tentar seguir o que o comentário acima da documentação do spring diz:&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;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;rabbitmq &lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;... adresses e outras configs&lt;/span&gt;
        &lt;span class="s"&gt;listener&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;simple&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;default-requeue-rejected&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois dessa configuração, as mensagens quando possuem um erro são DELETADAS, desabilitando os retries. Isso provavelmente não é o que queremos, por isso, vamos estudar as DLQ’s.&lt;/p&gt;

&lt;p&gt;Dead Letter Queues (DLQ) são filas que possuem mensagens que tiveram sua execução falhada em algum momento, o comportamento das DLQ’s pode ser configurado no próprio broker.&lt;/p&gt;

&lt;p&gt;Dead Letter Queues são úteis em sistemas mais críticos, onde necessitamos que um job rode de qualquer forma, onde podemos jogar mensagens de DLQ’s na exchange padrão novamente, ou pelo menos entendermos o porquê daquilo não ter sido executado, essas filas possuem diversas funções.&lt;/p&gt;

&lt;p&gt;A maneira de definir dead letters é algo explicado dentro do protocolo AMQP, podemos apenas seguir essa configuraçã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="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="nc"&gt;Queue&lt;/span&gt; &lt;span class="nf"&gt;messagesQueue&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;QueueBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"queue-name"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withArgument&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"x-dead-letter-exchange"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"nome-exchange.dlx"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withArgument&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"x-dead-letter-routing-key"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"queue-name.dlq"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// nao precisa ser o nome da queue, mas é comum para direct&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="nc"&gt;Queue&lt;/span&gt; &lt;span class="nf"&gt;deadLetterQueue&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;QueueBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;durable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"queue-name.dlq"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No fim das contas, uma dead letter queue é uma queue normal, e uma dead letter exchange também, portanto, se uma mensagem chegar na DLX (Dead Letter Exchange) e não tiver uma routing key correta, ela não chegará na fila, tudo normal por aqui.&lt;/p&gt;

&lt;p&gt;💡 Se tivermos uma exchange como string vazia, ela usará a exchange padrão!&lt;/p&gt;

&lt;h1&gt;
  
  
  Observações
&lt;/h1&gt;

&lt;p&gt;Existem diversas maneiras de trabalhar com rabbitMQ, e uma infinidade de propriedades e configurações não mostradas aqui, como por exemplo: Feedback síncrono de exchanges e filas, Consumers Assíncronos, Containers Diferentes, propriedades de requeue, monitoramento de consumers, etc. Se algo fizer sentido para seu contexto, pode buscar no material de referência do Spring 🙂&lt;/p&gt;

&lt;p&gt;Mais sobre DLQ: &lt;a href="https://www.youtube.com/watch?v=GgIJWxk_-jM"&gt;https://www.youtube.com/watch?v=GgIJWxk_-jM&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mais sobre exception handling: &lt;a href="https://www.baeldung.com/spring-amqp-error-handling"&gt;https://www.baeldung.com/spring-amqp-error-handling&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://docs.spring.io/spring-amqp/reference/html/#template-retry"&gt;https://docs.spring.io/spring-amqp/reference/html/#template-retry&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/spring-projects/spring-retry"&gt;https://github.com/spring-projects/spring-retry&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.baeldung.com/spring-amqp-error-handling"&gt;https://www.baeldung.com/spring-amqp-error-handling&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>spring</category>
      <category>java</category>
      <category>rabbitmq</category>
    </item>
    <item>
      <title>RabbitMQ com Java e Spring : Começando (pt. 1)</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Tue, 31 Oct 2023 19:33:39 +0000</pubDate>
      <link>https://dev.to/kauegatto/rabbitmq-com-java-e-spring-comecando-pt-1-265f</link>
      <guid>https://dev.to/kauegatto/rabbitmq-com-java-e-spring-comecando-pt-1-265f</guid>
      <description>&lt;p&gt;Bem vindo(a)! ao meu post de RabbitMQ com JAVA. &lt;strong&gt;Esse post não tem como objetivo te ensinar RabbitMQ em detalhes ou até o protocolo AMQP. Na realidade, possuo um outro artigo onde comento sobre algumas peculiaridades do protocolo AMQP&lt;/strong&gt; &lt;a href="https://drive.google.com/drive/folders/1PcESYtUyQ6O9QZun67YhjYXFjJSoCLZq?usp=sharing"&gt;nesse link&lt;/a&gt;. De qualquer forma, na parte dois vou explicar por cima o que são filas, exchanges, bindings e seus tipos.&lt;/p&gt;

&lt;p&gt;A ideia hoje é fazermos algo realmente simples e &lt;strong&gt;mão na massa&lt;/strong&gt;: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configurarmos nosso rabbitMQ no docker com docker-compose&lt;/li&gt;
&lt;li&gt;Configurarmos um publisher, que envia mensagens de texto para as filas do RabbitMQ&lt;/li&gt;
&lt;li&gt;Configurarmos um consumer, que recebe essas mensagens e as trata.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Configuração Básica
&lt;/h1&gt;

&lt;p&gt;Antes de tudo, precisamos subir um servidor do Rabbit em nossa máquina local, a melhor maneira, na minha visão, de fazer isso, é usando docker, curto mais usar compose pra essas tarefas, então:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;version: &lt;span class="s1"&gt;'3.1'&lt;/span&gt;

services:
  rabbitmq:
      image: rabbitmq:management
      container_name: &lt;span class="s1"&gt;'rabbitmq'&lt;/span&gt;
      ports:
        - &lt;span class="s2"&gt;"5672:5672"&lt;/span&gt;
        - &lt;span class="s2"&gt;"15672:15672"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois disso, você pode rodar &lt;code&gt;docker-compose up&lt;/code&gt; e ser feliz. (Você vai precisar ter docker &amp;amp; docker compose instalados).]&lt;br&gt;
&lt;strong&gt;Verifique sua instalação em &lt;code&gt;localhost:15672&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Definindo propriedades para a fila
&lt;/h2&gt;

&lt;p&gt;Gosto de organizar propriedades em um &lt;code&gt;ConfigurationProperty&lt;/code&gt; (principalmente quando elas podem crescer, o que é o caso), que busca informações do &lt;code&gt;application.properties&lt;/code&gt; ou &lt;code&gt;application.yaml&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Nesse caso em específico, vou fazer algo bem simples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.kaue.ticketservice.infrastructure.properties&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;lombok.Getter&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;lombok.Setter&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.springframework.boot.context.properties.ConfigurationProperties&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.springframework.stereotype.Component&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"broker.queue.ticket"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@Getter&lt;/span&gt;
&lt;span class="nd"&gt;@Setter&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;TicketQueueProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&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 yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;broker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ticket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default.ticket&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Poderíamos ter múltiplas entries, e cada queue poderia ter outras propriedades além de name (faremos isso na parte 2 😈):&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;broker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;queues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ticket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default.ticket&lt;/span&gt;
      &lt;span class="na"&gt;durable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;autoDelete&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;exclusive&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;otherQueue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;other.queue&lt;/span&gt;
      &lt;span class="na"&gt;durable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;autoDelete&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;exclusive&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se quiser adicionar mais filas, definiria uma classe com as configurações para cada fila e definiria o &lt;code&gt;ConfigurationProperties&lt;/code&gt; mais ou menos assim:&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;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"broker.queues"&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;QueueProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;QueueConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;queue&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;Mas a princípio, vamos atuar só com ticket e name, do jeito que passei anteriormente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Definindo a conexão com o Rabbit
&lt;/h2&gt;

&lt;p&gt;No seu application yaml ou properties, adicione:&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;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rabbitmq&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;addresses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${amqpURL:amqp://guest:guest@localhost}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso, se a variável de ambiente amqpURL existir, ela será utilizada, caso contrário, será utilizado o padrão guest:guest, que funcionará perfeitamente com o docker compose apresentado anteriormente, então não precisa mexer se não for usar rabbit cloud ou tiver configurados as credenciais :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Adicionando a dependência Spring-Amqp
&lt;/h2&gt;

&lt;p&gt;O RabbitMQ é uma ferramenta que implementa regras do protocolo AMQP, portanto, usaremos o Spring AMQP como dependência para configurar o nosso Rabbit!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-amqp&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.amqp&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-rabbit-test&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Criando uma Configuração Básica para Beans do Rabbit
&lt;/h2&gt;

&lt;p&gt;O Spring boot trabalha com beans, que são basicamente objetos os quais ele instancia e gera, nesse caso, vamos prover configurações de beans do &lt;code&gt;rabbit&lt;/code&gt; para o SPRING tomar conta, ou seja, criando um bean do tipo &lt;code&gt;Queue&lt;/code&gt;, uma fila será criada automaticamente&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;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RabbitMqConfiguration&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;TicketQueueProperties&lt;/span&gt; &lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Bean&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt; &lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Looking for queue: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&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;Queue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="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;⚠️ Para evitar confusão: &lt;/p&gt;

&lt;p&gt;Estou usando &lt;code&gt;RequiredArgsConstructor&lt;/code&gt; com um campo final: &lt;code&gt;TicketQueueProperties&lt;/code&gt;, &lt;code&gt;RequiredArgsConstructor&lt;/code&gt; faz com que exista um construtor que contenha todos os campos &lt;code&gt;final&lt;/code&gt; nele, portanto, como é o único construtor, o Spring Boot o usará e automaticamente irá inserir a dependência &lt;code&gt;TicketQueueProperties&lt;/code&gt; correta, o resultado é o mesmo que o &lt;code&gt;@Autowired&lt;/code&gt;, mas a injeção via construtor é mais recomendada que o uso de Autowired ☝️🤓!&lt;br&gt;
Aqui, podemos definir diversos beans, configurações de outras filas e exchanges, et cetera, um método para cada Bean;&lt;/p&gt;
&lt;h1&gt;
  
  
  Definindo o primeiro Publisher
&lt;/h1&gt;

&lt;p&gt;Aqui vamos usar a composição e injetar na nossa classe uma instância de &lt;code&gt;RabbitTemplate&lt;/code&gt;, depois, usar o método publish. Nesse caso, vamos utilizar a exchange padrão, e o nome da fila será o primeiro parâmetro, sendo o segundo a mensagem em si.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ommitted &lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.AllArgsConstructor&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;lombok.extern.slf4j.Slf4j&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.springframework.amqp.rabbit.core.RabbitTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RabbitTicketPublisher&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MessagePublisher&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;TicketQueueProperties&lt;/span&gt; &lt;span class="n"&gt;ticketQueueProperties&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;RabbitTemplate&lt;/span&gt; &lt;span class="n"&gt;rabbitTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Notifying queue: {} of text{}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;rabbitTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;convertAndSend&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;&lt;span class="n"&gt;text&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;MessagePublisher&lt;/code&gt;é uma interface própria que defini em meu domínio, para desacoplar a camada de infraestrutura, deixei apenas um método publish, onde enviamos os eventos e/ ou mensagens para algum lugar, as implentações sabem que lugar é esse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Definindo a injeção de dependências.
&lt;/h2&gt;

&lt;p&gt;De maneira similar ao que já vi em C#, optei por cuidar da DI mais manualmente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ommitted&lt;/span&gt;

&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DIConfiguration&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;TicketRepository&lt;/span&gt; &lt;span class="n"&gt;ticketRepository&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;TicketQueueProperties&lt;/span&gt; &lt;span class="n"&gt;ticketQueueProperties&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;RabbitTemplate&lt;/span&gt; &lt;span class="n"&gt;rabbitTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nd"&gt;@Bean&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;TicketService&lt;/span&gt; &lt;span class="nf"&gt;ticketService&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;TicketService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticketRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ticketsMessagePublisher&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nd"&gt;@Bean&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;MessagePublisher&lt;/span&gt; &lt;span class="nf"&gt;ticketsMessagePublisher&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;RabbitTicketPublisher&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticketQueueProperties&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rabbitTemplate&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;Poderíamos também criar uma interface para cada publisher, mas não sei o quanto gostaria dessa abordagem, talvez haja algo melhor, mas para mim, cuidar da desambiguação de Beans dessa forma não está sendo um problema (por hora)&lt;/p&gt;

&lt;h1&gt;
  
  
  O Primeiro Consumer:
&lt;/h1&gt;

&lt;p&gt;Aqui, vamos definir que estamos ouvindo a fila de nome X pela annotation &lt;code&gt;@RabbitListener&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="nd"&gt;@Slf4j&lt;/span&gt;
&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketConsumer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@RabbitListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"${broker.queue.ticket.name}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;listenEmailQueue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Payload&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&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;Aqui estou usando o @Value ao invés do configuration properties para exemplificar, sei que diversas pessoas preferem essa abordagem!&lt;/p&gt;

&lt;h1&gt;
  
  
  Resultado
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9dexgvfe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/leceodvqowfaxhpljisn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9dexgvfe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/leceodvqowfaxhpljisn.png" alt="Logs on console, rabbit running" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KRI2LSx_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k2rmjsg8dkxbznwa6u5n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KRI2LSx_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k2rmjsg8dkxbznwa6u5n.png" alt="Rabbit gui showing queue consumption and message handling" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Parte 2 : O que veremos
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;O que são filas, exchanges e bindings &lt;/li&gt;
&lt;li&gt;Definição automática elegante de filas, exchanges e bindings via application yaml usando declarables&lt;/li&gt;
&lt;li&gt;Enviando objetos!&lt;/li&gt;
&lt;li&gt;Outros super poderes do protocolo (introdução) : Retries, DLQ, DLXZ&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;a href="https://docs.spring.io/spring-amqp/reference/html/#template-retry"&gt;https://docs.spring.io/spring-amqp/reference/html/#template-retry&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rabbit</category>
      <category>java</category>
      <category>spring</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Encapsulamento: O Básico que todo jr. precisa saber!</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Wed, 25 Oct 2023 23:15:24 +0000</pubDate>
      <link>https://dev.to/kauegatto/encapsulamento-o-basico-que-todo-jr-precisa-saber-5b4k</link>
      <guid>https://dev.to/kauegatto/encapsulamento-o-basico-que-todo-jr-precisa-saber-5b4k</guid>
      <description>&lt;p&gt;&lt;a href="https://kauegatto.notion.site/1-Boas-pr-ticas-1323bd5daa404b049bb2a21bcd159cf1?pvs=4" rel="noopener noreferrer"&gt;Leitura no Notion: Boas práticas&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kauegatto.notion.site/1-1-Mais-Sobre-Encapsulamento-9f88dc2274d04382b373352440bfc77c?pvs=4" rel="noopener noreferrer"&gt;Leitura no Notion: Mais sobre encapsulamento&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Mudanças em Cascata, Menos pontos de contato
&lt;/h1&gt;

&lt;p&gt;Encapsulamento é um princípio fundamental da programação orientada a objetos (POO) que ajuda a controlar o acesso e a modificação de dados dentro de uma classe. Ele se refere à prática de esconder os detalhes de implementação de uma classe de códigos externos e expor apenas uma interface pública para interagir com a classe. Isso pode ajudar a evitar mudanças em cascata em um sistema de software limitando o número de pontos de contato entre diferentes partes do código.&lt;/p&gt;

&lt;p&gt;Uma maneira de alcançar o encapsulamento (pelo menos em uma linguagem OO) é usando modificadores de acesso como "private" ou "protected" em campos e métodos de classe. Isso pode evitar que códigos externos acessem ou modifiquem diretamente o estado interno da classe e forçar o uso de métodos ou propriedades públicas que fornecem uma forma controlada de interagir com a classe.&lt;/p&gt;

&lt;p&gt;Essa não é a única maneira e nem todos os atributos de uma classe devem ter cegamente getters e setters, faz sentido uma pessoa depois de sua criação ter seu id alterado? Esse setter tem que existir, realmente? Outra ocasião importante que indica falta de encapsulamento é comentada no ponto 1 do capítulo de &lt;a href="https://www.notion.so/3-Refatora-o-Casos-Usuais-03076ae1673a41a39e0c8182df7b230c?pvs=21" rel="noopener noreferrer"&gt;3. Refatoração → Casos Usuais&lt;/a&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;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getData&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;data&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setData&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;newData&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newData&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 encapsulamento também pode ser usado para evitar mudanças em cascata mantendo o número de pontos de contato entre diferentes partes do código o mínimo possível. Ou seja, ao invés de termos em 5 lugares diferentes o código &lt;code&gt;Float.parseFloat(getData())&lt;/code&gt; poderíamos encapsular isso dentro de um método na classe Data se isso for uma regra de Data ou um comportamento relacionado à ela (mesmo que não seja, provavelmente é um comportamento de alguma outra classe). Depois dessa refatoração, ao mexermos nesse método, cuidaremos dos 5 pontos que o utilizam, ao invés de ficar buscando por ai a linha de Float.parseFloat(getData()) e quebrarmos o código pois não encontramos uma ocorrência.&lt;/p&gt;

&lt;h2&gt;
  
  
  Devo abstrair um determinado parâmetro/retorno?
&lt;/h2&gt;

&lt;p&gt;Já dissemos muito sobre abstrações e encapsulamento, mas quando você deve abstrair um certo parâmetro ou retorno? Aquele atributo String CPF na sua classe é realmente prejudicial? Se sim, vale a pena criar uma classe para defini-lo?&lt;/p&gt;

&lt;p&gt;Suponha que você precise criar um objeto Usuário, que tem como parâmetro do construtor um nome e senha.&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;Usuario&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="nf"&gt;Usuario&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;senha&lt;/span&gt;&lt;span class="o"&gt;){}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;Usuario&lt;/span&gt; &lt;span class="n"&gt;user1&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;Usuario&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kaue"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"123456"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso, como você pode garantir que usuário deve receber sua senha como plain text, e não depois de passar por um hash? Ou que a senha deve ter ao menos 6 caracteres, isso foge da lógica e semântica estabelecida pela tipo String, apesar disso, não é uma validação que dá muito trabalho, um simples length já resolveria o problema do tamanho, nesse caso, não acho que valeria criar uma classe somente para isso, mas quanto ao problema do hash, como validaríamos que o cliente usou corretamente o construtor e passou uma senha como plain text?&lt;/p&gt;

&lt;p&gt;É simples, somente ver a implementação da classe Usuário, mas se isso não está claro, temos ai um &lt;em&gt;code smell,&lt;/em&gt; uma espécie de acoplamento mental. Se você não tivesse acesso à Usuário, não teria como adivinhar.  Nesse caso em específico, mudar o nome da variável para plainText seria uma solução caso. &lt;/p&gt;

&lt;p&gt;Contudo, se a solução não for tão simples, acredito que normalmente passa a valer a pena criar uma classe de domínio para o parâmetro (ou retorno). Uma classe Senha com um construtor privado e métodos factory seria uma alternativa.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F01652d07-158d-4164-9834-1fd6c1bbe164%2FUntitled.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F01652d07-158d-4164-9834-1fd6c1bbe164%2FUntitled.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Trazendo isso para um exemplo real, durante o handling de metadatas as guardávamos como &lt;code&gt;Map&amp;lt;String,Object&amp;gt;&lt;/code&gt; , repetidos em diversos lugares, apesar disso, usávamos o Map em seu exato contexto, sem a necessidade de métodos a mais além dos próprios do Map e o seu contexto e significado era exatamente o que um map representava, nesse caso, não sentimos necessidade de abstrair o tipo.&lt;/p&gt;

&lt;h1&gt;
  
  
  Protegendo Fronteiras
&lt;/h1&gt;

&lt;p&gt;As fronteiras são a parte do seu software que agem como portas ao mundo externo. No caso de uma API, os seus clientes e pessoas que chamam a API também são externos, nenhum dado externo deve ser confiado.&lt;/p&gt;

&lt;p&gt;Proteger as fronteiras de um software refere-se a garantir que as interfaces externas e entradas do software sejam validadas e sanitizadas adequadamente para evitar ataques maliciosos ou entradas inesperadas. Isso é uma parte importante da segurança de software e pode ajudar a prevenir problemas como SQL Injection, cross-site scripting (XSS) e outros tipos de ataques de injeção.&lt;/p&gt;

&lt;p&gt;Uma das principais partes de proteger as fronteiras de software é a validação de entrada (input validation). Isso envolve verificar todos os dados de entrada para garantir que eles atendam a certos critérios antes de serem processados. Por exemplo, uma entrada de formulário pode ser necessária para ter um certo comprimento ou estar em um formato específico. Isso pode ajudar a prevenir erros e comportamentos inesperados, além de proteger contra entradas maliciosas.&lt;/p&gt;

&lt;p&gt;Outra parte importante de proteger as fronteiras de software é a sanitização. Isso envolve remover ou modificar qualquer elemento potencialmente prejudicial de dados de entrada. Por exemplo, uma aplicação web pode sanitizar a entrada de usuários para remover qualquer código JavaScript ou HTML que possa ser usado para realizar um ataque cibernético.&lt;/p&gt;

&lt;p&gt;O DDD (Domain Driven Design) também desempenha um papel importante na proteção das fronteiras de software. O DDD é uma abordagem de design de software que se concentra no domínio empresarial e enfatiza a importância de criar uma separação clara entre a lógica do domínio e os detalhes técnicos da implementação. Isso pode ajudar a garantir que as interfaces externas do software sejam bem definidas e fáceis de entender, o que pode tornar mais fácil validar e sanitizar entradas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serializar classes de domínio → não fazer
&lt;/h3&gt;

&lt;p&gt;Ao expor os objetos do domínio através de uma API, serializá-los e enviá-los diretamente para o cliente como uma resposta, pode levar a uma série de problemas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O cliente pode potencialmente modificar o estado do objeto do domínio e violar as regras do domínio.&lt;/li&gt;
&lt;li&gt;O objeto do domínio pode conter informações sensíveis que não devem ser expostas ao cliente.&lt;/li&gt;
&lt;li&gt;O objeto do domínio pode conter informações que não são relevantes para o cliente e podem levar à coleta excessiva de dados.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para evitar esses problemas, é recomendado criar um DTO (Objeto de Transferência de Dados) separado que é especificamente projetado para a API, ele deve conter apenas as informações que o cliente precisa e não deve conter nenhum comportamento ou métodos que possam mudar o estado do objeto do domínio. Isso ajudará a proteger a integridade do modelo de domínio e manter o cliente desacoplado dos detalhes de implementação interna dos objetos do domínio.&lt;/p&gt;




&lt;p&gt;Princípio: &lt;strong&gt;Favorecemos coesão através do encapsulamento&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  O Básico
&lt;/h2&gt;

&lt;p&gt;O Encapsulamento é basicamente o ato de juntar comportamentos e estados que fazem sentido no mesmo lugar, garantindo maior coesão ao código, é um conceito básico que precisa ser dominado. Veja esse código em um repositório de um framework da Apache&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;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Address&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vcard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAddresses&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;workAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AddressType&lt;/span&gt; &lt;span class="n"&gt;addressType&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTypes&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AddressType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PREF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addressType&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nc"&gt;AddressType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WORK&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addressType&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                            &lt;span class="n"&gt;workAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                            &lt;span class="k"&gt;break&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;workAddress&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sem entender muito do código e de seu contexto, já somos capaz de refatorar isso de uma maneira melhor, poderíamos simplesmente usar:&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;adress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasWorkAdress&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, o código escrito na classe ficaria mais legível e a função de descobrir se há endereço de trabalho ou não, passa a ser da classe &lt;code&gt;Adress&lt;/code&gt; e pode ser replicado sem problemas através de toda a aplicação. Se decidirmos mudar a regra de negócio no estado atual, teríamos que verificar por esse imenso código esparramado por todo o programa, o que não acontece no código refatorado.&lt;/p&gt;

&lt;p&gt;Apenas com essa alteração:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O service fica mais legível&lt;/li&gt;
&lt;li&gt;O service fica mais testável&lt;/li&gt;
&lt;li&gt;O código é reaproveitado e muda junto com apenas um ponto de contato (dentro da classe Adres)&lt;/li&gt;
&lt;li&gt;O service tem maior complexidade

&lt;ul&gt;
&lt;li&gt;A complexidade não surge, ela é distribuída, a regra já existe.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Como podemos detectar isso? Um forte indicativo que algo está estranho é estarmos usando um estado interno e aplicando lógica em cima desse estado interno fora de sua classe.&lt;/p&gt;

&lt;p&gt;Métodos privados também podem indicar esse tipo de comportamento, talvez até mesmo a necessidade do nascimento de novas entidades.&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;private&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;createUserAccount&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;username&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GrantedAuthority&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;authorities&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nc"&gt;PersonAttributesLookup&lt;/span&gt; &lt;span class="n"&gt;personAttributesLookup&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasAccountCreationPermission&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorities&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Get the Person Attributes to create the person&lt;/span&gt;
                &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PersonAttributesResult&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                        &lt;span class="n"&gt;personAttributesLookup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookupPersonAttributes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSchoolId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSchoolId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setFirstName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFirstName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLastName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLastName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrimaryEmailAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPrimaryEmailAddress&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

                &lt;span class="n"&gt;ensureRequiredFieldsForDirectoryPerson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;externalPersonService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updatePersonFromExternalPerson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Successfully Created Account for {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ObjectNotFoundException&lt;/span&gt; &lt;span class="n"&gt;onfe&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;Refatorando:&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;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSchoolId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSchoolId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setFirstName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFirstName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLastName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLastName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrimaryEmailAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPrimaryEmailAddress&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// passa a se tornar&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;setAttributesBasedOnAttributesResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PersonAttributesResult&lt;/span&gt; &lt;span class="n"&gt;attr&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;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSchoolId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSchoolId&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;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setFirstName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFirstName&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;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLastName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLastName&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;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPrimaryEmailAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPrimaryEmailAddress&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// seria usado:&lt;/span&gt;
&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAttributesBasedOnAttributesResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Somente nessa alteração, já travamos setters que podem não ser interessantes para o negócio (como alterar o schoolId sem alterar o emailAdress, se isso for uma regra existente), ou seja, o código antigo estava desprotegido e acoplado mentalmente à alguma regra externa, precisamos sempre que atualizarmos o primeiro nome atualizar também o segundo? não sei. Se sim, podemos fazer com que o encapsulamento garanta isso.&lt;/p&gt;

&lt;p&gt;Outro ponto de refatoramento em Person é essa parte:&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;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Talvez os métodos de setEnabled e setUsername sejam necessários, ou seja, não faz sentido criarmos um usuário sem Username e desabilitado, por que isso não faz parte do construtor? Esses setters provavelmente nem deveriam existir, com os atributos setados no próprio construtor. Tratamos isso no capítulo de refatoração &lt;/p&gt;

&lt;p&gt;O código final poderia ficar:&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;private&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;createUserAccount&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;username&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GrantedAuthority&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;authorities&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nc"&gt;PersonAttributesLookup&lt;/span&gt; &lt;span class="n"&gt;personAttributesLookup&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasAccountCreationPermission&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorities&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Get the Person Attributes to create the person&lt;/span&gt;
                &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PersonAttributesResult&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                        &lt;span class="n"&gt;personAttributesLookup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookupPersonAttributes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAttributesBasedOnAttributesResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;ensureRequiredFieldsForDirectoryPerson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;externalPersonService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updatePersonFromExternalPerson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="no"&gt;LOGGER&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Successfully Created Account for {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ObjectNotFoundException&lt;/span&gt; &lt;span class="n"&gt;onfe&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;h2&gt;
  
  
  Disclaimer!
&lt;/h2&gt;

&lt;p&gt;Não leve tudo que leu aqui como verdades absolutas ou regras a serem seguida em 100% dos casos, não existe martelo de ouro nem bala de prata. Se houver algum questionamento ou sugestão, pode deixar aqui!&lt;/p&gt;

&lt;h1&gt;
  
  
  Referências:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=2Bso1Yg3xUA" rel="noopener noreferrer"&gt;Encapsulamento para ganhar mais coesão: O feijão com arroz que precisa estar dominado&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OOP E Solid para ninjas - Casa do código - Aniche &lt;/p&gt;

&lt;p&gt;Desbravando SOLID - Casa do Código - Aquiles&lt;/p&gt;

</description>
      <category>backend</category>
      <category>java</category>
      <category>csharp</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Features e Refactors Seguros com Java e SPRING: 2 dicas simples</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Wed, 25 Oct 2023 21:33:05 +0000</pubDate>
      <link>https://dev.to/kauegatto/features-e-refactors-seguros-com-java-e-spring-2-dicas-4jc4</link>
      <guid>https://dev.to/kauegatto/features-e-refactors-seguros-com-java-e-spring-2-dicas-4jc4</guid>
      <description>&lt;h1&gt;
  
  
  Contexto
&lt;/h1&gt;

&lt;p&gt;Quando trabalhando em sistemas reais, temos que nos preocupar com a segurança de nosso código, pontos específicos de nosso código podem ser mais suscetíveis a falhas, mudanças de uma camada de baixo nível (infraestrutura) podem acarretar em problemas caso haja grandes alterações ou até mesmo uma mudança de vendor. Nesse breve artigo irei discutir duas atividades bem frequentes na minha rotina no Bees/AmBev &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Features Toggle
&lt;/h2&gt;

&lt;p&gt;Em diversos momentos, faz sentido que uma feature seja facilmente desligada ou não usando um toggle, fazendo com que essa alteração não precise de um deploy, dando mais agilidade e segurança à sua alteração.&lt;br&gt;
Para isso temos algumas opções, podemos usar variáveis de ambientes ou até mesmo guardar o valor no banco de dados.&lt;br&gt;
Uma maneira fácil de implementar em Spring é simplesmente puxar os dados de seu&lt;code&gt;application.properties&lt;/code&gt; ou &lt;code&gt;application.yaml&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  No Spring
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Opção 1: @Value
&lt;/h4&gt;

&lt;p&gt;Essa opção é particularmente útil para configurações mais simples, que possuem apenas um campo (ex: Enabled) e não são usadas em diversos lugares.&lt;br&gt;
Yaml:&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;features&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;algumaFeature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;outraFeature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spring:&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;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${features.algumaFeature.enabled}"&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;Boolean&lt;/span&gt; &lt;span class="n"&gt;valueFromFile&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Opção 2: @ConfigurationProperties
&lt;/h4&gt;

&lt;p&gt;Melhor para cenários mais complexos, ou quando a propriedade é usada em diversos lugares.&lt;br&gt;
Yaml:&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;broker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;queues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ticket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default.ticket&lt;/span&gt;
    &lt;span class="na"&gt;exchanges&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ticket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;direct.ticket&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;direct&lt;/span&gt;
    &lt;span class="na"&gt;bindings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ticket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;direct.ticket&lt;/span&gt;
            &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default.ticket&lt;/span&gt;
            &lt;span class="na"&gt;routingKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default.ticke&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spring:&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;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"broker"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BrokerConfigurationProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;QueueProperties&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;queues&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExchangeProperties&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exchanges&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BindingProperties&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bindings&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Data&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueueProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Data&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExchangeProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Data&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BindingProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotEmpty&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;routingKey&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;Aqui basta você fazer o mapeamento das classes de acordo com suas propriedades. Se houver dificuldade, é uma tarefa em que alguma AI provavelmente vai lidar com facilidade.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Diferentes Beans de Infraestrutura! Permita um rollback fácil
&lt;/h2&gt;

&lt;p&gt;Em um código ideal, a sua camada de domínio provavelmente estará desacoplada de sua camada de infraestrutura por meio de interfaces. Se isso não faz sentido para você, recomendo meu post de SOLID :)&lt;br&gt;
Continuando, com um código com módulos de alto e baixo nível desacoplados, conseguimos mudar a infraestrutura sem mexer no domínio. Isso nos dá a liberdade de gerenciar os beans que sua classe de domínio irá usar com mais facilidade, pois todas as implementações de infraestrutura irão respeitar a 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="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketService&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;TicketRepository&lt;/span&gt; &lt;span class="n"&gt;repository&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;Notifier&lt;/span&gt; &lt;span class="n"&gt;messagePublisher&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Ticket&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Ticket&lt;/span&gt; &lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nc"&gt;Id&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;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Id&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;()&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;TicketNotFoundException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ticket not found"&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;Ticket&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Ticket&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;messagePublisher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Notify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TicketEventsEnum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TICKET_CREATED&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;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&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;Temos aqui um Simples Service, tendo suas dependências injetadas via construtor pelo SPRING. Note que nosso serviço conhece regras de negócio, dentre elas, quando um ticket é criado, ele tem que notificar algo, e tem que guardar em algum lugar (repository pode cuidar de mongoDB, MySQL, et cetera.)&lt;br&gt;
Note que se tivermos um repositório com código específico do MySQL e quisermos migrar para um código com Spring Data JPA, teremos que mudar a camada de infraestrutura (resumidamente, vamos escrever mais código de Repositório), mas nossa regra de negócio é a mesma.&lt;br&gt;
Imagine agora que essa camada é um ponto crítico da sua aplicação, caso a implementação que você fez com tanta boa vontade dê errado, você terá que fazer um rollback.&lt;/p&gt;
&lt;h3&gt;
  
  
  Definindo os Beans Manualmente
&lt;/h3&gt;

&lt;p&gt;Ao invés de definir os repositórios com &lt;code&gt;@Component&lt;/code&gt;, como teremos dois repositórios, o Spring não saberá com qual Bean lidar. &lt;br&gt;
Temos diversas maneiras de fazer a desambiguação de Beans, dentre elas, prioridades, primary, qualifier, aqui vou para uma abordagem simples, apenas para exemplificar a feature.&lt;br&gt;
No meu yaml, irei definir uma propriedade:&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;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DEFINED_REPOSITORY:mysql}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso exista uma variável de ambiente chamada DEFINED_REPOSITORY, ela será o padrão para o tipo do meu repositório, caso contrário, será mysql, como um fallback. (No caso, escolhi deixar o MySQL como fallback pois teoricamente ele é o repositório testado e já em produção).&lt;br&gt;
Perfeito, agora vamos definir qual bean utilizar:&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;@Configuration&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;RepositoryConfiguration&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${repository.type}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;repositoryType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Bean&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;TicketRepository&lt;/span&gt; &lt;span class="nf"&gt;ticketRepository&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="s"&gt;"mysql"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repositoryType&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;MySQLTicketRepository&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalsIgnoreCase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repositoryType&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;JpaTicketRepository&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;MySQLTicketRepository&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// fallback&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;Outra maneira de fazer esse tipo de configuração é usar profiles do Spring.&lt;/p&gt;

&lt;h1&gt;
  
  
  Obrigado!
&lt;/h1&gt;

&lt;p&gt;Obrigado, espero que o breve artigo tenha sido útil. Escrevi em 20 minutos e não o revisei, então se houver algum problema, pode me avisar :)&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>springboot</category>
      <category>spring</category>
      <category>java</category>
    </item>
    <item>
      <title>SOLID! Um post aprofundado</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Thu, 28 Sep 2023 23:59:57 +0000</pubDate>
      <link>https://dev.to/kauegatto/solid-um-guia-diferente-162m</link>
      <guid>https://dev.to/kauegatto/solid-um-guia-diferente-162m</guid>
      <description>&lt;p&gt;&lt;a href="https://www.notion.so/kauegatto/2-SOLID-2803807def464f3e884a1311ead6955c?pvs=4" rel="noopener noreferrer"&gt;Leitura no Notion: SOLID&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Sei que existem 1 milhão de posts sobre SOLID, considero esse "guia" um pouco fora do comum pelo seu aprofundamento, tentei esclarecer todas as dúvidas que tinha ou poderia ter e sempre trazer exemplos, além de usar boas referências. Espero que esse post seja o seu guia definitivo de SOLID, assim como é para mim!&lt;/p&gt;

&lt;h1&gt;
  
  
  O que é SOLID?
&lt;/h1&gt;

&lt;p&gt;SOLID é um Acrônimo para 5 boas práticas e/ou princípios que envolvem o desenvolvimento de um bom código orientado à objetos, não quero me estender na origem, vamos para os princípios!&lt;/p&gt;

&lt;h1&gt;
  
  
  Single Responsability Principle
&lt;/h1&gt;

&lt;p&gt;O nome, embora auto-explicativo e que muitas vezes levava esse princípio a ser explicado como &lt;em&gt;“Uma classe deve ter uma, e apenas uma responsabilidade”&lt;/em&gt;  não é necessariamente o que você deve pensar na hora de implementá-lo. Entenda esse padrão como : &lt;strong&gt;&lt;em&gt;“Uma classe deve ter um, e apenas um motivo para mudar”&lt;/em&gt;&lt;/strong&gt;. Ou seja, não crie uma classe com a função de Emitir Nota Fiscal, crie uma classe NotaFiscal, e garanta que apenas coisas que envolvem o domínio de Nota Fiscal irão altera-lá, a mudança da emissão não muda o seu domínio de Nota Fiscal. Se uma alteração na impressora fizer a classe Nota Fiscal ser alterada, algo está incorreto. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A questão principal do SRP é o motivo para uma classe ser modificada. E esse motivo para mudança, em geral, está relacionado a um grupo de usuários ou stakeholders, que Uncle&lt;br&gt;
Bob chama de atores. - Desbravando Solid&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Levando em conta o que dizemos acima, também podemos dizer que o SRP pode ser definido por: &lt;em&gt;“Um módulo deve ser responsável por um , e apenas um ator”.&lt;/em&gt;  O ator que se importa com a função da emissão nota fiscal é o setor de vendas, o ator que se importa com suas horas extras, o rh, o ator que se importa com salvar no banco por id é a implementação de persistência. &lt;/p&gt;

&lt;p&gt;Cada "interessado", de negócio ou técnico, faz com que a classe tenha uma responsabilidade diferente.&lt;/p&gt;

&lt;p&gt;Identificar classes que mudam por diversos motivos (ou atores) é simples, a coesão pode ser uma das métricas utilizadas:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Classes coesas têm uma característica semelhante: os conceitos que essas classes representam estariam relacionados e separá-los seria pouco natural. O SRP, no fim das contas, é uma outra maneira de falar sobre a necessidade de código coeso. - Desbravando Solid&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aniche (OOP E SOLID para ninjas) sugere que, para encontrar classes pouco coesas, devemos procurar classes que: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Possuem muitos métodos diferentes.&lt;/li&gt;
&lt;li&gt;São modificadas com frequência.&lt;/li&gt;
&lt;li&gt;Não param nunca de crescer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Outro fator importante é perceber a duplicação (ou pior, repetição) de código. Se seu código possui partes repetidas diversas vezes, tenha isso como um forte indicativo que essa responsabilidade provavelmente deveria estar encapsulada em algum lugar (e muito provavelmente em uma classe).&lt;/p&gt;

&lt;p&gt;Portanto, se seu sistema pega os dados, busca coisas no banco, salva como ePUB ou PDF, tudo em uma classe só, ele provavelmente não é coeso e muito menos segue o SRP. Um exemplo disso é que toda vez que a maneira que um pdf for gerado houver de mudar, você terá que mexer nessa classe principal, e se você tiver que repetir essa alteração em diversos pontos onde o código está repetido (o que já não é um bom indicador), você provavelmente terá problemas em algum momento (e mesmo que não tenha, sua manutenção definitivamente não está facilitada).&lt;/p&gt;

&lt;h2&gt;
  
  
  Caso real
&lt;/h2&gt;

&lt;p&gt;Recentemente ajudei um amigo em um projeto pessoal, onde ele enviava emails para a confirmação de cadastro de usuários, todas essas responsabilidades ficavam dentro da mesma classe Usuário (Gerar token, enviar email, registrar usuário).&lt;br&gt;
A partir daí, trabalhamos para termos um código mais coeso, no momento em que um usuário é registrado, ele envia um &lt;strong&gt;evento&lt;/strong&gt; de registro de usuário (o que é só um aviso falando: cadastrei um usuário).&lt;br&gt;
Com isso, uma classe chamada enviarEmailListener se prontificava a ouvir eventos de registro e alteração de senha de usuário e ela era a responsável por enviar emails.&lt;br&gt;
Portanto, com o refactor, a classe de Usuário não se preocupa com o que acontece após o registro do usuário, ela apenas notifica que isso aconteceu.&lt;br&gt;
Outro ponto de melhoria nisso foi a possibilidade de tornar o envio do email assíncrono, então para cadastrar um usuário, não precisavamos esperar o serviço de email fazer sua ação, ela é independente (nesse caso, não fazia sentido ser uma transação, o cadastro de um usuário não depende do email, se um erro ocorrer nessa etapa, ele pode só pedir outro email)&lt;/p&gt;

&lt;p&gt;Note que se tivermos mais ocasiões onde devemos enviar emails de usuário (além de cadastro e alteração de emails) podemos apenas adicionar um novo evento a ser ouvido pelo listener e se precisarmos mudar a forma de enviar email, mudamos apenas em um único método (o que aumenta MUITO a capacidade de manter o código), essa é a função do SRP.&lt;/p&gt;
&lt;h1&gt;
  
  
  Open-Closed Principle
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Software entities ... should be open for extension, but closed for modification.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essas citações trazem uma noção base do que o OCP quer dizer, nosso código deve estar sempre pronto para evoluir. e de maneira natural, não devemos sentir a necessidade de modificar muitos arquivos diferentes, ou mesmo procurar (usando o CTRL+F, por exemplo) os lugares que devem ser alterados.&lt;/p&gt;

&lt;p&gt;A segunda parte diz sobre ser fechada para modificação. nesse aspecto, podemos entender que elas não devem ter seu comportamento alterado a todo momento.&lt;/p&gt;
&lt;h2&gt;
  
  
  Um exemplo
&lt;/h2&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;CalculadoraDePrecos&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;calcula&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Compra&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Frete&lt;/span&gt; &lt;span class="n"&gt;correios&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;Frete&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;desconto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Inicialize desconto com um valor padrão&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REGRA&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// faz algo            &lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;REGRA&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// faz algo            &lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValor&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="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;desconto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;frete&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;Note que sempre que adicionarmos regras de frete, nosso código precisará alterar a classe calculadora de preços, incluindo um novo IF, ou seja, a classe que implementar a regra de frete está acoplada à Calculadora de Preços&lt;/p&gt;

&lt;p&gt;Uma segunda implementação comum é colocar os ifs dentro das classes&lt;br&gt;
específicas. Por exemplo, a classe Frete passaria a ter as diferentes regras de negócio (os mesmos if-else). Apesar de ficar melhor, continua claro que não é a melhor abordagem.&lt;/p&gt;
&lt;h3&gt;
  
  
  Melhorando
&lt;/h3&gt;

&lt;p&gt;Se temos diferentes regras de desconto e de frete, basta criarmos interfaces que as representam:&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;TabelaDePreco&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;descontoPara&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;valor&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;TabelaDePreco1&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;TabelaDePreco&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;TabelaDePreco2&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;TabelaDePreco&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;TabelaDePreco3&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;TabelaDePreco&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;ServicoDeEntrega&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;para&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cidade&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="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;Frete1&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ServicoDeEntrega&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;Frete2&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ServicoDeEntrega&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;Frete3&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ServicoDeEntrega&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Veja que essa simples mudança altera toda a maneira de se lidar com a classe. Com ela 'aberta', ou seja, recebendo as dependências pelo construtor, podemos passar a implementação concreta que quisermos para ela. Se passarmos a implementação TabelaDePreco1, e invocarmos o método &lt;code&gt;calcula()&lt;/code&gt;, o resultado será um; se passarmos a implementação TabelaDePreco2 e invocarmos o mesmo método, o resultado será outro." (ANICHE, 2015).&lt;/strong&gt;&lt;/p&gt;


&lt;/blockquote&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;CalculadoraDePrecos&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;TabelaDePreco&lt;/span&gt; &lt;span class="n"&gt;tabela&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;ServicoDeEntrega&lt;/span&gt; &lt;span class="n"&gt;entrega&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;CalculadoraDePrecos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TabelaDePreco&lt;/span&gt; &lt;span class="n"&gt;tabela&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServicoDeEntrega&lt;/span&gt; &lt;span class="n"&gt;entrega&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;tabela&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tabela&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;entrega&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entrega&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;calcula&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Compra&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;desconto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tabela&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;descontoPara&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValor&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;frete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entrega&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;para&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCidade&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;produto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValor&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="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;desconto&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;frete&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;💡 Exemplo do Livro OOP e SOLID para Ninjas&lt;/p&gt;

&lt;p&gt;Note que aqui trabalhamos também com a inversão de dependências (DIP), o “D”, do SOLID.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Se o OCP declara o objetivo de   uma arquitetura OO, o DIP declara o seu mecanismo   fundamental."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se você ainda não leu sobre o DIP, continue lendo o post, mais tarde revisite esse ponto, vai fazer sentido 😃&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstrações e Capacidade de Extensão
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"O que discutimos aqui, de certa forma, mistura-se com a discussão do capítulo anterior sobre estabilidade e inversão de dependências. As interfaces (abstrações) &lt;code&gt;TabelaDePreco&lt;/code&gt; e &lt;code&gt;ServicoDeEntrega&lt;/code&gt; tendem a ser estáveis. A &lt;code&gt;CalculadoraDePrecos&lt;/code&gt; é uma implementação mais instável e que só depende de abstrações estáveis. Pensar em abstrações nos ajuda a resolver o problema do acoplamento e, de quebra, ainda nos ajuda a ter códigos facilmente extensíveis. Isso é programar orientado a objetos. É lidar com acoplamento, coesão, pensando em abstrações para nossos problemas. Quando se tem uma boa abstração, é fácil evoluir o sistema. Seu sistema deve evoluir por meio de novas implementações dessas abstrações, previamente pensadas, e não por meio de diversos ifs espalhados por todo o código." (ANICHE, 2015).&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Design Pattern: Command
&lt;/h2&gt;

&lt;p&gt;Não vou me aprofundar em patterns nesse post, mas acho legal repassar alguns exemplos que vi no material base&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;EmissorNotaFiscal&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;RegrasDeTributacao&lt;/span&gt;  &lt;span class="n"&gt;tributacao&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;LegislacaoFiscal&lt;/span&gt;    &lt;span class="n"&gt;legislacao&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AcaoPosEmissao&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;    &lt;span class="n"&gt;acoes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;//...&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt;  &lt;span class="nc"&gt;NotaFiscal&lt;/span&gt;  &lt;span class="nf"&gt;gera&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Fatura&lt;/span&gt; &lt;span class="n"&gt;fatura&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Imposto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="n"&gt;impostos&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt;   &lt;span class="n"&gt;tributacao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;verifica&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fatura&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;Isencao&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="n"&gt;isencoes&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt;   &lt;span class="n"&gt;legislacao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;analisa&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fatura&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;//  método auxiliar&lt;/span&gt;
                &lt;span class="nc"&gt;NotaFiscal&lt;/span&gt;  &lt;span class="n"&gt;nota&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt;   &lt;span class="n"&gt;aplica&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;impostos&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;isencoes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;//  modificado&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AcaoPosEmissao&lt;/span&gt; &lt;span class="nl"&gt;acao:&lt;/span&gt;   &lt;span class="n"&gt;acoes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;acao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;faz&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nota&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;nota&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;Exemplo do livro Desbravando Solid (AQUILES, 2022)&lt;/p&gt;

&lt;p&gt;Note que é muito fácil adicionar novos comportamentos depois de uma nota fiscal ser emitida, podemos simplesmente adicionar um objeto na lista de ações, isso caracteriza o padrão &lt;code&gt;Command&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Recomendo a leitura mais aprofundada em: &lt;a href="https://refactoring.guru/design-patterns/command" rel="noopener noreferrer"&gt;https://refactoring.guru/design-patterns/command&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Pattern: Strategy
&lt;/h2&gt;

&lt;p&gt;Exemplo de: &lt;a href="https://en.wikipedia.org/wiki/Strategy_pattern" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Strategy_pattern&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Strategy permite que o algoritmo varie independentemente dos clientes que o utilizam. Strategy é um dos padrões incluídos no influente livro "Design Patterns" de Gamma et al., que popularizou o conceito de usar padrões de design para descrever como projetar software orientado a objetos flexível e reutilizável. Adiar a decisão sobre qual algoritmo usar até o tempo de execução permite que o código chamador seja mais flexível e reutilizável."&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Strategy_pattern" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Strategy_pattern&lt;/a&gt;&lt;/p&gt;


&lt;/blockquote&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;IComportamentoDeFreio&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;frear&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;FreioComABS&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;IComportamentoDeFreio&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;frear&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;"Freio com ABS aplicado"&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;FreioSimples&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;IComportamentoDeFreio&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;frear&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;"Freio simples aplicado"&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="cm"&gt;/* Cliente que pode usar os algoritmos acima de forma intercambiável */&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Carro&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;IComportamentoDeFreio&lt;/span&gt; &lt;span class="n"&gt;comportamentoDeFreio&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;Carro&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IComportamentoDeFreio&lt;/span&gt; &lt;span class="n"&gt;comportamentoDeFreio&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;comportamentoDeFreio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;comportamentoDeFreio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;aplicarFreio&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;comportamentoDeFreio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;frear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// note que usamos a interface!&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setComportamentoDeFreio&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IComportamentoDeFreio&lt;/span&gt; &lt;span class="n"&gt;tipoDeFreio&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;comportamentoDeFreio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tipoDeFreio&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// podemos mudar livremente!&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;SUV&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Carro&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;SUV&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FreioComABS&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;CarExample&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="kd"&gt;final&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;arguments&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Carro&lt;/span&gt; &lt;span class="n"&gt;suvCar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;SUV&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;suvCar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;frear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// freio com abs&lt;/span&gt;

        &lt;span class="n"&gt;suvCar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBrakeBehavior&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;FreioSimples&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;suvCar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;frear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// freia, mas sem abs.&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;Nesse exemplo, note que definimos uma interface comum, a qual um carro se acopla, podemos trocar a implementação dessa interface livremente, também ajuda no OCP.&lt;/p&gt;

&lt;h1&gt;
  
  
  Liskov Substitution Principle
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Funções que utilizam ponteiros ou referências para classes base devem ser capazes de usar objetos de classes derivadas sem saber disso&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nesse caso, vamos começar com citações:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;"Se um gato possui raça e patas, e um cachorro possui raça, patas e tipoDoPelo, logo Cachorro extends Gato? Pode parecer engraçado, mas é (...) herança por preguiça, por comodismo, porque vai dar uma ajudinha. A relação “é um” não se encaixa aqui, e vai nos gerar problemas."&lt;br&gt;
Paulo Silveira, no artigo Como não aprender orientação a objetos: Herança (SILVEIRA, 2006)&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O Princípio da Substituição de Liskov (LSP) estabelece uma diretriz fundamental : Ele afirma que objetos de classes derivadas ou subclasses devem poder ser usados no lugar de objetos da classe base ou superclasse sem quebrar o comportamento esperado do programa. Em outras palavras, uma classe derivada deve estender ou especializar o comportamento da classe base sem modificar seu contrato.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;"A ideia intuitiva de um subtipo é aquela cujos objetos fornecem todo o comportamento de objetos de outro tipo (o supertipo) mais algo extra."&lt;br&gt;
Data Abstraction and Hierarchy (LISKOV, 1988)&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine um exemplo em que temos uma classe base chamada &lt;strong&gt;&lt;code&gt;Animal&lt;/code&gt;&lt;/strong&gt; e classes derivadas, como &lt;strong&gt;&lt;code&gt;Cachorro&lt;/code&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;code&gt;Gato&lt;/code&gt;&lt;/strong&gt;. O LSP nos orienta a garantir que qualquer código que funcione com objetos &lt;strong&gt;&lt;code&gt;Animal&lt;/code&gt;&lt;/strong&gt; também funcione corretamente com objetos &lt;strong&gt;&lt;code&gt;Cachorro&lt;/code&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;code&gt;Gato&lt;/code&gt;&lt;/strong&gt;. Isso significa que as subclasses não devem introduzir comportamentos que contradigam as expectativas estabelecidas pela classe base. Ou seja, se todo animal implementa o método comer, classes derivadas desse Animal devem também incluir o método comer, que funciona como esperado. (Se seu animal não come, reveja suas abstrações, o próximo princípio, ISP, pode ser útil aqui!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Favoreça composição sobre Herança
&lt;/h2&gt;

&lt;p&gt;Essa é uma frase amplamente falada no meio da computação, algo que você já ouviu milhares de vezes, seja em artigos, livros como o Design Patterns, do GoF ou até mesmo vídeos no youtube, mas por quê?&lt;/p&gt;

&lt;p&gt;Em vez de herdar comportamentos de uma classe base, prefira compor objetos que fornecem os comportamentos necessários. O princípio de design normalmente começa pela definição de interfaces que representam o comportamento que o sistema deve exibir, as classes recebem objetos dessas interfaces e fazem os comportamentos a partir daí&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefícios
&lt;/h3&gt;

&lt;p&gt;Favorecer a composição proporciona maior flexibilidade no design. É mais natural construir classes de domínio de negócios a partir de vários componentes do que tentar encontrar pontos em comum entre eles e criar uma árvore de herança. Por exemplo, um pedal de acelerador e um volante têm poucos traços em comum, mas são componentes vitais em um carro.&lt;/p&gt;

&lt;p&gt;Além disso, a composição oferece um domínio de negócios mais estável, pois está menos sujeito às peculiaridades dos membros da família. Em outras palavras, é melhor compor o que um objeto pode fazer (&lt;strong&gt;&lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Has-a" rel="noopener noreferrer"&gt;tem-um&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;) do que estender o que ele é (&lt;strong&gt;&lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Is-a" rel="noopener noreferrer"&gt;é-um&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;💡 Linguagens como Go e Rust não possuem mecanismos de herança, e focam exclusivamente na composição de tipos a fim de evitar problemas com herança.&lt;/p&gt;

&lt;h3&gt;
  
  
  Drawbacks
&lt;/h3&gt;

&lt;p&gt;“Composition is good until it is not” - O uso excessivo de composição pode levar a classes superlotadas e complexas, mas de maneira geral, se você mantiver : A divisão de responsabilidades, O acoplamento controlado, Uso de Design Patterns adequados, isso provavelmente não será um problema.&lt;/p&gt;

&lt;h1&gt;
  
  
  Interface Segregation Principle
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod" rel="noopener noreferrer"&gt;“*Make fine grained interfaces that are client specific.”&lt;/a&gt;&lt;br&gt;
&lt;a href="https://web.archive.org/web/20150906155800/http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf" rel="noopener noreferrer"&gt;”Clients should not be forced to depend upon interfaces that they do not use”&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uncle Bob*&lt;/p&gt;

&lt;blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;O Interface Segregation Principle (ISP) basicamente nos orienta a escrever interfaces coesas, em que seus métodos conversem entre si e sempre sejam implementados.&lt;/p&gt;

&lt;p&gt;Vamos a um exemplo:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;Imposto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;NotaFiscal&lt;/span&gt; &lt;span class="nf"&gt;geraNota&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;imposto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;valorCheio&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;Imagine que em algum momento da existência da sua aplicação, um imposto não gere nota fiscal, nesse caso, ele irá jogar uma exception? retornar nulo? É exatamente esse tipo de situação que o ISP quer que você evite passar, pois &lt;strong&gt;ambas as opções anteriores são ruins e configuram quebra de contrato.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nesse caso anterior, temos uma interface não muito coesa, com dois comportamentos distintos (isso se dá pois um imposto nem sempre gera nota), nesse caso, o mais adequado seria dividi-la em duas interfaces distintas, como por exemplo:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;Tributavel&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;imposto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;valorCheio&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;GeradorNF&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;NotaFiscal&lt;/span&gt; &lt;span class="nf"&gt;geraNota&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;Com isso, podemos fazer com que nossas classes sejam construídas por composição de interfaces que às sirvam perfeitamente, como:&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;ImpostoGeraNota&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Tributavel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;GeradorNF&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// os dois métodos aqui&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;Imposto&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Tributavel&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//  implementa imposto(double valorCheio)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://web.archive.org/web/20150906155800/http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf" rel="noopener noreferrer"&gt;Many client specific interfaces are better than one general purpose interface&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Uncle Bob&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;Além disso, muitas vezes queremos apenas parte dos atributos ou comportamentos de uma classe, e&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Se você tiver uma classe que tenha vários clientes, em vez de carregar a classe com todos os métodos de que os clientes precisam, crie interfaces específicas para cada cliente e implemente-as na classe.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.cvc.uab.es/shared/teach/a21291/temes/object_oriented_design/materials_adicionals/principles_and_patterns.pdf" rel="noopener noreferrer"&gt;Design Principles and Design Patterns&lt;/a&gt; (MARTIN, 2000) &lt;/p&gt;

&lt;p&gt;Citação retirada da Referência da Caelum&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Por que?
&lt;/h2&gt;

&lt;p&gt;Mas Kauê, por quê é uma boa prática criarmos interfaces magras? Como disse anteriormente, a palavra chave é &lt;strong&gt;coesão&lt;/strong&gt;, a coesão é o elemento chave que garante a estabilidade de nossas interfaces, e se essa interface realmente precisar ser mudada, apenas os membros que implementam ela terão sua implementação alterada. No final das contas, o ISP é sobre avaliarmos a coesão das nossas interfaces,&lt;/p&gt;

&lt;p&gt;Lembre-se também que devemos sempre nos acoplar a membros os mais estáveis possíveis! Nesse caso, tanto &lt;code&gt;Tributavel&lt;/code&gt; quanto &lt;code&gt;GeradorNF&lt;/code&gt; são mais interfaces coesas e estáveis.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Classes que dependem de interfaces leves sofrem menos com mudanças em outros pontos do sistema. Novamente, elas são pequenas, portanto, têm poucas razões para mudar.” - Aniche, M. OOP E SOLID para Ninjas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Dependency Inversion Principle
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Depend upon Abstractions. Do not depend upon concretions. - Design Principles and Design Patterns, Bob Martin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aqui, vamos começar com conceitos bem fundamentados dentro da computação&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Depender de abstrações e não de implementações” - Bob Martin&lt;br&gt;
”Programe voltado à interface, não à implementação” - Design Patterns, GoF&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mas o que isso significa? A ideia aqui é que abstrações e interfaces definem contratos estáveis para nossos sistemas, classes e comportamentos base do sistema, ou seja, não-voláteis, não devem ser impactados por implementação de módulos as quais elas dependem.&lt;/p&gt;

&lt;p&gt;Sua classe que cuida do registro do usuário não deve depender da implementação que o envio de email possui, você não deve ter imports de uma biblioteca específica dentro de uma classe que cuida de regras de negócio. Nesse caso, você deverá usar abstração, por exemplo, &lt;code&gt;EnviadorEmail&lt;/code&gt; e usará algum método dela que encapsule detalhes de implementação&lt;/p&gt;

&lt;p&gt;Vamos ver um exemplo bom:&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;EnviadorEmail&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;enviarEmail&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;destinatario&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// em seu próprio arquivo:&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;RegistrarUsuario&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;EnviadorEmail&lt;/span&gt; &lt;span class="n"&gt;enviadorEmail&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;RegistrarUsuario&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EnviadorEmail&lt;/span&gt; &lt;span class="n"&gt;enviadorEmail&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;enviadorEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enviadorEmail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;registrarUsuario&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Lógica para registrar o usuário&lt;/span&gt;

        &lt;span class="c1"&gt;// Envio de e-mail de boas-vindas&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bem-vindo, "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"!"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;enviadorEmail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enviarEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código acima, podemos mudar a implementação do provedor de email e não precisaremos mexer na classe RegistrarUsuário, perfeito!&lt;/p&gt;

&lt;p&gt;💡 Nesse caso em específico, gosto da abordagem de eventos, onde o enviador de email que diz estar ouvindo eventos de cadastro, mudança de senha e/ou emissão de nota fiscal. Mas é apenas uma ressalva :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Um pouco mais concreto:
&lt;/h2&gt;

&lt;p&gt;Vamos dar algumas definições que podem ajudar a você seguir como guideline para garantir que seu código está desacoplado&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Módulos de Alto Nível: São módulos que implementam regras de negócio, devem ser reutilizáveis, estáveis e inafetados por mudanças em módulos de baixo nível.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Módulos de Baixo Nível: São módulos que dizem respeito à detalhes de implementação, muitas vezes, agem como utilitários para módulos de alto nível, mas devem ser utilizados através de uma barreira de abstração sempre que fizer sentido&lt;/p&gt;

&lt;blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;💡 Nem toda abstração é necessária, nem todo acoplamento é ruim. Não faz sentido abstrairmos classes estáveis da linguagem que estamos utilizando, como por exemplo, a classe &lt;code&gt;String&lt;/code&gt; em Java.&lt;/p&gt;

&lt;p&gt;Portanto, nossa “”regra”” é:  &lt;/p&gt;




&lt;p&gt;Módulos de Alto nível não devem depender explicitamente de módulos de baixo nível, e sim de abstrações.&lt;/p&gt;




&lt;h3&gt;
  
  
  E de onde vem o nome de “Inversão de Dependência”?
&lt;/h3&gt;

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

&lt;p&gt;No exemplo acima é claro, &lt;code&gt;RegistrarUsuário&lt;/code&gt;, uma classe de alto nível, depende do Enviador de Email, que utiliza a dependência do AWS SES, no final das contas, &lt;code&gt;RegistrarUsuário&lt;/code&gt; também está acoplado ao SES.&lt;/p&gt;

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

&lt;p&gt;Nesse caso, note que as dependências foram invertidas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nem toda interface é de alto nível
&lt;/h2&gt;

&lt;p&gt;A linguagem Java está cheia de interfaces e abstrações, mas muitas vezes essas abstrações atuam diretamente sobre detalhes de implementação, como &lt;code&gt;java.sql.Connection&lt;/code&gt; do JDBC, elas são interfaces para mecanismos de entrega, detalhes técnicos e uma classe que depende delas, não necessariamente segue o dip, mas isso não é um problema, pois essas interfaces são &lt;strong&gt;estáveis&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dicas gerais
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Não precisamos implementar e criar uma dependência diretamente com a classe EnviadorEmailX ou EnviadorEmailY, nesse caso, podemos usar o design pattern &lt;code&gt;Factory&lt;/code&gt; e abstrair essa dependência, podemos fazer isso dentro da própria interface com java.
&lt;/li&gt;
&lt;/ol&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;EnviadorEmail&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;enviarEmail&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;destinatario&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;EnviadorEmail&lt;/span&gt; &lt;span class="nf"&gt;criarEnviadorEmailPadrao&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;EnviadorEmailPadrao&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;EnviadorEmail&lt;/span&gt; &lt;span class="nf"&gt;criarEnviadorEmailAlternativo&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;EnviadorEmailAlternativo&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Em outra classe&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;Main&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;EnviadorEmail&lt;/span&gt; &lt;span class="n"&gt;enviadorPadrao&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EnviadorEmail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;criarEnviadorEmailPadrao&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;EnviadorEmail&lt;/span&gt; &lt;span class="n"&gt;enviadorAlternativo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EnviadorEmail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;criarEnviadorEmailAlternativo&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Use as instâncias de EnviadorEmail conforme necessário&lt;/span&gt;
        &lt;span class="n"&gt;enviadorPadrao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enviarEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"destinatario@example.com"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Mensagem de teste"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;enviadorAlternativo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enviarEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"outrodestinatario@example.com"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Outra mensagem de teste"&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;ol&gt;
&lt;li&gt;Em java, se definirmos interfaces comuns para diversos provedores de notificação como &lt;code&gt;enviadorMensagem&lt;/code&gt;, que ser para tanto enviadorEmail quanto enviadorSMS, podemos fazer com que o spring nos entregue uma lista com todos os Beans anotados com &lt;code&gt;@Component&lt;/code&gt; que satisfaça essa interface (Podemos usar o applicationContext para isso), simplificando o código iterando pela lista e usando o seu método de enviar.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EnviadorEmail&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;EnviadorMensagem&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;enviarMensagem&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;destinatario&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// abstraido :p&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EnviadorSMS&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;EnviadorMensagem&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// você já sabe&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Importante!!
&lt;/h1&gt;

&lt;p&gt;Obrigado pela leitura, espero que tenha sido útil, de verdade, tentei trazer exemplos de código e bastante citações, mas a maioria desse tipo de conteúdo é fonte dos livros da casa do código e caelum, mas de maneira mais enxuta e com minhas palavras, recomendo fortemente a compra dos dois livros abaixo.&lt;/p&gt;

&lt;p&gt;Se encontrar erros ortográficos ou algo estranho, me envie uma mensagem ou comente aqui, arrumarei assim que possível. Não farei uma rigorosa verificação antes de postar aqui.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://www.amazon.com.br/Design-Patterns-Object-Oriented-Addison-Wesley-Professional-ebook/dp/B000SEIBB8" rel="noopener noreferrer"&gt;https://www.amazon.com.br/Design-Patterns-Object-Oriented-Addison-Wesley-Professional-ebook/dp/B000SEIBB8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Composition_over_inheritance#:~:text=To%20favor%20composition%20over%20inheritance,and%20creating%20a%20family%20tree" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Composition_over_inheritance&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.casadocodigo.com.br/products/livro-oo-solid" rel="noopener noreferrer"&gt;https://www.casadocodigo.com.br/products/livro-oo-solid&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.casadocodigo.com.br/products/livro-desbravando-solid" rel="noopener noreferrer"&gt;https://www.casadocodigo.com.br/products/livro-desbravando-solid&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/caelum/apostila-oo-avancado-em-java/blob/master/09-interface-segregation-principle.md" rel="noopener noreferrer"&gt;https://github.com/caelum/apostila-oo-avancado-em-java/blob/master/09-interface-segregation-principle.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Strategy_pattern" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Strategy_pattern&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://refactoring.guru/design-patterns/command" rel="noopener noreferrer"&gt;https://refactoring.guru/design-patterns/command&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidprinciples</category>
      <category>java</category>
      <category>braziliandevs</category>
      <category>oop</category>
    </item>
    <item>
      <title>Streams em JAVA: Tudo que você precisa saber</title>
      <dc:creator>Kauê Gatto</dc:creator>
      <pubDate>Tue, 05 Sep 2023 22:54:17 +0000</pubDate>
      <link>https://dev.to/kauegatto/streams-em-java-tudo-que-voce-precisa-saber-5f4b</link>
      <guid>https://dev.to/kauegatto/streams-em-java-tudo-que-voce-precisa-saber-5f4b</guid>
      <description>&lt;h2&gt;
  
  
  Map, Filter, Reduce
&lt;/h2&gt;

&lt;p&gt;Vamos começar com um exemplo?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Given&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;We&lt;/span&gt; &lt;span class="n"&gt;need&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;compute&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;those&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;For&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="n"&gt;older&lt;/span&gt; &lt;span class="n"&gt;than&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;


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

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Nesse caso, é meio claro, começamos com um objeto pessoa, mas trabalharemos / transformaremos o dado de uma maneira que consigamos a idade (&lt;strong&gt;map&lt;/strong&gt;). O map pega um objeto, e mapeia para outro, geralmente de tipo diferente&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq8t11tcox29jfu7dcw0x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq8t11tcox29jfu7dcw0x.png" alt="Map, um objeto entra, é transformado (seta) e sai outro"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Com isso, vamos filtrar o dado age, para que ele só compute a média de maiores de 20 anos. Isso é um &lt;strong&gt;filter.&lt;/strong&gt; O filter literalmente filtra os dados, não os transforma (diferente de map) e decide se deve manter ou não o dado.
2.1. Filters em código recebem uma predicate como parâmetro, ela representa uma função que recebe um argumento e retorna um valor booleano.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycioms5b7brys8h07bz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycioms5b7brys8h07bz1.png" alt="Filter, entra idade, passa pelo filter (seta) e voltam apenas idades &amp;gt;20 "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Por fim, vamos calcular a média desse dado, já transformado de pessoas e filtado para que a idade seja &amp;gt;20. Essa operação avg é o reduce, nesse caso, vamos pensar nela a princípio como uma agregação (tipo min,max,count, etc).&lt;/li&gt;
&lt;/ol&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operação&lt;/th&gt;
&lt;th&gt;Comportamento&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Map&lt;/td&gt;
&lt;td&gt;Transforma o dado, mudando seu tipo. Não muda o número de elementos.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter&lt;/td&gt;
&lt;td&gt;Não transforma o dado, reduz (ou mantém igual) o número de elementos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reduce&lt;/td&gt;
&lt;td&gt;Combina os elementos em um resultado único. É uma operação terminal que produz um único valor com base em uma operação de redução, como soma, média ou máximo.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Por que usar Streams?
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&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;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;people&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;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="nl"&gt;person:&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAge&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
        &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAge&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="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;d&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;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;No exemplo acima, temos um código que &lt;strong&gt;descreve com detalhes o que deve ser feito para chegarmos em um resultado&lt;/strong&gt; (o resultado do exemplo apresentado), e se mudarmos o algoritmo, precisamos mudar o código, mesmo que o algoritmo seja o mesmo. Não necessariamente precisa ser assim, em SQL, por exemplo, escreveríamos:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;Select&lt;/span&gt; &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;People&lt;/span&gt;
&lt;span class="k"&gt;Where&lt;/span&gt; &lt;span class="n"&gt;People&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note que no exemplo acima, descrevemos ao código o que queremos que seja feito, as premissas, descrevemos o resultado, e não como o resultado deve ser computado.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Collection X Streams
&lt;/h2&gt;

&lt;p&gt;Tudo certo, se o código faz parte de uma lista ou qualquer coleção, podemos tentar implementar assim:&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...;&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
&lt;span class="n"&gt;people&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;person&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAge&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;age&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;average&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ERRADO!&lt;/strong&gt; A API de collections não provê esse tipo de operações, o código acima não compila 😄!&lt;/p&gt;

&lt;h3&gt;
  
  
  Mas por que a API de Collections e Streams são separadas?
&lt;/h3&gt;

&lt;p&gt;Imagine que essas operações são feitas em uma lista de 1.000.000 de pessoas! Portanto, após o primeiro map, você teria uma Lista com 1.000.000 de inteiros de idade (porque o map não reduziria o tamanho em si), acho que já deu para perceber que duplicar a collection vai ser altamente custoso para o processador e para a memória&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Um objeto de stream oferece operações de map / filter / reduce sem duplicação e com máxima eficiência!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mas como isso funciona? Quando usamos &lt;code&gt;pessoas.stream()&lt;/code&gt;, retornamos uma &lt;code&gt;Stream&amp;lt;Pessoa&amp;gt;&lt;/code&gt;. Por definição, um objeto de stream não carrega dados, é grátis cria-lo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A collection is an in-memory data structure to hold values and before we start using collection, all the values should have been populated. Whereas a java Stream is a data structure that is computed on-demand. Java Stream doesn’t store data, it operates on the source data structure (collection and array) and produce pipelined data that we can use and perform specific operations.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/java-8-stream" rel="noopener noreferrer"&gt;https://www.digitalocean.com/community/tutorials/java-8-stream&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Operações Intermediárias X Finais
&lt;/h2&gt;

&lt;p&gt;Streams atuam sobre coleções para realizar map / filter / reduce, operações intermediárias são operações sobre streams que retornam streams ( &lt;code&gt;Stream&amp;lt;T&amp;gt; map()&lt;/code&gt;  → Método de stream, retorna stream). &lt;/p&gt;

&lt;p&gt;Operações finais são operações que retornam a coleção de novo, depois do processamento  / pipelining acabar &lt;code&gt;toList()&lt;/code&gt; é um exemplo&lt;/p&gt;

&lt;h2&gt;
  
  
  E como ficaria o código
&lt;/h2&gt;

&lt;p&gt;Aqui está um exemplo de como ficaria o código.&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pessoa&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="n"&gt;pessoas&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="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="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;average&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;💡 Importante: Você não pode processar a mesma stream duas vezes:&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;Stream&lt;/span&gt; &lt;span class="n"&gt;personNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;personStream&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="nl"&gt;Person:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;emptyNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;personNames&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;name&lt;/span&gt; &lt;span class="o"&gt;-&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;gt&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="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
&lt;span class="nc"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;notEmptyNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;personNames&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;name&lt;/span&gt; &lt;span class="o"&gt;-&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;Esse código quebrará, tendo em vista que estamos processando a mesma stream personNames duas vezes!&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;Stream&lt;/span&gt; &lt;span class="n"&gt;personNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;personStream&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="nl"&gt;Person:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;personAges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;personStream&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="nl"&gt;Person:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getAge&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;Nesse caso, estamos aplicando o map para criar duas streams diferentes, não quebrará o código.&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;Stream&lt;/span&gt; &lt;span class="n"&gt;emptyNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;personStream&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="nl"&gt;Person:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getName&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;name&lt;/span&gt; &lt;span class="o"&gt;-&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;gt&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="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="nc"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;notEmptyNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;personStream&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="nl"&gt;Person:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getName&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;name&lt;/span&gt; &lt;span class="o"&gt;-&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;Esse código, processando duas streams diferentes também funcionará&lt;/p&gt;

&lt;p&gt;Por favor, não crie variáveis para trabalhar com streams, fiz por didática&lt;/p&gt;

&lt;h2&gt;
  
  
  FlatMapping
&lt;/h2&gt;

&lt;p&gt;Flatmapping funciona para lidar com relações 1:N&lt;/p&gt;

&lt;p&gt;Exemplo: Cidades, onde temos várias pessoas por cidade.&lt;/p&gt;

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

&lt;p&gt;Suponha que queremos pegar todas as pessoas, independente de suas cidades. Nesse caso, nos preocupamos com a entidade relacionada, não com as cidades em si*&lt;em&gt;. O flatmap faz isso, pega uma entidade Cidade e retorna para nós uma &lt;code&gt;Stream&amp;lt;Pessoas&amp;gt;&lt;/code&gt;.&lt;/em&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;City&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cities&lt;/span&gt; &lt;span class="o"&gt;=&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;City&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;flatMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPeople&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="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="n"&gt;cities&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;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flatMapper&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="cm"&gt;/*poderíamos colocar city -&amp;gt; city.getPeople().stream() direto*/&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;💡 Uma operação de flatmap recebe um objeto e retorna uma stream de outros objetos&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;List&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="s"&gt;"Gomu"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"Gomu"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"No"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Mi"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;streamStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="n"&gt;words&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;w&lt;/span&gt; &lt;span class="o"&gt;-&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// Stream&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Arrays:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Stream&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;O flatmap funciona nesse caso, pois ao aplicar &lt;strong&gt;&lt;code&gt;flatMap(Arrays::stream)&lt;/code&gt;&lt;/strong&gt;, você está dizendo ao Java para pegar cada array de caracteres da &lt;strong&gt;&lt;code&gt;Stream&lt;/code&gt;&lt;/strong&gt; e transformá-lo em uma stream de strings (&lt;strong&gt;&lt;code&gt;Stream&lt;/code&gt;&lt;/strong&gt;) usando o método estático &lt;strong&gt;&lt;code&gt;Arrays.stream()&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streams a partir de RegEx
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sentence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"the quick brown fox jumps over the lazy dog"&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;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sentence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
&lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wordsStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Ion&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wordsStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Ao fazermos dessa forma, criamos um array intermediário, perdemos o propósito de streams.&lt;/p&gt;

&lt;p&gt;Podemos fazer:&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;Pattern&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sp1itAsStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentence&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Streams de outro tipo
&lt;/h2&gt;

&lt;p&gt;Em java, existem interfaces de stream feitas para manipular certos primitivos mais adequadamente, um exemplo disso é a &lt;code&gt;IntStream&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  IntStream
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;IntStream&lt;/code&gt;&lt;/strong&gt; tende a ser mais eficiente em termos de espaço e desempenho quando você está trabalhando com valores inteiros primitivos, uma vez que evita a criação de objetos &lt;strong&gt;&lt;code&gt;Integer&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;&lt;code&gt;IntStream&lt;/code&gt;&lt;/strong&gt; oferece operações especializadas para trabalhar com valores inteiros, como &lt;strong&gt;&lt;code&gt;sum()&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;average()&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;range()&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;rangeClosed()&lt;/code&gt;&lt;/strong&gt;, etc. Uma &lt;strong&gt;&lt;code&gt;Stream&amp;lt;Integer&amp;gt;&lt;/code&gt;&lt;/strong&gt; fornece operações de stream &lt;strong&gt;genéricas&lt;/strong&gt; aplicáveis a &lt;strong&gt;objetos&lt;/strong&gt;, mas é menos eficiente quando se trata de cálculos com tipos primitivos.&lt;/p&gt;


💡 Além do IntStream, também existem `LongStream`e `DoubleStream`(Além da `Stream`)


&lt;h2&gt;
  
  
  Refactoring → Exemplo com múltiplas tarefas ao mesmo tempo
&lt;/h2&gt;

&lt;p&gt;Streams não são uma boa para realizarem múltiplas tarefas simultaneamente, portanto se temos um for loop que agrega valores à 3 variáveis diferentes, precisamos dividir em 3 for’s (repetidos) e trocar cada um deles por uma stream. Claro, isso diminui muito a performance, mas em um for com poucos elementos a serem iterados, será basicamente imperceptível.&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;String&lt;/span&gt; &lt;span class="nf"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;totalAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rentals&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;mapToDoub1e&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;computeRenta1Amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sum&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;frequentRenterPoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rentals&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;mapToInt&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;getFrequentRenterPoints&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sum&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;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;composeHeader&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;rentals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;computeStatementLine&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;joining&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

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


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Reduções
&lt;/h2&gt;

&lt;p&gt;Antes, ouvimos que redução era algo similar a uma agregação do SQL, vamos continuar com isso em mente, mas como isso funciona?&lt;/p&gt;

&lt;p&gt;Vamos ter como exemplo a soma, a soma é uma uma implementação de &lt;code&gt;BinaryOperator&amp;lt;Integer&amp;gt;&lt;/code&gt;, que pega dois elementos e os soma ( &lt;code&gt;sum = (i1,i2) -&amp;gt; i1+i2;&lt;/code&gt;). Isso acontece com dois elementos por vez, associando os valores e depois somando com o outro.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reduções de uma stream vazia
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mas e qual a redução de uma Stream vazia?&lt;/strong&gt; A &lt;strong&gt;redução de uma Stream vazia é o seu elemento identidade (identity),&lt;/strong&gt; um elemento identidade é um valor pré-definido que atua como ponto de partida em uma operação de redução. Em contextos de programação funcional, quando não há elementos para combinar na Stream, a operação de redução retorna o elemento identidade como resultado, garantindo que a operação seja definida e não cause exceções em casos de Stream vazia. Isso é especialmente útil para lidar com casos em que não há dados disponíveis para a operação específica, permitindo que o código se comporte de maneira previsível e segura.&lt;/p&gt;

&lt;p&gt;Por exemplo, o identity de uma soma é 0, tendo em vista que o 0 não impactará no valor final, para múltiplicação, um.&lt;/p&gt;
&lt;h3&gt;
  
  
  Max, Min, Avg?
&lt;/h3&gt;

&lt;p&gt;O "identity element" ou valor inicial para as operações de &lt;strong&gt;&lt;code&gt;max&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;min&lt;/code&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;code&gt;average&lt;/code&gt;&lt;/strong&gt; em Streams do Java é um pouco diferente porque essas operações retornam um &lt;strong&gt;&lt;code&gt;Optional&lt;/code&gt;&lt;/strong&gt;, que pode ser vazio (caso a Stream esteja vazia) ou conter um valor, portanto, essas operações não tem valores identity.&lt;/p&gt;

&lt;p&gt;Portanto, para acessar max, min e avg, você deve fazer algo do tipo:&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;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&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="na"&gt;max&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Integer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&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="na"&gt;min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Integer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;OptionalDouble&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&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="na"&gt;mapToDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Integer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;doubleValue&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;average&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;"Max: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Min: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Average: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NaN&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Como podemos escrever nossas reductions?
&lt;/h3&gt;

&lt;p&gt;Talvez você esteja se perguntando o porquê de entendermos também a fundamentação de identity elements, se ainda não ficou claro, vai ficar agora:&lt;/p&gt;

&lt;p&gt;A operação &lt;strong&gt;&lt;code&gt;reduce&lt;/code&gt;&lt;/strong&gt; em Streams do Java tem dois parâmetros principais:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O valor inicial (identity element): Já foi explicado&lt;/li&gt;
&lt;li&gt;Uma função de acumulação (accumulator function): Esta função é usada para combinar os elementos da Stream em um único resultado. A função deve ser uma expressão lambda ou um método de referência que aceite dois argumentos e retorne um resultado. Em soma, seria 
&lt;code&gt;(a, b) -&amp;gt; a + b&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


💡 Se você não passar um identity correto, o resultado estará incorreto.

Se sua stream não possuir um identity, você pode usar uma outra sobrecarga do método que não recebe o identity, mas retorna um Optional. Use-o somente se não possuir o identity…


&lt;h2&gt;
  
  
  Reduções em um container mutável
&lt;/h2&gt;

&lt;p&gt;Reduções em um container mutável referem-se à aplicação de operações de redução, como soma, multiplicação, média, entre outras, a elementos armazenados em um contêiner que pode ser alterado durante o processo de redução.  Um "container" neste contexto pode ser definido como uma estrutura de dados flexível que permite armazenar e modificar elementos de forma dinâmica (Lists, Maps, etc.). Portanto, podemos simplificar reduções em containers mutáveis como reduções em coleções.&lt;/p&gt;

&lt;p&gt;Ao chamar &lt;strong&gt;&lt;code&gt;.stream()&lt;/code&gt;&lt;/strong&gt; em uma lista, você está criando uma Stream dos elementos contidos na lista. A Stream é uma sequência de elementos que pode ser processada de maneira funcional, &lt;strong&gt;mas não modifica a lista original.&lt;/strong&gt; Quando você chama &lt;strong&gt;&lt;code&gt;.max()&lt;/code&gt;&lt;/strong&gt;,  por exemplo, está solicitando o elemento máximo com base em algum critério da lista, mas a lista em si permanece a mesma.&lt;/p&gt;
&lt;h3&gt;
  
  
  Coletores!
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&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;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoasDaBaixada&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;pessoasDaBaixada&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;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDDD&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;"013"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoasDaBaixada&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;p&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Mas esse exemplo acima não é muito diferente do que já vimos, por que estamos focando nesse tipo de redução?&lt;/p&gt;

&lt;p&gt;Para filtrar e coletar elementos em uma nova lista usando a API de Streams do Java, você deve usar um &lt;strong&gt;coletor&lt;/strong&gt; adequado, como &lt;strong&gt;&lt;code&gt;Collectors.toList()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Os coletores permitem que você capture os resultados das operações de redução em coleções ou outros tipos de dados concretos. &lt;strong&gt;Em outras palavras, eles transformam os elementos processados em uma Stream em uma coleção real que pode ser usada e manipulada posteriormente.&lt;/strong&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoasDaBaixada&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Supondo que o número de DDD seja uma String&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;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoasComDDD13&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pessoasDaBaixada&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;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"13"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDDD&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="c1"&gt;//.toList() retornará uma lista imutável!&lt;/span&gt;


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;”O novo método Stream.toList() não produz nem uma lista não modificável nem é um atalho para &lt;code&gt;collect(toUnmodifiableList())&lt;/code&gt;, porque &lt;code&gt;toUnmodifiableList()&lt;/code&gt; **não aceita valores nulos&lt;/em&gt;&lt;em&gt;. A implementação de Stream.toList() não é limitada pela interface &lt;code&gt;Collector&lt;/code&gt;; portanto, &lt;code&gt;Stream.toList()&lt;/code&gt; aloca menos memória. Isso a torna ideal para uso quando o tamanho da stream é conhecida antecipadamente.”&lt;/em&gt;  &lt;a href="https://stackoverflow.com/questions/65969919/differences-of-java-16s-stream-tolist-and-stream-collectcollectors-tolist#comment121174778_65991907" rel="noopener noreferrer"&gt;Link para comentário no stackoverflow&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Exemplos de Outros Coletores&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Collectors.toSet()&lt;/code&gt;&lt;/strong&gt;: Cria um conjunto a partir dos elementos da Stream, removendo duplicatas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Collectors.toMap(keyMapper, valueMapper)&lt;/code&gt;&lt;/strong&gt;: Cria um map a partir dos elementos da Stream, usando funções de mapeamento para extrair chaves e valores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Collectors.groupingBy(classifier)&lt;/code&gt;&lt;/strong&gt;: Agrupa elementos da Stream com base em um critério definido pela função de classificação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Collectors.joining(delimiter)&lt;/code&gt;&lt;/strong&gt;: Concatena os elementos da Stream em uma única String usando um delimitador.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Collectors.summingInt()&lt;/code&gt;&lt;/strong&gt; ou &lt;strong&gt;&lt;code&gt;Collectors.summingLong()&lt;/code&gt;&lt;/strong&gt;: Calcula a soma dos valores inteiros ou longos de elementos da Stream.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exemplos de uso:
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&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;Integer&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;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoasPorIdade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pessoas&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;groupingBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Person:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getIdade&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="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jorge"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&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;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ben"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&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;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jor"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="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;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapNomeIdade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pessoas&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;toMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Person:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Person:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getIdade&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;💡 Não necessariamente precisamos de collectors para trabalhar com coleções, mas eles tornam a vida mais fácil, veja os dois exemplos anteriores:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="c1"&gt;// ex1&lt;/span&gt;&lt;br&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;Integer&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;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoasPorIdade&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;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;&lt;br&gt;
&lt;span class="n"&gt;pessoas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIdade&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;&lt;br&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;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoasComIdade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pessoasPorIdade&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;idade&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pessoasComIdade&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;br&gt;
        &lt;span class="n"&gt;pessoasComIdade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;&lt;br&gt;
        &lt;span class="n"&gt;pessoasPorIdade&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pessoasComIdade&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;br&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;pessoasComIdade&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;person&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="o"&gt;});&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c1"&gt;// ex2&lt;/span&gt;&lt;br&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;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapNomeIdade&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;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;&lt;br&gt;
&lt;span class="n"&gt;pessoas&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="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapNomeIdade&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIdade&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Pincelando: Streams Paralelas&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;À medida que exploramos as reductions e operações terminais, é crucial considerar o potencial das streams paralelas em Java, mas o que são? 🤔&lt;/p&gt;

&lt;p&gt;Streams paralelas oferecem a capacidade de executar operações em paralelo, aproveitando múltiplos núcleos da CPU, o que melhora muito o desempenho da stream.&lt;/p&gt;

&lt;p&gt;Apesar disso, vale dizer que operações em paralelo nem sempre podem ser consideradas em uma stream, suponha que você esteja calculando uma média com uma reduction, para calcularmos a média, precisamos primeiro somar os elementos, e então dividirmos, se somarmos e depois dividirmos partes distintas, isso trará um &lt;strong&gt;resultado incorreto, isso significa que a média é uma operação não associativa!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Operações Associativas
&lt;/h3&gt;

&lt;p&gt;São operações em que a ordem em que os elementos são combinados não afeta o resultado. Exemplos comuns de operações associativas incluem soma e multiplicação.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;p&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;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&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="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="c1"&gt;// Cálculo da soma em uma stream paralela&lt;/span&gt;&lt;br&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parallelStream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Integer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="nc"&gt;Esse&lt;/span&gt; &lt;span class="n"&gt;parágrafo&lt;/span&gt; &lt;span class="n"&gt;tem&lt;/span&gt; &lt;span class="n"&gt;como&lt;/span&gt; &lt;span class="n"&gt;objetivo&lt;/span&gt; &lt;span class="n"&gt;apenas&lt;/span&gt; &lt;span class="n"&gt;introduzir&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;notificar&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;existência&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt; &lt;span class="n"&gt;streams&lt;/span&gt; &lt;span class="n"&gt;paralelas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;procure&lt;/span&gt; &lt;span class="n"&gt;saber&lt;/span&gt; &lt;span class="n"&gt;mais&lt;/span&gt; &lt;span class="n"&gt;sobre&lt;/span&gt; &lt;span class="n"&gt;elas&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Operações Não-Associativas&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;São o oposto!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusão e Agradecimento
&lt;/h1&gt;

&lt;p&gt;Obrigado pela leitura, espero que tenha sido produtiva e que você tenha todo o conhecimento necessário para conseguir dar seus próprios passos e construir streams funcionais e avançadas, caso necessário.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://app.pluralsight.com/library/courses/692a1310-42db-4f3c-a33b-208a55b7bd84/table-of-contents" rel="noopener noreferrer"&gt;https://app.pluralsight.com/library/courses/692a1310-42db-4f3c-a33b-208a55b7bd84/table-of-contents&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/java-8-stream" rel="noopener noreferrer"&gt;https://www.digitalocean.com/community/tutorials/java-8-stream&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/playlist?list=PL62G310vn6nFIsOCC0H-C2infYgwm8SWW" rel="noopener noreferrer"&gt;Maratona Java Virado no Jiraya&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://acervolima.com/coletores-java/" rel="noopener noreferrer"&gt;https://acervolima.com/coletores-java/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>stream</category>
      <category>java8</category>
      <category>braziliandevs</category>
    </item>
  </channel>
</rss>
