Olá, leitores! Olá, leitores! Olá, leitores!
Repetir a mesma frase várias vezes pode parecer chato e entediante, não é, não é, não é? Pois bem, o artigo de hoje discute justamente sobre a repetição de código e as consequências que ela pode trazer na arquitetura do software.
Se você pretende ser mais objetivo em suas implementações, acompanhe o artigo!
A questão da duplicação de código já foi levantada por vários autores na área de desenvolvimento de software. Dave Thomas e Andy Hunt criaram um princípio chamado DRY, do inglês Don’t Repeat Yourself (Não se repita), para discursar os problemas que a duplicação pode causar. Mais tarde, Kent Beck também incluiu este princípio na metodologia ágil eXtreme Programming (XP), devido à sua importância.
Em 2013, elaborei um artigo sobre Sub-Rotinas que trata a duplicação de forma prática, criando métodos em comum que podem ser utilizados em diferentes locais do software.
Agora, iremos entrar um pouco mais no contexto da duplicação. Você já parou pra pensar, por exemplo, o motivo que leva um desenvolvedor a duplicar o código?
Ainda não pensei nisso…
Quando fazemos a modelagem das classes, utilizamos bastante o conceito de abstração da Orientação a Objetos. Através dela, é possível identificar a hierarquia de classes, heranças, dependências e os métodos que podem ser polimórficos. Logo, se um determinado código está duplicado no software, pode-se afirmar que houve uma falha na modelagem, ou melhor, na abstração do projeto.
Muitas vezes, tudo se inicia com o tradicional “Copiar e Colar”. Ao implementar uma nova funcionalidade que converte um relatório para PDF, por exemplo, o desenvolvedor pensa consigo: “Oras, se eu preciso converter um relatório para PDF e já existe um método pronto pra isso, vou usá-lo!”. Porém, ao invés de utilizar o mesmo método, o cidadão cria outro método e copia o código!!!
E por que ele faz isso?
Há vários motivos. Talvez porque seja mais rápido, embora o desenvolvedor não pense na dificuldade de manutenção que isso irá resultar.
Outro motivo é a “separação de preocupações”: vamos supor que o método de conversão para PDF esteja na classe “RelatorioPedido” e seja necessário utilizar essa mesma funcionalidade na emissão de orçamentos. Se fizermos referência da classe “RelatorioPedido” dentro da classe “EmissaoOrcamentos”, vai ficar sem sentido, concorda? São escopos diferentes e não devem ser confundidos. Além disso, estaríamos causando um efeito conhecido como Dependência Magnética.
Dependência Magnética?
Sim. Continuando o exemplo, imagine que o desenvolvedor efetue uma modificação no método de conversão da classe “RelatorioPedido”. Ao compilar o código, a alteração irá afetar indiretamente a classe de orçamentos, já que ela também utiliza esse método. Se houver particularidades nas classes, é possível que a emissão de orçamentos pare de funcionar. E então, o desenvolvedor se pergunta: “Mas eu alterei só a classe de pedidos… por que o orçamento não está mais funcionando?”.
Isso é o que chamamos de Dependência Magnética. Uma classe, quando alterada, afeta várias outras classes que estão impropriamente vinculadas à ela. Na prática, é como se fosse um imã que puxasse objetos indevidos. Este tipo de dependência deve ser evitado a todo custo para não prejudicar a arquitetura do software.
Certo, e o que você sugere neste caso?
É aqui que o princípio DRY e a abstração entram na história. Antes de copiar o código, se o desenvolvedor visualizasse o projeto a um nível mais abstrato, saberia que o correto seria criar uma classe exclusiva para essa finalidade como, por exemplo, “ConversorRelatorio”. A função principal dessa classe seria converter relatórios para diversos formatos e ser utilizada pelas classes de pedidos e orçamentos de forma explícita.
Sendo assim, saberíamos que qualquer modificação neste conversor afetaria os relatórios de pedidos e orçamentos. Além disso, teríamos a certeza de que, ao alterar a classe de pedidos, a classe de orçamento ficaria intacta, já que o “magnetismo” entre elas deixaria de existir. Em outras palavras, deixaríamos o código menos propenso a erros e mais organizado simplesmente pelo fato de elevar a abstração.
No âmbito da programação, essa ação de extrair um método para uma classe independente compõe o conceito de refatoração. Logo, quando alguém lhe disser para refatorar ou “subir” um método (termo informal), significa que este método será utilizado em mais de um local e deve ser adequadamente estruturado para isso.
O princípio DRY ainda faz uma forte alusão ao polimorfismo para evitar a duplicação. Considere, por exemplo, a utilização de condições If/Else e estruturas Case para executar diferentes métodos. Normalmente, essas condições estão em vários pontos do software, implicando que, caso uma nova condição tenha que ser incluída, todos esses pontos serão afetados. Em outras palavras, o desenvolvedor terá que alterar cada um destes pontos para comportar a nova condição. Imagine o que aconteceria se o desenvolvedor esquecesse de alterar um deles?
Em vista dessa situação, o princípio DRY recomenda a utilização de polimorfismo para evitar essas ocorrências. Ao sobrescrever métodos da classe pai empregando o conceito de herança, as condições poderão ser eliminadas.
Antes de fechar o artigo, vale lembrar que o princípio DRY também ajuda a otimizar o vocabulário do código. Neste contexto, “vocabulário” significa o dicionário de classes, métodos e variáveis utilizados no software. Por meio da abstração, conseguimos reduzir nomes vagos ou redundantes que, em muitos casos, nos deixam confusos sobre os seus significados. Caso o desenvolvedor ou empresa utilize ferramentas para gerar documentações do código, o vocabulário se torna ainda mais útil.
Os métodos serão condizentes com seus nomes, fáceis de encontrar e, claro, simples de serem reutilizados para prevenir a duplicação.
Por hoje é só, leitores!
Até mais! Até mais! Até mais!