Independência ou sorte!
Podemos chamar de Desenvolvimento Orientado a Sorte o ato de escrever o código sem se preocupar com a dependência entre suas classes e objetos, pois nessa situação o sucesso do seu projeto depende de:
-
Não haver necessidade de alterações no seu código (o que é difícil de acontecer);
-
As classes do seu código possuírem pouca dependência, sem que você tenha consciência disso.
Ou seja, pura sorte.
Por que a dependência entre as classes e objetos é tão prejudicial?
Quando você não se preocupa com a dependência no seu código e surge a necessidade de alterar uma ou mais classes, você pode:
-
Inserir um bug ou um mal funcionamento ao código de produção, pois você não alterou todas as classes dependentes da classe modificada;
-
Levar horas para realizar uma modificação que deveria ser feita em minutos, pois são muitas classes dependentes.
Como saber se há dependência no seu código?
Sempre que a alteração de uma classe te obrigar a alterar outras, há dependência no seu código.
Mas você pode (e deve) identificar as dependências enquanto desenha ou escreve o seu código.
E como fazer isso?
Existem quatro tipos de dependências que você deve evitar:
-
Dependência em relação ao nome de outra classe;
-
Dependência em relação ao nome da mensagem enviada a outra classe;
-
Dependência em relação aos argumentos que a mensagem necessita;
-
Dependência em relação a ordem dos argumentos que a mensagem necessita.
Vamos a um exemplo prático
Imagine o seguinte contexto: você está desenvolvendo um sistema de gestão para uma biblioteca. Por ora, o sistema possui apenas dois requisitos:
-
Deve ser possível adicionar livros em uma determinada posição;
-
Deve ser possível recuperar a posição de um determinado livro.
Então, você escreveu o código para atender aos dois requisitos e como resultado seu sistema possui duas classes Library e Book:
Você consegue identificar as dependências no código?
Apesar de não parecer, esse código inocente contém os tipos de dependências que listei acima. Vejamos onde estão:
1. Dependência em relação ao nome de outra classe
Em nosso código, o método add_book da classe Library é dependente do nome da classe Book.
Esse tipo de dependência apresenta os seguintes problemas:
- Se o nome da classe Book for alterado o método add_book também deverá ser alterado;
- A classe Library está limitada a trabalhar apenas com Book. Se em algum momento a classe Library quiser trabalhar com Article ou Magazine não será possível.
2. Dependência em relação ao nome da mensagem enviada a outra classe
Os métodos públicos add_book e book_position são dependentes da mensagem identification enviada aos objetos da classe Book.
Esse tipo de dependência apresenta o seguinte problema:
- Se o nome da mensagem for modificada, ambos métodos públicos da classe Library também terão de ser modificados.
3. Dependência em relação aos argumentos que a mensagem necessita
4. Dependência em relação a ordem dos argumentos que a mensagem necessita
O método add_book da classe Library é dependente dos argumentos necessários para instanciar os objetos da classe Book. Então, se novos argumentos forem adicionados ou a ordem for alterada, o método add_book também deverá ser modificado.
Além disso, o próprio método add_book possui dependência em relação aos seus parâmetros. Se novos forem adicionados ou a ordem for alterada, todos os objetos e classes que enviam a mensagem add_book aos objetos da classe Library terão que ser alterados.
Como você pôde perceber, em apenas duas classes é possível ter muita dependência. Agora, imagine um contexto com mais de 200 classes.
É possível escrever esse mesmo código evitando essas dependências?
A resposta: sim, é possível!
Existem três técnicas que são excelentes para diminuir a dependência entre suas classes e objetos:
Após aplicar as três técnicas, o código para nosso sistema de gestão da biblioteca ficou assim:
Após aplicar a técnica Dependency Injection, a classe Library não depende mais da classe concreta Book, nem dos argumentos necessários para sua criação. A dependência da classe Library, agora é com um conceito abstrato capaz de responder ao método identification.
Além disso, a nova classe Library é capaz de gerenciar outros itens, como por exemplo artigos (Article). O único detalhe é que os novos itens devem responder a mensagem identification.
Ao aplicar a técnica Isolate Vulnerable External Messages, a classe Library isolou a dependência em relação ao método externo identification em um método privado de seu controle, chamado item_identification(item).
Agora, se alterarmos o nome do método identification para id, por exemplo, o impacto será apenas nesse novo método, protegendo os métodos públicos.
Ao aplicar a técnica Remove Argument-Order Dependencies, o método add_item (que substituiu o antigo add_book) da classe Library necessita apenas de um parâmetro, a hash args. Com isso, você pode adicionar um novo parâmetro em qualquer posição sem que haja a necessidade de alteração de todos os objetos e classes que enviam a mensagem add_item.
Além disso, a nova solução provê mais um benefício: as chaves da hash explicitam a intenção de cada parâmetro.
Concluindo, um código com menos dependência entre as classes e objetos é mais fácil de ser mantido, principalmente se o código for um viajante do tempo, como descrito nesse artigo.