<?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: Bruno Brolesi</title>
    <description>The latest articles on DEV Community by Bruno Brolesi (@brunobrolesi).</description>
    <link>https://dev.to/brunobrolesi</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%2F1659258%2F9ad85094-6d4f-4ab2-be2d-db5d1063e9f1.jpeg</url>
      <title>DEV Community: Bruno Brolesi</title>
      <link>https://dev.to/brunobrolesi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brunobrolesi"/>
    <language>en</language>
    <item>
      <title>Modelo de Desing de Aplicações Backend</title>
      <dc:creator>Bruno Brolesi</dc:creator>
      <pubDate>Thu, 20 Jun 2024 22:52:06 +0000</pubDate>
      <link>https://dev.to/brunobrolesi/modelo-de-desing-de-aplicacoes-backend-47jp</link>
      <guid>https://dev.to/brunobrolesi/modelo-de-desing-de-aplicacoes-backend-47jp</guid>
      <description>&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introdução&lt;/li&gt;
&lt;li&gt;
Camadas

&lt;ul&gt;
&lt;li&gt;Infrastructure&lt;/li&gt;
&lt;li&gt;Business&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Boas Práticas

&lt;ul&gt;
&lt;li&gt;Testes Unitários&lt;/li&gt;
&lt;li&gt;Testes de Integração&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fluxo de Desenvolvimento&lt;/li&gt;
&lt;li&gt;Pontos de Atenção&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Após anos trabalhando com diferentes modelos de design em aplicações e coletando feedbacks variados sobre como as implementações evoluem ao longo do tempo, decidi escrever este artigo. Aqui, proponho um modelo de design de código para o desenvolvimento de aplicações backend, baseado no que funcionou melhor nas equipes em que trabalhei. Esse modelo busca equilibrar abstrações e a separação de responsabilidades, combinando conceitos de &lt;a href="https://medium.com/bemobi-tech/ports-adapters-architecture-ou-arquitetura-hexagonal-b4b9904dad1a" rel="noopener noreferrer"&gt;Arquitetura Hexagonal&lt;/a&gt;, &lt;a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" rel="noopener noreferrer"&gt;Clean Architecture&lt;/a&gt; e &lt;a href="https://fullcycle.com.br/domain-driven-design/" rel="noopener noreferrer"&gt;DDD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A imagem abaixo oferece um panorama do modelo que será detalhado ao longo deste artigo.&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%2Fqdahigo6v11njbg7c15s.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%2Fqdahigo6v11njbg7c15s.png" alt="Imagem contendo blocos que representam cada camada e subcamada da aplicação; cada camada será explicada ao longo do artigo" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Antes de nos aprofundarmos nos detalhes de cada módulo, vejamos um panorama rápido das camadas da nossa aplicação:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Um cliente faz uma chamada para a aplicação, que é recebida na camada de &lt;code&gt;delivery&lt;/code&gt;. Nessa etapa, os dados fornecidos são extraídos e validados. Se os dados forem inválidos, a requisição é rejeitada aqui mesmo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se os dados forem válidos, a requisição é encaminhada para a camada de &lt;code&gt;usecase&lt;/code&gt;, onde todas as regras de negócio são processadas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Se o &lt;code&gt;usecase&lt;/code&gt; precisar de um serviço externo, como um banco de dados, ele utiliza a camada de &lt;code&gt;gateway&lt;/code&gt;, que contém as interfaces que definem os contratos das implementações responsáveis por essa comunicação.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Após a interação com o serviço externo, o fluxo segue o caminho inverso até retornar o resultado ao cliente, passando novamente pela camada de &lt;code&gt;usecase&lt;/code&gt; e depois pela camada de &lt;code&gt;delivery&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Camadas &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Agora vamos explorar cada uma das camadas do modelo mostrado na imagem, começando pelas partes mais externas: &lt;code&gt;infrastructure&lt;/code&gt; e &lt;code&gt;business&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;infrastructure&lt;/code&gt;: Este pacote contém tudo o que não faz parte das regras de negócio da aplicação, como protocolos de comunicação, frameworks e conexões com bancos de dados. Vamos explorar os pacotes internos deste módulo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;delivery&lt;/code&gt;: Responsável pela comunicação entre a aplicação e seus clientes (webapp, CLI, etc.). Ele possui subpacotes para organizar cada responsabilidade.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;webapp&lt;/code&gt;: Contém o servidor web, rotas e o tratamento de requisições HTTP.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;middlewares&lt;/code&gt;: Contém os middlewares da aplicação.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;handlers&lt;/code&gt;: Trata as requisições HTTP, extraindo e validando os dados, para então chamar os &lt;code&gt;use cases&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;consumers&lt;/code&gt;: Trata as mensagens recebidas em consumers, realizando a extração e validação dos dados antes de chamar os &lt;code&gt;use cases&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;requests&lt;/code&gt;: Define as estruturas e validadores para o body, headers, pathParams e queryParams das requisições.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;responses&lt;/code&gt;: Define as estruturas e padroniza as respostas de sucesso e erro dos handlers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;messages&lt;/code&gt;: Define e valida as mensagens processadas pelos consumers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dependencies&lt;/code&gt;: Gerencia a injeção de dependências da aplicação.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;repository&lt;/code&gt;: Implementa a comunicação com bancos de dados, seguindo o contrato definido pelos gateways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;config&lt;/code&gt;: Configura os clientes dos bancos de dados utilizados no repository.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;service&lt;/code&gt;: Implementa a comunicação com serviços externos, seguindo o contrato definido pelos gateways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;config&lt;/code&gt;: Configura clientes HTTP, SDKs, etc., utilizados pelo service.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;publisher&lt;/code&gt;: Implementa a publicação de mensagens em tópicos, seguindo o contrato dos gateways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;config&lt;/code&gt;: Configura os clientes utilizados para publicação de mensagens.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Business &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;business&lt;/code&gt;: Este pacote contém tudo relacionado ao domínio da aplicação, dividido nos seguintes subpacotes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;usecase&lt;/code&gt;: Implementa os casos de uso da aplicação, aplicando as regras de negócio necessárias.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;logic&lt;/code&gt;: Camada opcional para tratar lógicas mais complexas, como a aplicação do padrão &lt;a href="https://refactoring.guru/pt-br/design-patterns/strategy" rel="noopener noreferrer"&gt;strategy&lt;/a&gt; e &lt;a href="https://refactoring.guru/design-patterns/chain-of-responsibility" rel="noopener noreferrer"&gt;chain-of-responsibility&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gateway&lt;/code&gt;: Define as interfaces (contratos) para comunicação com serviços externos, que são implementadas nas camadas de &lt;code&gt;repository&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt; e &lt;code&gt;publisher&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;domain&lt;/code&gt;: Contém as entidades core da aplicação. A camada &lt;code&gt;domain&lt;/code&gt; pode ser usada por outras camadas, mas não deve depender de nenhuma delas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Boas Práticas &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Testes Unitários &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A escrita de testes unitários é essencial, mas não para todas as camadas. Em minha experiência, não é vantajoso testar pacotes de &lt;code&gt;infrastructure&lt;/code&gt; que implementam os gateways (&lt;code&gt;repository&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt; e &lt;code&gt;publisher&lt;/code&gt;), pois, em geral, esses pacotes utilizam bibliotecas externas já bem testadas.&lt;/p&gt;

