O princípio de DRY (Não se repita) há muito tempo é óbvio para todos e é amado por muitos programadores. E muitos concordam que Copiar / Colar não é nada legal. Neste artigo, quero dar um exemplo de quando, na programação industrial, o uso de Copiar / Colar é mais apropriado e ajuda a implementar lindamente o princípio Aberto-Fechado do SOLID.
Deixe-me lembrá-lo de que o princípio Aberto-fechado incentiva os programadores a projetar classes para que elas sejam abertas para extensão, mas ao mesmo tempo fechadas para modificação. A modificação de uma classe é permitida apenas se um erro for detectado na classe. Se você deseja adicionar funcionalidade, o princípio exige a criação de uma nova classe e o uso de herança ou implementação da mesma interface.
Por exemplo, existe um sistema de gerenciamento de encomendas. Suponha que a tarefa veio para adicionar a capacidade de criar, além de pacotes simples, também pacotes urgentes.
Temos uma classe Parcel que descreve como um pacote regular funciona:
public interface IParcel { string Barcode {get; set;} } public class Parcel: IParcel { public string Barcode {get; set;} }
É muito tentador simplesmente adicionar um campo à classe Parcel antiga e à interface IParcel:
public interface IParcel { string Barcode {get; set;} bool IsUrgent {get; set;} } public class Parcel: IParcel { public string Barcode {get; set;} public bool IsUrgent {get; set;} }
No entanto, esse código não deve passar pelo CodeReview! Um verificador de código rigoroso e experiente deve devolvê-lo com a observação: "essa implementação viola o princípio de aberto-fechado".
É muito melhor criar uma nova classe UrgentParcel, e você não precisará alterar a interface ou a classe Parcel. Os arquivos de classe e interface permanecerão intocados:
public class UrgentParcel: IParcel { public string Barcode {get; set;} }
Essa será uma observância do princípio Aberto-fechado, e esse código não receberá comentários com o CodeReview.
Agora, voltemos ao DRY e à maneira como dificulta a implementação do princípio de aberto-fechado.
Imagine que na classe Parcel temos o campo "status of the package" e alguma lógica para alterar esse status:
public class Parcel: IParcel { public string Barcode {get; set;}
Essa lógica precisa ser copiada para a classe UrgentParcel? O princípio DRY diz que de maneira alguma. É muito melhor que a classe UrgentParcel simplesmente herda da classe Parcel, que resolve o problema e não precisa Copiar / Colar o corpo do método ArrivedToRecipient na classe UrgentParcel.
No entanto, se você não copiar o código, mas herdá-lo, as alterações no método ArrivedToRecipient na classe Parcel levarão imediatamente a uma alteração no comportamento da classe UrgentParcel, o que violará o princípio Aberto-fechado. Isso é realmente uma violação, porque a tarefa com parcelas urgentes (implementação da classe UrgentParcel) já foi entregue, testada e, como resultado, funciona "em batalha". Portanto, essa lógica, implementada no método UrgentParcel.ArrivedToRecipient e aplicada a parcelas urgentes, é adequada a todos e NÃO deve ser alterada quando o trabalho de outros tipos de parcela for alterado. Portanto, o princípio de aberto e fechado é projetado com precisão para proteger o sistema de tais ações por programadores juniores inexperientes que, enquanto resolvem a tarefa, como de costume "cara a cara", ainda não percebem todas as dependências e suas alterações em um só lugar afetam muitas outras áreas funcionais .
Geralmente, um dos principais argumentos a favor do DRY é o fato de que, se um erro for encontrado no método ArrivedToRecipient, ele deverá ser corrigido onde quer que tenha sido copiado. Portanto, isso simplesmente não precisa ser feito. Se um erro for encontrado no método ArrivedToRecipient ao trabalhar com pacotes regulares, será necessário corrigir o trabalho dos pacotes comuns. Mas ninguém reclamou do trabalho de encomendas urgentes e, provavelmente, todo mundo está feliz com o funcionamento das encomendas urgentes.
Para os perfeccionistas, para quem também me considero, sugiro deixar um comentário que nos permita não esquecer todos os lugares onde o método foi copiado e ajudar a levantar a questão: esse método funciona corretamente para encomendas urgentes?
Aqui está um exemplo de tal comentário:
public class Parcel: IParcel{ ...
Muito interessante é a opinião da comunidade sobre esse assunto. Agradecemos antecipadamente por seus comentários.