O que é e Quais os Tipos de Acoplamento - Existe Acoplamento "Bom"?
Tags: braziliandevs, solidprinciples, softwaredevelopment, architecture
Published: 2023-10-31 20:09:51

Segundo o dicionário, uma definição da palavra acoplamento é:

1.união ou ligação entre dois ou mais corpos, formando um único conjunto.
2.conexão, compatibilização (de fatos, ações etc.).

No contexto de software, consideramos acoplamento a dependência entre classes, que tem tudo a ver com a definição da palavra em si. Quando uma classe "chama" outra para executar algo ou buscar algum dado/valor, em qualquer ponto, podemos dizer que existe ali um acoplamento, pois ela depende de alguma coisa que essa outra classe que está sendo chamada faz ou possui.
Ao usar qualquer biblioteca estamos gerando um acoplamento, mesmo em bibliotecas "core" de cada linguagem.

Quando implementamos um sistema, naturalmente queremos evitar o máximo possível de falhas que possam ocorrer ou fatores externos que possam impactar esse sistema de alguma forma. 
É aí que começamos a discutir sobre acoplamento. Quando dependemos de outras classes, sejam abstrações ou implementações concretas, estamos sujeitos as alterações que essas classes podem fazer.

Até aí tudo bem, pois é quase impossível criarmos classes que não dependem de nenhuma outra. Se esse fosse o objetivo, tudo que fossemos criar teríamos que implementar do zero, "reinventar a roda" toda vez, e sabemos que isso vai contra o reuso de código. 

Além do mais, uma classe da qual dependemos alterar internamente uma implementação não é necessariamente algo ruim, pois se criamos um sistema coeso não importa como outras classes implementam seus métodos, contanto que façam o que tem que fazer corretamente.

Por isso podemos dizer que existem dois tipos de acoplamento: o acoplamento bom(ou aceitável) e o acoplamento ruim. Para entendê-los, precisamos antes entender outros dois conceitos de acoplamento: Acoplamento Evolutivo e Acoplamento Estrutural.


- Acoplamento Evolutivo:
O acoplamento evolutivo em software ocorre quando duas partes do código estão tão interligadas que mudanças em uma parte podem forçar mudanças na outra parte para manter a compatibilidade. Em outras palavras, se você altera uma parte do sistema, é necessário fazer alterações em outra parte do sistema para que ele continue funcionando corretamente.

<ul>
Exemplo de Acoplamento Evolutivo:
Imagine um sistema para um site de comércio eletrônico. Temos uma classe Pedido e uma classe Produto. A classe Produto, grava o preço de um produto acessando uma planilha do Excel e registrando o valor na coluna PRECO. Já a classe Pedido tem um método para calcular o valor total de um pedido somando o preço de cada produto no pedido, e para buscar o valor do preço do produto ela lê essa planilha do Excel buscando a coluna PRECO para fazer o somatório.

Nesse caso temos um acoplamento evolutivo, pois uma simples mudança no formato do arquivo gravado na classe Produto teria impacto na classe Pedido.
</ul>

- Acoplamento Estrutural:
O acoplamento estrutural se refere à dependência entre os componentes do sistema: Uma classe A possui uma referência explícita em seu código para uma classe B. 
Por exemplo, no sistema de comércio eletrônico citado anteriormente, cada pedido teria que ter uma lista de produtos. Então na classe Pedido suponhamos que essa lista estivesse armazenada em uma variável: 

```
List<Produto> produtos
```
<ul>
Nesse caso, temos um acoplamento estrutural entre Pedido e List.
</ul>

Tendo isso em mente, podemos observar que o acoplamento menos prejudicial tende a ser o estrutural, onde as mudanças não se propagam tão diretamente. Além disso, um acoplamento  pode ser considerado mais aceitável quando:

- Dependemos de interfaces e não de implementações. Ao dependermos de uma interface não estamos sujeitos a detalhes das implementações, podendo trocar a implementação facilmente sem alterar nossas classes. 

<ul>
Por exemplo: Uma classe que realiza um processo X e chama uma outra para fazer o envio de uma mensagem no final desse processo, que pode ser via chat, email ou etc. O ideal seria termos uma interface do tipo Mensagem e ao realizar o envio da mensagem não teríamos que nos preocupar qual vai ser o tipo de implementação dessa interface(ou seja, como a mensagem será enviada), se via chat ou email.
</ul>
- As interfaces que dependemos são estáveis, ou seja, as assinaturas dos métodos não mudam com frequência.
- Dependemos apenas de métodos públicos das outras classes.

Um acoplamento pode ser considerado ruim e de má prática, quando:
- Dependemos de classes instáveis, que são alteradas com frequência.
- Acessamos diretamente detalhes da implementação de uma classe que dependemos, por exemplo acessar diretamente arquivos, banco de dados, atributos etc. Se essa classe que dependemos mudar um tipo de arquivo ou o tipo de banco de dados, quebraríamos nossa aplicação.
- Os métodos dos quais dependemos são confusos e não deixam claro o que fazem.
- As classes compartilham variáveis ou dados globais com as classes dependentes, por exemplo, a classe B altera o valor de uma variável global que a classe A usa no seu código.

Mesmo seguindo essas "boas práticas" de acoplamento, é importante evitarmos estar acoplados a muitas interfaces diferentes, pois isso naturalmente aumenta o impacto dessas dependências em nossa aplicação. Aliás, muitas dependências podem ser um indicativo de que nossa classe possa estar pouco coerente, realizando muitas funções que poderiam ser de responsabilidade de outras classes.

Além disso, existe também o acoplamento indireto. Podemos estar dependendo de classes que dependem de outras classes e assim sucessivamente. Se uma classe A depende da B que depende da C, e C por algum motivo gera um comportamento inesperado que afeta a classe B, consequentemente a classe A também pode ser impactada.

Resumindo, acoplamento não é necessariamente algo ruim. Entender e gerenciar os tipos de acoplamento evolutivo e estrutural é essencial para o desenvolvimento de software robusto e flexível. Ao aderir às boas práticas, como depender de interfaces estáveis e evitar acessos diretos a implementações específicas, podemos minimizar o impacto das mudanças e promover sistemas mais coesos e de fácil manutenção, garantindo assim a qualidade e a adaptabilidade das nossas aplicações.



---


> Referências: Livro Engenharia de Software Moderna, do Marco Tulio Valente, capítulo 5.