&lt;p&gt;Ao escrever testes unitários, devemos isolar a unidade de código. Por exemplo, ao testar um &lt;code&gt;handler&lt;/code&gt;, o &lt;code&gt;usecase&lt;/code&gt; chamado deve ser mockado. Da mesma forma, ao testar um &lt;code&gt;usecase&lt;/code&gt;, as chamadas aos serviços externos devem ser mocks, não implementações reais.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testes de Integração &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Testes de integração garantem a confiabilidade da comunicação entre camadas. Eles são especialmente úteis para cobrir partes da aplicação que não possuem testes unitários. Ao realizar esses testes, simulamos a aplicação e mockamos apenas as dependências externas, como bancos de dados ou chamadas HTTP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fluxo de Desenvolvimento &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Uma boa prática é evitar criar toda a estrutura do projeto no início. Em vez disso, comece pela camada de &lt;code&gt;usecase&lt;/code&gt;, e vá adicionando as outras camadas conforme necessário. Isso mantém o foco nas regras de negócio e evita código não utilizado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dica:&lt;/strong&gt; Utilizar diagramas de fluxo, como os criados com o &lt;a href="https://mermaid.js.org/" rel="noopener noreferrer"&gt;Mermaid&lt;/a&gt;, ajuda a visualizar o que precisa ser implementado em cada &lt;code&gt;usecase&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pontos de Atenção &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Este modelo separa bem as regras de negócio das tecnologias de terceiros, mas, em alguns casos, pode ser necessário "sujar" o design para atender a certos requisitos, como a necessidade de uma transação SQL. O importante é balancear eficiência e elegância no design.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
