<?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>Forem: DevDen</title>
    <description>The latest articles on Forem by DevDen (@devden).</description>
    <link>https://forem.com/devden</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%2F1076173%2Ffc48b54e-979a-42df-a32d-97a32280a2d8.png</url>
      <title>Forem: DevDen</title>
      <link>https://forem.com/devden</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/devden"/>
    <language>en</language>
    <item>
      <title>revisitando arquitetura em camadas - separação de responsabilidades no backend</title>
      <dc:creator>DevDen</dc:creator>
      <pubDate>Wed, 24 Sep 2025 22:23:30 +0000</pubDate>
      <link>https://forem.com/devden/revisitando-arquitetura-em-camadas-separacao-de-responsabilidades-no-backend-3h9n</link>
      <guid>https://forem.com/devden/revisitando-arquitetura-em-camadas-separacao-de-responsabilidades-no-backend-3h9n</guid>
      <description>&lt;p&gt;Esse ano eu decidi tirar um projeto do papel: parar de ficar apenas pintando botão na interface e rever conceitos básicos de programação e engenharia de software que, por falta de uso no dia a dia, acabaram se perdendo na memória.&lt;br&gt;
O tópico da minha revisão hoje é arquitetura em camadas, mais especificamente a relação entre &lt;code&gt;modules&lt;/code&gt;, &lt;code&gt;services&lt;/code&gt;, &lt;code&gt;controllers&lt;/code&gt;, &lt;code&gt;repositories&lt;/code&gt; e &lt;code&gt;clients&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;E quem quiser refrescar a memória (ou dar pitaco!) também, vamo junto:&lt;/p&gt;
&lt;h2&gt;
  
  
  Module
&lt;/h2&gt;

