Desenvolvimento

28 set, 2015

Qual é a diferença entre Tightly-, Loosely-, e De-Coupled?

Publicidade

Em um tweetstorm gerado há algum tempo, Taylor Otwell produziu os seguintes comentários:

  • Olha, gente, estou “desacoplado” porque esse pacote não tem dependências do composer !!! HAHAHAHA LOL
  • Quantos pacotes um determinado aplicativo tem no composer não afeta o desacoplamento do seu código, já que essa é uma questão de programação para uma interface etc.
  • Vocês seriamente não entendem desacoplamento. De jeito nenhum.
  • Se você digitar AuraAnything, esta será uma dependência dura e concreta, ISSO é acoplamento.
  • IlluminateContracts são interfaces, abstrações e não são concreções. Isso é desacoplamento.
  • IlluminateContractsViewFactory pode ser uma View Factory do Laravel, pode ser uma do Aura. Isso é desacoplamento.
  • Quantos pacotes do composer são necessários para implementar alguma coisa é um detalhe de implementação que meu código consumidor não precisa se preocupar. O código consumidor só se preocupa com programar para uma interface por causa do desacoplamento.
  • Você [philsturgeon], Brandon [savage] e paul [Jones] não entendem conceitos básicos de programação como acoplamento e acham que, de alguma forma, o acoplamento está ligado ao composer.
  • Aura entrega concreções duras = você está fortemente acoplado ao Aura.
  • Não dou a mínima se Aura está desacoplado de si mesmo. Ninguém dá a mínima. Eu só me importo se o meu código está acoplado ao Aura, e como o Aura o faz depender de concreções duras, isso promove altos acoplamentos.
  • Eu estou dizendo que se você fizer uma referência explícita para uma classe, você estará acoplado àquela implementação, independentemente das dependências internas existentes no pacote.

Enquanto parte do discurso de Taylor é correto, existem distinções em várias direções, e gera alguns mal entendidos. Ele também está errado em suas afirmações sobre a compreensão de outras pessoas sobre a “terminologia de programação básica”. Como tal, penso que suas palavras exigem uma resposta cuidadosa para referência futura.

Em primeiro lugar, estou contente em ver o Taylor chamar a atenção para o uso adequado da terminologia em um contexto de software. Isso é algo que ele nem sempre fez direito no passado, e eu o encorajo a fazer aqui.

Mas eu não consigo dizer se Taylor acha que os desenvolvedores que usam Aura acreditam que seu código é desacoplado em virtude da utilização do Aura. Ou talvez seja a comercialização da frase “bibliotecas totalmente desacopladas” o alvo de sua ira. Deduzo alusões sobre seus tweets, então eu vou tentar abordar as duas possibilidades (talvez haja alguma outra interpretação que eu perdi).

Deve ser tão óbvio que não exija afirmação, mas apenas por uma questão de clareza: se o seu código tem uma dependência explícita de classes de um determinado pacote de terceiros, então ele estará fortemente acoplado ao código desse pacote. Isso é verdade para qualquer classe de qualquer biblioteca, framework ou outro pacote qualquer. Então, se você acredita que depender de uma biblioteca Aura em seu código o torna “desacoplado”, então você está enganado. Até onde eu sei, nunca tentei afirmar ou sugerir o contrário. Eu não acho que qualquer usuário Aura tem essa percepção, mas, se assim for, considere esta uma correção.

O fato de seu código estar fortemente acoplado a outro pacote não significa que o outro pacote está acoplado a qualquer outra coisa. Ou seja, o outro pacote não pode ter nenhum acoplamento de qualquer tipo ou para qualquer outro código externo. O outro pacote, nesse caso, é des-acoplado.

Os pacotes do biblioteca Aura são projetados com esse tipo de desacoplamento em mente. Ou seja, nenhum pacote da biblioteca Aura depende de qualquer coisa ou de qualquer outro pacote Aura. Cada uma das bibliotecas Aura é, portanto, totalmente desacoplada das outras, e, incidentalmente, de qualquer framework que seja composto por elas (note que _Kernel e pacotes _Project são acoplados a outros pacotes. A princípio, o desacoplamento apenas se aplica aos pacotes de bibliotecas Aura).

