Recentemente, retomei minha leitura do livro “Arquitetura Limpa – O Guia do Artesão para Estrutura e Design de Software”, de Robert C. Martin, gostaria de compartilhar com vocês um tópico que, particularmente, não vejo ser citado em muitos lugares: a Coesão de Componentes.
Saber determinar a que componente uma certa classe pertence é uma tarefa de grande importância, que requer bons conhecimentos sobre os princípios da engenharia de software. Infelizmente, isso não é frequentemente considerado na construção de sistemas, sendo muitas vezes ignorado ou feito ao acaso durante o desenvolvimento, com base no contexto imediato.
Os princípios de coesão de componentes
A coesão de componentes refere-se ao grau em que partes ou módulos de um sistema estão logicamente interligados e focados em uma única função ou propósito. Para compreender a coesão de componentes, é fundamental entender os três princípios que a regem:
- REP: Princípio da Equivalência Reúso/Release (Reuse/Release Equivalence Principle)
- CCP: Princípio do Fechamento Comum (Common Closure Principle)
- CRP: Princípio do Reúso Comum (Common Reuse Principle)
O Princípio da Equivalência do Reuso/Release – REP
A granularidade do reúso é a granularidade do release – Robert C. Martin
No decorrer da evolução tecnológica da última década, tornaram-se populares as ferramentas de gerenciamento de módulos/pacotes, tais como Maven, NuGet, Composer, entre outros. Logo, torna-se indispensável o conhecimento sobre o REP, que à primeira vista pode parecer óbvio, mas deve ser bem compreendido para melhorar a qualidade do seu software.
Esse princípio dita que, para reutilizar componentes em um software, estes devem ser rastreados por um processo e receber números de release. Sem esses números, não é possível garantir a compatibilidade dos componentes. Além disso, esses números servem como base para desenvolvedores saberem quando novos releases serão lançados e quais mudanças devem ser implementadas.
Do ponto de vista de design e arquitetura de software, esse princípio significa que as classes e módulos gerados em um componente devem pertencer a um grupo coeso. O componente não pode simplesmente consistir em uma mistura de diversas classes; deve ter um tema ou propósito abrangente que todos esses módulos compartilham.
Imagine que estamos desenvolvendo um sistema de gerenciamento de biblioteca. Um componente específico é responsável pelo gerenciamento de livros. Seguindo o princípio da equivalência do reuso/release, todas as classes dentro deste componente devem estar focadas em funções relacionadas aos livros, como adicionar novos livros, atualizar informações dos livros e procurar livros no catálogo. Não faria sentido incluir dentro deste componente classes que tratam do gerenciamento de usuários ou da administração de multas, pois isso quebraria a coesão e o foco do componente. Dessa forma, o componente de gerenciamento de livros permanece coeso e reutilizável, facilitando sua manutenção e evolução.
O Princípio do Fechamento Comum – CCP
Reúna em componentes as classes que mudam pelas mesmas razões e nos mesmos momentos. Separe em componentes diferentes as classes que mudam em momentos diferentes e por diferentes razões – Robert C. Martin
Aplicado aos componentes, o CCP diz que devemos reunir em um componente as classes que mudam pelas mesmas razões e nos mesmos momentos e separar em diferentes componentes as classes que mudam em momentos distintos e por diferentes razões.
Esse princípio é uma releitura do Princípio da Responsabilidade Única (SRP), que dita que uma classe ou função deve ter somente uma razão para mudar. Assim como no SRP, o CCP diz que um componente não deve ter muitos motivos para mudar.
Basicamente, quando é necessário fazer uma mudança em um código, o ideal é que essas mudanças ocorram apenas em um componente, não em vários. Caso contrário, é necessário reescrever diversas linhas, reimplementando o que já foi feito e adicionando novas informações.
O CCP também se relaciona com outro princípio do SOLID, o Princípio Aberto/Fechado (OCP), tendo o significado do termo “fechado” igual em ambos. O OCP diz que as classes devem ser fechadas para modificações, mas abertas para extensões. Por não ser possível ter um fechamento completo, as classes são projetadas para ficarem fechadas para a maioria dos tipos de mudanças esperados ou observados. O CCP segue essa definição ao reunir em um mesmo componente as classes fechadas para os mesmos tipos de mudanças, de forma que, ao ocorrer uma modificação nos requisitos, ela tenha uma grande chance de se limitar a uma quantidade reduzida de componentes.
O Princípio do Reuso Comum – CRP
Não force os usuários de um componente a dependerem de coisas que eles não precisam – Robert C. Martin
Assim como os demais, o CRP também nos ajuda a decidir quais classes e módulos devem ser colocados em um componente. Segundo ele, as classes e módulos que tendem a ser reutilizados juntos pertencem ao mesmo componente.
Devido ao fato de que as classes raramente são utilizadas isoladamente, é esperado que diversas classes que fazem parte da abstração reutilizável colaborem umas com as outras. Portanto, segundo o CRP, essas classes devem pertencer a um mesmo componente, tendo várias dependências entre si.
Contudo, o CRP faz mais do que dizer quais classes devem ser reunidas; ele também nos diz quais classes não devem ser reunidas em um componente. Quando um componente usa/estende/implementa outro, uma dependência é criada entre eles. Talvez o componente A use apenas uma classe do componente B, mas ainda assim existe uma dependência. Por conta dessa dependência, toda vez que o componente B for modificado, o A provavelmente precisará ser modificado. Mesmo que não existam mudanças para o A, ele precisará ser recompilado.
Portanto, quando dependemos de um componente, devemos ter a certeza de que dependemos de todas as classes dele, para não gerar dependências e usos desnecessários de código em classes que não fazem parte do contexto da dependência.
O diagrama de tensão para coesão de componentes
Nem tudo são flores. Caso você tenha lido os tópicos anteriores, deve ter percebido que os princípios de coesão tendem a lutar uns com os outros. Por exemplo, o REP e o CCP são princípios inclusivos (ambos tendem a aumentar os componentes), mas o CRP é um princípio excludente (diminui os componentes).
Para isso temos o diagrama de tensão, que representa como os três princípios de coesão interagem entre si. As bordas do diagrama mostram o custo de abandonar o princípio do vértice oposto.
Cabe a um bom arquiteto pesar o uso de determinado princípio no decorrer do projeto. É bastante comum que, no início do desenvolvimento, tenhamos o uso do REP em grande parte, sendo considerado mais importante, algo que certamente mudará conforme o projeto crescer.
Conclusão
No passado, o conceito de coesão era muito mais simples do que sugerido pelo REP, CCP e CRP, já que os sistemas nos dias atuais possuem um nível maior de complexidade, seja em questão de escala, usabilidade ou manutenção. Portanto, lembre-se de aplicar esses conceitos antes de iniciar o desenvolvimento do seu projeto. Não tente construir sua casa sem um bom alicerce. Todos esses princípios parecem simples, mas no final ajudam a manter o nível de complexidade e qualidade do seu software.
Referências: