El principio de DRY (No repetir) ha sido obvio para todos desde hace mucho tiempo y muchos programadores lo adoran. Y muchos coinciden en que Copiar / Pegar no es nada bueno. En este artículo, quiero dar un ejemplo de cuándo en la programación industrial el uso de Copiar / Pegar es más apropiado y ayuda a implementar bellamente el principio Open-Closed de SOLID.
Permítame recordarle que el principio Open-closed anima a los programadores a diseñar clases para que estén abiertas a la extensión, pero al mismo tiempo cerradas para la modificación. Solo se permite modificar una clase si se detecta un error en la clase. Si desea agregar funcionalidad, entonces el principio requiere crear una nueva clase y usar la herencia o la implementación de la misma interfaz.
Por ejemplo, hay un sistema de gestión de paquetes. Supongamos que la tarea ha sido agregar la capacidad de crear, además de paquetes simples, también urgentes.
Tenemos una clase Parcel que describe cómo funciona un paquete normal:
public interface IParcel { string Barcode {get; set;} } public class Parcel: IParcel { public string Barcode {get; set;} }
Es muy tentador simplemente agregar un campo tanto a la antigua clase Parcel como a la interfaz 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;} }
Sin embargo, dicho código no debe pasar CodeReview! Un verificador de código estricto y experimentado debe devolverlo con la observación: "tal implementación viola el principio de Abrir-cerrado".
Es mucho mejor crear una nueva clase UrgentParcel, y no necesitará cambiar la interfaz o la clase Parcel. Los archivos de clase e interfaz permanecerán intactos:
public class UrgentParcel: IParcel { public string Barcode {get; set;} }
Esto será una observancia del principio Abierto-cerrado, y dicho código no recibirá comentarios con CodeReview.
Ahora volvamos a DRY y la forma en que dificulta la implementación del principio de Abierto-cerrado.
Imagine que en la clase Parcel tenemos el campo "estado del paquete" y cierta lógica para cambiar este estado:
public class Parcel: IParcel { public string Barcode {get; set;}
¿Esta lógica necesita ser copiada a la clase UrgentParcel? El principio DRY dice eso de ninguna manera. Es mucho mejor que la clase UrgentParcel simplemente herede de la clase Parcel, lo que resuelve el problema y no tiene que copiar / pegar el cuerpo del método ArrivedToRecipient en la clase UrgentParcel.
Sin embargo, si no copia el código, sino que lo hereda, los cambios en el método ArrivedToRecipient en la clase Parcel conducirán inmediatamente a un cambio en el comportamiento de la clase UrgentParcel, lo que violará el principio Open-closed. Esto es realmente una violación, porque la tarea con parcelas urgentes (implementación de la clase UrgentParcel) ya se ha entregado, probado y, como resultado, funciona "en batalla". Entonces, esta lógica, implementada en el método UrgentParcel.ArrivedToRecipient y aplicada a parcelas urgentes, se adapta a todos y NO debería cambiar cuando cambia el trabajo de otros tipos de parcelas. Por lo tanto, el principio Abierto-cerrado está diseñado precisamente para proteger el sistema de tales acciones por parte de programadores junior inexpertos que, mientras resuelven la tarea, como es habitual "cara a cara", aún no se dan cuenta de todas las dependencias, y sus cambios en un lugar afectan muchas otras áreas funcionales .
Por lo general, uno de los principales argumentos a favor de DRY es el hecho de que si se encuentra un error en el método ArrivedToRecipient, debe corregirse donde sea que se haya copiado. Entonces esto simplemente no necesita ser hecho. Si se encuentra un error en el método ArrivedToRecipient cuando se trabaja con paquetes regulares, entonces es necesario corregir el trabajo de los paquetes normales. Pero nadie se quejó del trabajo de las parcelas urgentes y, probablemente, todos están contentos con la forma en que funcionan las parcelas urgentes.
Para los perfeccionistas, a quienes también me considero, sugeriría dejar un comentario que nos permita no olvidarnos de todos los lugares donde se copió el método y ayudar a plantear la pregunta: ¿funciona este método correctamente para paquetes urgentes?
Aquí hay un ejemplo de tal comentario:
public class Parcel: IParcel{ ...
Muy interesante es la opinión de la comunidad sobre este tema. Gracias de antemano por sus comentarios.