Mas por que você se importaria se um pacote de biblioteca em particular é desacoplado de outros pacotes? Afirmo que uma razão (de muitas) pelas quais você desejaria que bibliotecas estejam desacopladas é para que, no caso de precisar variar uma biblioteca que seu código utiliza, você precisará se ​​preocupar somente com a biblioteca que irá trocar, e não com todas as bibliotecas dependentes e que estão acopladas à ela (e todas as bibliotecas dependentes que estão acopladas entre si). Variar bibliotecas é ainda tedioso: você vai precisar trabalhar através de seu código, alterar todas as referências explícitas de classes da biblioteca utilizada e mudar todas as injeções que especificam as classes da biblioteca. Mas pelo menos será somente aquela biblioteca; o fato de a biblioteca ser desacoplada reduz o trabalho de refatoração.

Taylor aponta outro nível de acoplamento chamado acoplamento “fraco”. Isso significa que, em vez de seu código depender de uma classe em particular, irá depender de uma interface. Isso o acoplará à uma interface, mas não à qualquer implementação específica. Se o seu código depende de interfaces, estará fracamente acoplado às implementações dessas interfaces (embora eu não ache que isso signifique que o código é des-acoplado – há ainda algum conhecimento necessário para interações).

Estar fracamente acoplado é uma boa situação, quando comparado com o código que está fortemente acoplado. Se precisar trocar uma implementação de uma interface, não precisará alterar as referências explícitas (a menos que você as troque para outro conjunto de interfaces). No entanto, ainda será necessário mudar todas as suas injeções de código para a nova implementação. No geral, o acoplamento “fraco” faz o trabalho ser menor quando você está variando bibliotecas.

Como podemos dizer se um pacote está acoplado a outro pacote? Uma vez que o arquivo composer.json não está mentindo, é fácil examinar o elemento “require” e verificar se outros pacotes estão listados lá. Se estiverem, então é provável que o pacote esteja acoplado ao que quer que seja requerido. Você precisa ter um pouco de juízo, no entanto. Se o pacote contém apenas interfaces necessárias, então o acoplamento está “fraco”. Se não houver outros pacotes necessários, o pacote não terá acoplamento de qualquer tipo; ele estará totalmente desacoplado de qualquer coisa fora dele.

No entanto, isso funcionará apenas se você assumir que o composer.json não está mentindo. Para realmente descobrir o acoplamento de um pacote em particular, é preciso examinar seu código. Quaisquer usos de interfaces definidas fora do pacote indicam um acoplamento fraco, uso de classes definidas fora do pacote indicam acoplamento forte, e nenhum uso de interfaces ou classes externas ao pacote indicam desacoplamento total.

(Note que essa discussão é sobre acoplamento inter-pacote. Mesmo se as classes dentro de um pacote ainda estiverem acopladas umas às outras, o pacote como um todo pode ainda estar desacoplado de qualquer outro pacote).

Dito tudo isso, Taylor está tentando criar um pacote de contratos que expõe as interfaces Laravel, independentemente das implementações. Acho que essa é uma ideia elegante. É a única coisa verdadeiramente nova que eu vi apresentada à comunidade PHP pela base de código Laravel, e eu acho que é digna de ser imitada.

Mesmo assim, se os contratos incluírem quaisquer coisas além de interfaces, acho que o acoplamento para eles pode ser definido como “forte”. Estou pensando especificamente nas classes de exceção incluídas no pacote. Embora possa ser justo pensar que exceções são isentas de regras de acoplamento, talvez elas sejam melhor fornecidas como interfaces para exceções, em vez de classes propriamente ditas. Vou reservar meu julgamento para um momento posterior.

***

Paul M. Jones faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://paul-m-jones.com/archives/6051