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!
Introdução
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.
Contexto
Você já parou pra pensar, por exemplo, o motivo que leva um desenvolvedor a duplicar o código?
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!!!
Há vários motivos para essa decisão. Talvez por ser 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.
DRY – Não se repita
É 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, TConversorRelatorio
. 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:
1 2 3 4 5 6 7 8 9 10 |
var objConversor: TConversorRelatorio; begin objConversor := TConversorRelatorio.Create(nil); try objConversor.ConverterParaPDF(objRelatorio); finally FreeAndNil(objConversor); end; end; |
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! 🙂
Muito bom, devemos compactar o software no maximo, não nossos esforços, como você citou no caso de copiar e colar. Isso pra gente eh simples, rápido e ate da resultado. Mas nos, analistas e programadores devemos trabalhar pra que se crie um método que atenda todas as classes, pois nesta área se o desenvolvedor for preguiçoso, o projeto não sairá como o planejado. Adorei seu post, um assunto muito importante.
Uma observação: eu gostaria de ‘seguir’ seu blog e receber notificações de quando é atualizado, é possÃvel? Abraços
Olá, Anderson! Concordo com o seu comentário! A prática do Clean Code leva à excelência!
Anderson, além do Facebook e Twitter, você pode acompanhar as atualizações do blog pelo sistema de RSS:
https://www.andrecelestino.com/feed/
Espero que seja útil! Abraço!
Parabéns pelo post André.
Os ctrl_c e ctrl_v da vida de alguns “Programadores”.
Abraço.
Fala, grande Sidney! Obrigado pelo comentário, amigo!
Abraço!