23 de abril de 2026
Arquitetura Limpa e DDD: Qualidade e Desempenho em APIs de Investimentos
Felipe Mendes Lopes; Ugo Henrique Pereira da Silva
Resumo elaborado pela ferramenta ResumeAI, solução de inteligência artificial desenvolvida pelo Instituto Pecege voltada à síntese e redação.
A crescente demanda por sistemas de software robustos e escaláveis tem impulsionado a adoção de arquiteturas que promovam a separação de responsabilidades, testabilidade e facilidade de manutenção. Nesse cenário, a Arquitetura Limpa, proposta por Robert C. Martin, e o Domain-Driven Design, conceituado por Eric Evans, emergem como abordagens complementares que visam estruturar aplicações complexas de forma mais eficiente e sustentável. A Arquitetura Limpa estabelece uma hierarquia de camadas em que as dependências apontam sempre para o centro, garantindo que a lógica de negócio permaneça independente de frameworks, interfaces de usuário e mecanismos de persistência (Martin, 2017). Essa abordagem promove a inversão de dependências por meio de interfaces bem definidas, permitindo maior flexibilidade e testabilidade do sistema. Complementarmente, o Domain-Driven Design enfatiza a modelagem do software baseada no domínio do problema, utilizando conceitos como Agregados, Entidades, Value Objects e Serviços de Domínio para criar uma representação fiel das regras de negócio (Evans, 2003; Vernon, 2013). Arquiteturas bem estruturadas facilitam a implementação de microsserviços e sistemas distribuídos, elementos fundamentais para a escalabilidade horizontal (Fowler & Lewis, 2014). A qualidade arquitetural pode ser mensurada por meio de métricas objetivas de acoplamento, coesão e complexidade, proporcionando bases empíricas para avaliação comparativa entre diferentes abordagens de design (Bass et al., 2021). O foco central reside na análise e demonstração empírica da eficiência e escalabilidade de uma Application Programming Interface desenvolvida com esses princípios, implementada em Node.js com o framework NestJS, aplicada a um sistema de gerenciamento de investimentos.
A fundamentação teórica que sustenta a separação de interesses baseia-se na premissa de que o núcleo da aplicação deve ser isolado de preocupações externas. Na Arquitetura Limpa, as entidades representam as regras de negócio globais, enquanto os casos de uso orquestram o fluxo de dados para e a partir das entidades. Os adaptadores de interface convertem os dados do formato mais conveniente para os casos de uso e entidades para o formato mais conveniente para agentes externos, como bancos de dados ou a web (Martin, 2017). O Domain-Driven Design complementa essa estrutura ao fornecer um vocabulário e padrões táticos para lidar com a complexidade do domínio. O uso de Agregados garante a integridade dos dados dentro de fronteiras de consistência, enquanto os Value Objects permitem modelar conceitos descritivos sem identidade própria, reduzindo a complexidade cognitiva do sistema (Evans, 2003). A integração dessas práticas em ecossistemas modernos, como o Node.js, exige uma compreensão profunda do gerenciamento de dependências e da natureza assíncrona do runtime. A adoção de padrões como o Inversion of Control e a Dependency Injection, nativos em frameworks como o NestJS, facilita a implementação da inversão de dependências preconizada pela Arquitetura Limpa. Além disso, a manutenção da qualidade de software a longo prazo depende da capacidade de evolução do sistema sem a introdução de débitos técnicos excessivos, o que justifica a investigação de métricas de manutenibilidade e extensibilidade em implementações reais (Bass et al., 2021).
O delineamento metodológico adotou a pesquisa experimental aplicada a um sistema de gerenciamento de investimentos, estruturado em três eixos complementares de evidência: testes automatizados de comportamento e de negócio, testes de carga e estresse, e análise estática e dinâmica de qualidade arquitetural. O sistema foi concebido para atender a casos de uso críticos, incluindo cadastro e autenticação de investidores, criação e consulta de ativos, montagem de portfólios, registro de transações de compra, venda e dividendos, além da definição de metas de investimento com cálculos de projeções. Para permitir uma comparação isonômica, implementaram-se duas versões da API: uma seguindo os princípios da Arquitetura Limpa e DDD com NestJS, e outra utilizando o padrão Model-View-Controller tradicional com Express.js e acoplamento direto ao Object-Relational Mapping. A coleta de dados foi automatizada, empregando ferramentas de rastreabilidade de cenários e inspeção de sintomas de tempo de execução. A estratégia de medição para correção funcional fundamentou-se na família de normas ISO/IEC/IEEE 29119, organizando as atividades de planejamento e execução de testes para orientar a rastreabilidade entre requisitos e riscos (ISO/IEC/IEEE 29119-1, 2013).
Os procedimentos operacionais detalhados envolveram a execução de testes unitários e end-to-end com coleta estruturada de tempos por caso e por rota em relatórios XML. Os testes cobriram serviços de domínio como registro de metas, carteira e autenticação. Para a avaliação de desempenho e escalabilidade, realizaram-se ensaios de carga progressiva utilizando a ferramenta Grafana K6, registrando percentis de duração de requisições (p50, p95 e p99), taxa de erros e throughput. A configuração dos testes de carga seguiu a prática de modelagem de Service Level Objectives sobre as caudas de latência, em vez de médias, para capturar com precisão a experiência do usuário em cenários de alta concorrência (Dean & Barroso, 2013). Em paralelo, o runtime foi instrumentado com o Clinic.js Doctor, que coletou perfis de uso de CPU, utilização de memória (RSS, Heap Total e Heap Used), atraso do loop de eventos e handles ativos. Essa instrumentação permitiu diagnosticar gargalos de loop de eventos e consumo anômalo de recursos sob tráfego realista. Para a mensuração da qualidade arquitetural, aplicou-se a ferramenta ts-morph sobre o código-fonte para calcular a complexidade ciclomática, complexidade cognitiva, profundidade de aninhamento e o índice de manutenibilidade, variando de 0 a 171. Também foram extraídas métricas de Halstead para estimar a carga cognitiva e o esforço de implementação (Halstead, 1977).
A análise estática de código incluiu a avaliação do acoplamento eferente, instabilidade e a distância da sequência principal, conforme as métricas de Robert C. Martin para verificar se os módulos do núcleo permaneceram estáveis e abstratos (Martin, 2017). A coesão foi mensurada por meio do Lack of Cohesion in Methods, enquanto o débito técnico foi estimado em horas de trabalho necessárias para refatoração. O ambiente de teste foi configurado com 20 usuários virtuais operando simultaneamente por aproximadamente 16 minutos, garantindo uma carga constante para a comparação entre as arquiteturas. A implementação MVC estruturou-se em camadas de apresentação, aplicação e dados, com os controllers atuando como intermediários diretos entre as entradas HTTP e os serviços que orquestravam a persistência via ORM. Já a implementação em Arquitetura Limpa isolou o domínio em entidades ricas e objetos de valor, com os casos de uso dependendo apenas de interfaces de repositório, deixando as implementações concretas de infraestrutura confinadas na camada externa. Essa rigorosa estruturação visou minimizar o impacto de mudanças tecnológicas no coração da aplicação.
Os resultados apresentados pelos testes de carga evidenciaram uma superioridade substancial da API construída com Arquitetura Limpa e DDD em comparação à implementação MVC tradicional. Sob carga idêntica, a versão em Arquitetura Limpa exibiu uma latência global na casa de dezenas de milissegundos, com um percentil 95 de 45,53 ms. A taxa de falhas foi de apenas 0,01% em um total de 12.570 requisições, demonstrando alta estabilidade. Em contrapartida, a versão MVC manteve uma latência de cauda elevada, com o percentil 95 atingindo 3,82 s, e uma taxa de falhas HTTP de 8,14%. O throughput da versão MVC foi de aproximadamente seis requisições por segundo, totalizando 5.808 requisições, o que representa menos da metade da capacidade processada pela versão em Arquitetura Limpa. Os principais gargalos na implementação MVC foram identificados nas rotas de autenticação e registro de investidor, cujas latências p95 chegaram a 3,42 s e 4,41 s, respectivamente. Esses dados sugerem que o acoplamento direto entre controladores, serviços e o mecanismo de persistência na arquitetura MVC gerou contenções que degradaram o desempenho sob concorrência moderada.
A análise do runtime via Clinic.js Doctor corroborou os achados de desempenho. Na API em Arquitetura Limpa, não foram sinalizados problemas de CPU ou atrasos significativos no loop de eventos, com delays estáveis em dezenas de microssegundos. A utilização do loop de eventos permaneceu em uma faixa típica de 22 a 24 durante o período observado, e o consumo de memória mostrou-se estável, com o heap utilizado em torno de 32 MB. Na aplicação MVC, o diagnóstico identificou problemas de performance tanto para o atraso do loop de eventos quanto para o uso de CPU. Observaram-se picos significativos de latência no início dos traços, atingindo até 187,36 ms, o que indica janelas de bloqueio do loop ou períodos de pressão intensa de Garbage Collection que impactam diretamente a responsividade do sistema. O traço da versão MVC também registrou atividades de coleta de lixo do motor V8 com durações custosas, sugerindo que o arranjo acoplado e a gestão de objetos menos eficiente contribuíram para pausas pontuais mais frequentes. Esses sintomas são coerentes com a maior probabilidade de blocos síncronos ou caminhos de execução ineficientes em arquiteturas onde as responsabilidades não estão claramente delimitadas.
No eixo da qualidade arquitetural, o relatório gerado pelo ts-morph apontou uma complexidade média de 2,21 para o projeto em Arquitetura Limpa, com um acoplamento médio de 0,93 e coesão média de 0,81. A distribuição por camadas preservou uma coesão elevada nas camadas de apresentação e manteve a complexidade controlada no domínio e na infraestrutura. Na implementação MVC, a complexidade média foi de 4,16, quase o dobro da observada na Arquitetura Limpa, com uma coesão média significativamente inferior, de 0,10. A camada de controladores no MVC apresentou uma complexidade máxima de 18, sinalizando uma concentração excessiva de múltiplas responsabilidades na borda do sistema e um baixo encapsulamento do domínio. A correlação entre coesão elevada, complexidade baixa e latência estável emergiu de forma clara nos dados. Embora a Arquitetura Limpa possua um tamanho de código significativamente maior em termos de número de arquivos e linhas, ela sustenta métricas internas mais favoráveis que se traduzem em um desempenho mais previsível. O débito técnico estimado para a versão em Arquitetura Limpa foi de 783,87 horas, enquanto para a MVC foi de 842,45 horas, indicando que, apesar do esforço inicial de estruturação, a manutenibilidade a longo prazo é favorecida pela primeira.
A discussão dos resultados permite inferir que a separação de responsabilidades e a independência tecnológica da Arquitetura Limpa favoreceram a baixa latência de cauda e a resiliência sob carga. A modelagem por casos de uso e o isolamento das regras de negócio em entidades ricas permitiram que o sistema escalasse com maior previsibilidade. Em sistemas distribuídos, as caudas de latência importam de modo desproporcional para a experiência do usuário, e a capacidade da Arquitetura Limpa de manter esses valores dentro de limites aceitáveis é um diferencial crítico (Dean & Barroso, 2013). A implementação MVC, ao favorecer a entrega inicial rápida por meio do acoplamento natural a frameworks e ORMs, expôs a aplicação a dependências diretas que dificultaram a otimização e o isolamento de gargalos. A variabilidade observada na latência do MVC e a maior incidência de erros sugerem que o custo de evolução e a robustez operacional são prejudicados em arranjos altamente acoplados. A convergência entre as métricas de qualidade estática e os resultados dinâmicos de carga respalda a conclusão de que a coesão de módulo e a complexidade contida são determinantes para a saúde do sistema à medida que a pressão de usuários simultâneos cresce.
A testabilidade também se mostrou superior na abordagem em Arquitetura Limpa. A suíte unitária abrangeu amplamente o domínio com 164 casos de teste, exercitando invariantes e comportamentos de casos de uso de forma isolada. A mediana de execução desses testes foi de 5 ms, permitindo um feedback rápido durante o desenvolvimento. Na versão MVC, a suíte unitária contabilizou apenas 10 casos, focando em caminhos felizes e com menor decomposição de cenários de borda. A ausência de isolamento das regras de negócio no MVC reduziu a robustez do oráculo de testes, exigindo uma ênfase maior em testes de integração e end-to-end, que são naturalmente mais lentos e custosos de manter (Fowler, 2012). Os testes end-to-end na Arquitetura Limpa cobriram 18 casos com uma mediana de 100 ms, enquanto no MVC foram cobertos oito casos com uma mediana de 622 ms. Essa diferença de latência nos testes de fluxo completo reflete tanto o acoplamento entre as camadas quanto a eficiência do processamento interno de cada arquitetura. A capacidade de realizar testes rápidos e variados no núcleo de negócio, sem carregar o ambiente completo de infraestrutura, é uma vantagem competitiva da Arquitetura Limpa para a evolução segura do software.
Reconhecem-se limitações inerentes à adoção conjunta da Arquitetura Limpa e do DDD, como a curva de aprendizado acentuada e o overhead inicial no desenvolvimento, que resulta em um maior número de arquivos e configurações comparado à abordagem tradicional. A natureza single-threaded do Node.js também influencia os resultados, especialmente em operações intensivas de CPU, onde a eficiência do código e a gestão do loop de eventos tornam-se ainda mais críticas. A generalização dos resultados pode ser limitada ao contexto do domínio de investimentos, sendo recomendada a validação em outros domínios com diferentes cargas de trabalho. No entanto, as evidências coletadas sugerem que, para sistemas que exigem alta disponibilidade e evolução contínua, os benefícios da estruturação rigorosa superam os custos iniciais. Pesquisas futuras poderiam explorar o impacto dessas arquiteturas em ambientes de microsserviços orquestrados por Kubernetes, avaliando como a independência tecnológica facilita estratégias de autoscaling e implantação contínua. A integração de métricas de observabilidade em tempo real com orçamentos de erro baseados em Service Level Indicators também representa um campo promissor para a gestão operacional baseada em evidências.
Conclui-se que o objetivo foi atingido ao demonstrar que a Arquitetura Limpa e o Domain-Driven Design habilitam uma evolução segura e um desempenho superior em APIs de investimentos, proporcionando latência estável, alta testabilidade e baixo risco estrutural. A separação de responsabilidades e a independência de infraestrutura reduziram o acoplamento e elevaram a coesão, permitindo que o sistema suportasse cargas de trabalho intensas com uma taxa de erro quase nula, enquanto a abordagem tradicional apresentou degradação crítica sob as mesmas condições. A organização do domínio em entidades ricas e casos de uso explícitos facilitou o isolamento de regras de negócio e a automação de testes, resultando em uma base de código mais manutenível e preparada para o crescimento escalável. Recomenda-se a adoção dessas práticas em projetos de alta complexidade, priorizando a gestão incremental do débito técnico e o monitoramento contínuo orientado a percentis para sustentar a qualidade da experiência do usuário ao longo do ciclo de vida do software.
Referências Bibliográficas:
Bass, L.; Clements, P.; Kazman, R. Software Architecture in Practice. 4. ed. Boston: Addison-Wesley, 2021.
Dean, J.; Barroso, L. A. The Tail at Scale. Communications of the ACM, v. 56, n. 2, p. 74-80, 2013.
Evans, E. Domain-Driven Design: Tackling Complexity in the Heart of Software. Boston: Addison-Wesley, 2003.
Fowler, M. The Practical Test Pyramid. 2012. Disponível em: <https://martinfowler.com/bliki/TestPyramid.html>. Acesso em: 14 set. 2025.
Fowler, M.; Lewis, J. Microservices. 2014. Disponível em: <https://martinfowler.com/articles/microservices.html>. Acesso em: 14 set. 2025.
Halstead, M. H. Elements of Software Science. New York: Elsevier, 1977.
ISO/IEC/IEEE 29119-1; 29119-2; 29119-3; 29119-4. Software and systems engineering — Software testing. Genebra: ISO, 2013–2015.
Martin, R. C. Clean Architecture: A Craftsman’s Guide to Software Structure and Design. Boston: Prentice Hall, 2017.
Vernon, V. Implementing Domain-Driven Design. Boston: Addison-Wesley, 2013.
Resumo executivo oriundo de Trabalho de Conclusão de Curso da Especialização em Engenharia de Software do MBA USP/Esalq
Para saber mais sobre o curso, clique aqui e acesse a plataforma MBX Academy




























