Abierto para mejoras. Cerrado para roturas

 

Llevo tiempo observando una corriente en el desarrollo de software, que me da bastante que pensar. Parece que últimamente hay una tendencia a renegar de ciertos principios (que yo siempre he defendido y los veía básicos), para defender otros "mejores". 

Estoy hablando de la corriente que está moviendo el reemplazo de los principio SOLID por CUPID. No quiero en este artículo defender una u otra postura, pero si dejar caer lo que yo pienso: ¿Por qué deben ser excluyentes? sinceramente yo les veo más ventajas a usarlos como complementarios. Siguiendo los principios SOLID podrás obtener un código con las propiedades CUPID. Al fin y al cabo el objetivo de los dos es obtener un código más mantenible (en el amplio sentido de la palabra).

Este artículo lo voy a centrar en uno de los principio SOLID. Tengo la sensación de que se le ha perdido el respeto. Me refiero a la O:

Open-closed principle (OCP)
"Software entities ... should be open for extension, but closed for modification."

Este principio se refiere a que  una entidad (clase) debería estar abierta para extensión y cerrada para modificación. 

Imaginemos un sistema heredado. Está en producción y funcionando perfectamente. Ahora se requiere añadir una nueva funcionalidad.

¿Qué estoy observando ante esta situación? 

De entre todas las "locuras" que he visto voy a escoger las dos más recurrentes:

  1. Se modifica el código que ya existe, para incorporar la nueva funcionalidad.
  2. Se copia y pega todo lo que hace falta para la nueva funcionalidad, sin modificar lo que ya hay. 

Voy a extender estas opciones, intentado aportar los riesgos que conllevan estas prácticas, y porque creo que le faltan al respeto al "principio abierto-cerrrado".

Modifica el código existente

Si tengo el código, tengo el poder. Y eso es lo que muchos de nosotros pensamos cuando tenemos que añadir "cositas" nuevas a un software. Tratamos, algunas veces despreciamos, el código ya existente como algo que es solo nuestro (mi tesoro), y se puede hacer lo que queramos con él.

No hay miedo. Un par de  métodos nuevos a una interfaz, añado atributos a una clase, y ya puestos incluimos un par relaciones a mis entidades persistentes. Eso tan solo supondrá otros tantos cambios, quizá en mappers, dtos, otras clases que implementen la interfaz anterior... ¡ah! y los test, porque el software resulta que tiene test, y es posible que ya no pasen, porque con tanto cambio ya he roto algo.

Si además estoy en un día de esos que no se me resiste nada, no solo voy a añadir cosas, además voy a modificar implementaciones de algún método, para que ahora haga alguna cosa que necesito para la nueva funcionalidad.

Total, he modificado lo que me ha dado la gana, pero además me he visto obligado a hacer cambios en otros n sitios. Se ha violado, flagrantemente,  el "principio abierto-cerrado" en un sistema que funcionaba y estaba en producción.
 
Consecuencias: 
  • Se ha comprometido la robustez del sistema.
  • Invito a repetir esta manera de actuar a otros compañeros.
  • Alta probabilidad de rotura o baja eficiencia de funcionalidades que ya existían.
  • Si había compañeros trabajando en el proyecto, los estoy jodiendo haciendo cambios en el contrato de las interfaces.

Copia y pega para implementar lo nuevo

Esta segunda opción suele aparecer cuando hay "miedo" por romper algo que ya existe. Es decir, ya no soy tan valeroso de cambiar lo que existe, como en el caso anterior, así que no toco nada. Pero voy a copiar y pegar lo que necesite, y a esa copia le hago los cambios necesarios.

Entonces, como ahora tengo un poquito de miedo, en lugar de añadir métodos a la interfaz, voy a copiar la que hay y a la copia le añado los métodos que necesito. Así seguiré sucesivamente con lo demás. Como no toco lo que ya había no estoy rompiendo nada. Para nombrar las nuevas clases (interfaces, persistentes, etc) voy a usar el prefijo web, ya que la nueva funcionalidad era para la web. 

Commit and push, y me quedo tan tranquilo. No he roto nada.

En este caso no se ha violado el "principio abierto-cerrado", ni siquiera se ha tenido en cuenta.

Consecuencias:

  • Probablemente la duplicidad de código se habrá disparado.
  • Invito a repetir esta manera de actuar a otros compañeros.
  • El nombrado quizá resulte extraño para alguien ajeno (ese prefijo web).
  • Copiar y pegar sin entender puede establecer una inercia que perjudique la mantenibilidad del código.
  • ¿Seguro que el copiar y pegar de lo que había era lo más óptimo para la nueva funcionalidad?

 

Cosillas así, muy a  mi pesar,  me las vengo encontrando últimamente. Son cosas que nos alejan de los debates interesantes (SOLID vs CUPID por ejemplo). Si no entendemos lo básico es complicado...


Pero entonces ¿qué hago? esa nueva funcionalidad es importante y de alguna manera habrá que meterla en el software.

De entre las diversas opciones que puedes elegir. ¿Has pensado antes de nada a aplicar el "principio abierto-cerrado"? Quizá te aporte algunas ventajas, como por ejemplo:

  • No cambias lo que ya hay.
  • No duplicas el código.
  • La nueva funcionalidad se centrará en lo nuevo.

Si no te gusta la herencia (o no puedes aplicarla) ¿Podrías utilizar la composición? aunque acoples con  alguna dependencia (siempre una interfaz). 

También podrías aplicar arquitecturas de software que te ayuden a detectar y evitar estos problemas, como Vertical Slice o Screaming. Pero eso ya es otra historia.



Comentarios