Descomplicando a Clean Architecture

Guilherme Biff Zarelli
luizalabs
Published in
7 min readJun 29, 2020

Objetivo: O objetivo é mostrar que podemos adequar qualquer design de software mantendo seus princípios para chegar em uma solução que possa ser adequada para cada tipo de problema.

Inspiração: Esse artigo é inspirado em situações e dificuldades reais já vivenciadas que me fez ter uma visão um pouco mais abrangente sobre ter um ideal de arquitetura.

A Clean Architecture foi criada por Robert C. Martin e promovida em seu livro Clean Architecture: A Craftsman’s Guide to Software Structure. Assim como outras filosofias de design de software, a Clean Architecture tenta fornecer uma metodologia a ser usada na codificação, a fim de facilitar o desenvolvimento códigos, permitir uma melhor manutenção, atualização e menos dependências.

Um objetivo importante da Clean Architecture é fornecer aos desenvolvedores uma maneira de organizar o código de forma que encapsule a lógica de negócios, mas mantenha-o separado do mecanismo de entrega.

The Clean Architecture by Robert C. Martin
The Clean Architecture by Robert C. Martin

A Clean Architecture não foi o primeiro conceito de design de software que apareceu, ao longo do tempo as arquiteturas de software vêm sendo criadas com um mesmo objetivo de solucionar um princípio de design conhecido como SoC (separation of concerns).

As vantagens de utilizar uma arquitetura em camadas são muitas, porém podemos pontuar algumas:

  • Testável. As regras de negócios podem ser testadas sem a interface do usuário, banco de dados, servidor ou qualquer outro elemento externo.
  • Independente da interface do usuário. A interface do usuário pode mudar facilmente, sem alterar o restante do sistema. Uma UI da Web pode ser substituída por uma UI do console, por exemplo, sem alterar as regras de negócios.
  • Independente de banco de dados. Você pode trocar o Oracle ou SQL Server, por Mongo, BigTable, CouchDB ou qualquer outro. Suas regras de negócios não estão vinculadas ao banco de dados.
  • Independente de qualquer agente externo. Na verdade, suas regras de negócios simplesmente não sabem nada sobre o mundo exterior, não estão ligadas a nenhum Framework.

A separação de camadas poupará o desenvolvedor de muitos problemas futuros com a manutenção do software, a regra de dependência bem aplicada deixará seu sistema completamente testável. Quando um framework, um banco de dados, ou uma API se tornar obsoleta a substituição de uma camada não será uma dor de cabeça, além de garantir a integridade do core do projeto. Para mais detalhes de cada camada da Clean Architecture podemos ver no blog do Uncle Bob.

“Good architecture makes the system easy to understand, easy to develop, easy to maintain, and easy to deploy. The ultimate goal is to minimize the lifetime cost of the system and to maximize programmer productivity.”
― Robert C. Martin, Clean Architecture

Descomplicando

Uma solução arquitetural dessas se mostra muito eficiente, porém para cada bônus há um ônus, na prática a criação de um modelo estrutural desse porte mostra-se um trabalho e tanto no início, ainda mais com as aplicações se reduzindo cada vez mais a níveis de micro-serviços. Também não podemos permitir que qualquer aplicação seja construída sem o mínimo de estrutura e respeito aos princípios do SOLID.

“Good software systems begin with clean code. On the one hand, if the bricks aren’t well made, the architecture of the building doesn’t matter much. On the other hand, you can make a substantial mess with well-made bricks. This is where the SOLID principles come in.”
― Robert C. Martin, Clean Architecture

O que é errado?

Imagine uma aplicação com um um design muito conhecido e que creio que todo desenvolvedor de software já utilizou:

Primeiramente o problema mais gritante desse design é a não utilização de uma camada de negócio, concentrar toda regra nos services ou até mesmo em outros pontos como entities ou por incrível que pareça nos controllers, é uma grande falha arquitetural.

Por mais bem escrito que esteja, esse acoplamento pode custar muito sua manutenção futura. Possivelmente as entities possuem dependências diretas com regras de negócio e seu ORM, trazendo para ela uma grande responsabilidade e um grande ponto de falha com essa mistura de políticas de baixo e alto nível.

Com essa estrutura como poderíamos migrar uma tecnologia ou um Framework sem alterar praticamente todo o código?

“If you think good architecture is expensive, try bad architecture.”
— Brian Foote and Joseph Yoder

O Ideal é complicado?

