Descomplicando a Clean Architecture


A Clean Architecture foi criada por Robert C. Martin e promovida em seu livro Clean Architecture: A Craftsman’s Guide to Software Structure. 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 possuir 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

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 e 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, sua solução apresentou o ideal de um software em camadas, modular e com uma manutenção relativamente baixa após sua completa implementação, porém 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 foi necessário? 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

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:

Diagrama de classe

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 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 o único contrato disponível 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

Help DEV – Analista desenvolvedor Java / Android https://helpdev.com.br/zarelli

Descomplicando a Clean Architecture

2 pensou em “Descomplicando a Clean Architecture

  1. Olá, estou estudando a clean architecture e acabei achando esse artigo. Gostei bastante da explicação, porém surgiu algumas dúvidas.
    Após a leitura, fui verificar o projeto do seu repositório git para entender melhor como isso ficaria em código, e vi que além das anotações @Named e @Inject (citadas aqui), seu projeto também tem anotações do lombok dentro do core como @Builder, @Data ..

    A dúvida é, o propósito da clean architecture é a de isolar o core da aplicação e seus casos de uso para prevenir erros em mudanças futuras (caso ocorra) porém nesse modelo simplificado, a utilização de bibliotecas de terceiros (como lombok, mapstruct), não fere a independência do core?

    Só fiquei com essa dúvida, pois pelo o que eu havia entendido em outras leituras, era que não se deveria ter dependência de terceiros no core da aplicação, mas como seu projeto usa o lombok gostaria de essa regra se refere apenas aos frameworks (Spring, Quarkus,..) e libs como Mapstruct, lombok estão liberadas?

    Ficou também a dúvida se somente algumas especificações da linguagem como a de injeção de dependências @Named, @Inject são permitidas ou se todas as outras especificações da jakarta também são, tipo validations @NotEmpty, @Valid…

    1. Fala @Jhon tudo bem? obrigado pelo comentário. O propósito maior é o isolamento do framework, as especificações como do Jakarta são justamente uma alternativa ao framework por se tratarem de especificações comumente utilizadas em quase todos os frameworks para garantir a retrocompatibilidade, no caso, acredito que são válidas sim, e demais dependencias como Lombok, Mapstruct seguem o mesmo princípio, pois elas não vão deixar sua aplicação acoplada ao framework, elas são mais volateis entre eles, não são criadas por eles. Em resumo, não acredito que devemos ser tão ‘puristas’ ao ponto de não usar nenhuma lib, até mesmo porque isso complicaria muito mais nosso desenvolvimento e não traria vantágens significativas, gosto de pensar que o mais importante é partir pela independência sem gerar acoplamento, como? usando especificações e libs que eu possa usar em outros escopos, faz sentido?

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

Rolar para o topo