/ Desenvolvimento

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:

  1. Não haver necessidade de alterações no seu código (o que é difícil de acontecer);

  2. 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:

  1. 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;

  2. 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:

  1. Dependência em relação ao nome de outra classe;

  2. Dependência em relação ao nome da mensagem enviada a outra classe;

  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.

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:

  1. Deve ser possível adicionar livros em uma determinada posição;

  2. 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:

worst_solution-1

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.

add_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.

add_book_book_position

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.

add_book-1

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.

add_book-2

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:

better_solution-2

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.

add_item-4

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.

article_class
using-3

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).

item_position

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.

item_identification-1

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.

add_item-5

Além disso, a nova solução provê mais um benefício: as chaves da hash explicitam a intenção de cada parâmetro.

adding_book

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.