Estudando as diversas arquiteturas e conceitos, passando pelo Hexagonal, Onion e por fim na Clean Architecture, que apresentou o ideal de um software em camadas, modular e com uma manutenção relativamente baixa após sua completa implementação, ele e outras geraram um problema de conhecimento e confusão entre as equipes, algumas com dificuldades em implementar um projeto do zero, ou outras esquecendo do trivial no caso de configurar uma injeção de dependência ou não conseguindo entender como funciona todos aqueles módulos. Quando passamos por essas dificuldades evoluímos muito em conhecimento, mas será que vale a pena perder (ou ganhar) boa parte de nossa produtividade na definição de uma arquitetura extremamente ideal?

Lembro de ter passado por diversos problemas até chegar em uma solução de build adequada para um projeto multi módulos implementado de ponta a ponta e depois me perguntei, todo o esforço valeu a pena? Todo e qualquer software precisa desse esforço?

Um bom arquiteto serve justamente para tentar definir esses limites, tendo uma visão mais abrangente de quando, o que implementar, qual a necessidade do projeto no momento e até onde ele pode chegar.

O ideal é complicado? Não deveria, por isso lembre-se sempre do famoso YAGNI (You aren’t gonna need it).

“Architectural refactoring is hard, and we’re still ignorant of its full costs, but it isn’t impossible.”
― Martin Fowler, Patterns of Enterprise Application Architecture

Como podemos descomplicar ?

Com uma visão de arquitetura mais simplista, seguindo todos os bons conceitos, principalmente a de manter o isolamento total do core, mas com uma única camada externa para a aplicação, simulando uma divisão modular fisicamente por packages com config, entrypoint e dataprovider.

Para exemplificar um pouco mais o modelo baseado na Clean Architecture e Ports and Adapters, segue uma ilustração para visualização das dependências de cada camada e as ligações com seus componentes, deixando bem claro suas responsabilidades.

The Simple Clean Architecture by HelpDev
The Simple Clean Architecture by HelpDev

Veja como as dependências sempre vão para o centro, e como o core está totalmente protegido de qualquer interferência externa, permitindo que o desenvolvimento dos detalhes de implementação fiquem totalmente baseados em contratos, nunca expondo os detalhes de alto nível diretamente. Comprovamos isso com o seguinte diagrama de classe:

Nota: Observa-se que no diagrama de classe mostrado foi inserido nas classes que implementam as interfaces a notação @javax.inject.Named, essa notação para quem não a conhece, ou utiliza outra linguagem, é uma notação da especificação de injeção de dependência do Java (JSR-330). Ela é utilizada como dependência no core para que o mesmo não possua nenhuma dependência direta de Framework, assim contendo apenas o trivial, como especificações. Em aplicações Java utilizando o Spring Framework, essa notação permite que nossa aplicação configure a injeção de dependência de forma automática, basta inserir o package que deseja escanear na propriedade scanBasePackages da notação @SpringBootApplication de sua classe principal e se o package do seu core for o mesmo de sua application, nada precisa ser feito (realmente mágico).

Esse modelo também é apresentado brevemente no livro do Robert C. Martin como “Périphérique anti pattern of ports and adapters” pelo seu potencial trade-off caso não se dê importância aos modificadores de acesso, porém se utilizarmos corretamente o modificador de acesso package-private em nossas implementações, isso seria descartado, pois não teria como sua aplicação (ex. entry points) chamar diretamente sua infraestrutura (dataprovider), assim os únicos contratos disponíveis que faça sentido são os contratos dos use cases.

“Architecture is a hypothesis, that needs to be proven by implementation and measurement.”
— Tom Gilb

Conclusão

A solução de uma arquitetura adequada é trivial em qualquer sistema.

Independente de qualquer arquitetura ou método para dizer como você deve ou não construir seu software, acredito que primeiramente temos que respeitar alguns princípios, como o SOLID e os princípios de coesão e acoplamento.

Robert C. Martin disse que arquitetura de software é saber desenhar limites claros de suas classes e componentes para minimizar os recursos humanos necessários para sua construção e manutenção. Seu modelo tem esses limites muito bem definidos porém nesse artigo tentei mostrar que nem tudo precisa ser realizado como um passo a passo ideal, cada problema pode haver uma ou mais soluções adequadas, o importante ao definir uma arquitetura de software é conseguirmos antecipar algumas decisões para que não seja tarde.

“The only way to go fast, is to go well.”
— Robert C. Martin

Referências

Show me the code

--

--