&lt;p&gt;É como o &lt;em&gt;mise en place&lt;/em&gt; do serviço em questão. Pra quem não tem 300 vídeos de culinária salvos no youtube e não conhece o termo, &lt;em&gt;mise en place&lt;/em&gt; é o preparo e arranjo de todos os ingredientes necessários antes que o prato comece a ser feito, e é exatamente isso que o &lt;code&gt;module&lt;/code&gt; faz: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;configura os providers&lt;/li&gt;
&lt;li&gt;exporta serviços para uso em outros módulos&lt;/li&gt;
&lt;li&gt;importa as dependências que os &lt;code&gt;controllers&lt;/code&gt;, &lt;code&gt;services&lt;/code&gt; e etc vão precisar
tudo isso no &lt;code&gt;start&lt;/code&gt; da aplicação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O código lá dentro se parece mais ou menos com isso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserModule {
    static create() {
        const repository = new UserRepository();
        const service = new UserService(repository);
        const controller = new UserController(service);

        return { repository, service, controller }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Nota:&lt;/strong&gt; em arquiteturas mais comuns em Node/Java (sem frameworks), o termo &lt;code&gt;module&lt;/code&gt; nem sempre é usado para este conceito, muitas vezes se fala em &lt;code&gt;inversão/injeção de dependência&lt;/code&gt;.  Para fins deste artigo, &lt;code&gt;module&lt;/code&gt; é uma abstração usada pra organizar dependências e inicialização de componente, mas pode ter outros significados em outros contextos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Controller
&lt;/h2&gt;

&lt;p&gt;O controller é o ponto de entrada que define os endpoints da API. É ele quem vai lidar com as requisições e as respostas, bem como definir que tipo de requisições os endpoints aceitam (GET, POST, DELETE, etc).&lt;/p&gt;

&lt;p&gt;Aqui do ponto de vista de alguém que está totalmente não familiarizado com backend, o controller se destaca como a camada mais simpática para entender o que determinado serviço (ou contexto?) faz.&lt;/p&gt;

&lt;p&gt;Outras coisas legais também caem sob a responsabilidade do controller:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;transformar dados de resposta usando DTOs&lt;/li&gt;
&lt;li&gt;delegar a lógica de negócio para os &lt;code&gt;services&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserController {
    constructor(userService) {
        this.userService = userService;
    }

    getUsers(){
        try {
            const users = this.userService.getAllUsers();
            return { success: true, data: users };
        } catch (error) {
            return { success: false, error: error.message };
        }
    }

    createUser(name, email) {
        try {
            const user = this.userService.createUser(name, email);
            return { success: true, data: user };
        } catch (error) {
            return { success: false, error: error.message };
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Service
&lt;/h2&gt;

&lt;p&gt;Falando nele, é aqui que a mágica acontece. Todas as operações pesadas e regras de negócio são definidas e realizadas dentro do service. O endpoint retorna dados filtrados de uma lista gigantesca? Provavelmente é o service que vai fazer essa filtragem. O controller, então, não precisa saber de nada complicado: basta chamar o método necessário que o service faz o trabalho todo (ou manda outra camada fazer, mas a gente chega lá daqui a pouco ;))&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserService {
    constructor(userRepository) {
        this.userRepository = userRepository;
    }

    getAllUsers() {
        return this.userRepository.findAll();
    }

    createUser(name, email) {
        if(!email.includes("@")) {
            throw new Error("Invalid email");
        }

        return this.userRepository.create({ name, email });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;É a camada responsável por acessar e fazer operações no banco de dados. Essencialmente abstrai as interações com o BD, encapsulando as queries e assim criando uma interface limpa para acessar dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserRepository {
    constructor() {
        this.users = [
            {id: 1, name: "John", email: "john@email.com"},
            {id: 2, name: "Jane", email: "jane@email.com"}
        ];
    }

    findAll() {
        return this.users;
    }

    create(user) {
        const newUser = { id:Date.now(), ...user };
        this.users.push(newUser);
        return newUser;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Client
&lt;/h2&gt;

&lt;p&gt;Camada de comunicação com serviços externos. Se a aplicação precisa usar outras APIs, esse vai ser o ponto de contato entre ambos, então o Client fica normalmente responsável por:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fazer as requisições HTTP para os outros serviços&lt;/li&gt;
&lt;li&gt;transformar os dados que recebe para que possam ser utilizados na aplicação&lt;/li&gt;
&lt;li&gt;lidar com cache, headers e autenticação
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class EmailClient {
    constructor(apiKey) {
        this.apiKey = apiKey;
    }

    async sendEmail(to, subject, message) {
        const response = await fetch('https://some-api.email-service.com/send', {
            method: 'POST', 
            headers: { 
                'Authorization': this.apiKey,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ to, subject, message })
        });

        if (!response.ok) {
            throw new Error('Email failed');
        }

        return response.json();
    }
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Em resumo:
&lt;/h3&gt;

&lt;p&gt;Separando as responsabilidades em camadas, o fluxo acontece mais ou menos assim:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ao iniciar a aplicação (AppStart)

&lt;ul&gt;
&lt;li&gt;O &lt;code&gt;Module&lt;/code&gt; cria e injeta dependências

&lt;ul&gt;
&lt;li&gt;O &lt;code&gt;UserRepository&lt;/code&gt; é passado pro &lt;code&gt;UserService&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserService&lt;/code&gt; é passado pro &lt;code&gt;UserController&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EmailClient&lt;/code&gt; pode ser injetado no &lt;code&gt;UserService&lt;/code&gt;, se necessário&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; Uma requisição é feita

&lt;ul&gt;
&lt;li&gt;Usuário -&amp;gt; &lt;code&gt;Controller&lt;/code&gt; -&amp;gt; &lt;code&gt;Service&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Service&lt;/code&gt; busca os dados em &lt;code&gt;Repository&lt;/code&gt; (banco de dados) ou &lt;code&gt;Client&lt;/code&gt; (API externa)&lt;/li&gt;
&lt;li&gt;A resposta volta pelo mesmo caminho até o usuário&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  E o module?
&lt;/h4&gt;

&lt;p&gt;Ele não participa desse fluxo em tempo de execução, o module é chamado na inicialização da aplicação e garante que, quando a aplicação estiver de pé, todas as pecinhas dela estão prontas pra uso.&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>programming</category>
      <category>architecture</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
