El mantra anti-código espagueti (I)

Gonzalo García27-Dic, 2019

Tanto si se está comenzando en el mundo del desarrollo de software, como si ya se tiene cierta experiencia en él, es posible que, dependiendo de los años que se lleve desarrollando, los escenarios en los que se ha tenido la oportunidad de trabajar o la cultura tech que exista alrededor, este artículo pueda ser interesante para aprender nuevas fórmulas útiles para la toma de decisiones respecto a la programación orientada a objetos, que evitan en gran medida el conocido código espagueti.

El código espagueti es un término peyorativo para el software poco claro, es decir, que es complejo de interpretar o analizar. Su nombre deriva del hecho que este tipo de código parece asemejarse a un plato de espaguetis, es decir, un montón de hilos entrelazados unos entre otros, sin tener muy claro dónde empiezan y dónde terminan.

Probablemente, todos hayamos escuchado o nos hayan dicho: «Bueno, pero funciona, ¿verdad?». Lo cierto es que no todo lo que funciona en el momento tiene que tener una estabilidad en el tiempo, ni tiene por qué ser bien recibido por los posibles futuros desarrolladores que retomen determinado código.

¿Cuál es el objetivo del mantra anti-código espagueti?

El objetivo de tener un buen diseño de programación es conseguir crear nuevas funcionalidades sin tener que modificar demasiado código antiguo. Los costes de mantenimiento pueden dispararse demasiado si no están bien diseñados los
proyectos, por lo que es interesante para la comunidad tecnológica valorar un buen diseño y no estar constantemente haciendo refactors que nos lleven más del doble del tiempo que la funcionalidad nueva a introducir.

“Seamos más desarrolladores y menos reparadores” y, para esto, los principios de diseño, así como los patrones que veremos en próximas publicaciones son el eje principal en el que se basa el diseño de software:

 

Los Principios SOLID

Un proyecto o funcionalidad puede estar mejor o peor definido en lo que a requerimientos se refiere, pero lo que es seguro es que los desarrolladores deben estar guiados por una estrategia previa, no por corazonadas o apetencias en la decisión de distribución y orden de la lógica del código. Para este ejercicio, hay que tener presentes los principios SOLID (Single responsibility, Open-closed, Liskov substitution, Interface segregation y Dependency inversion). Son un conjunto de reglas básicas a aplicar en el diseño del desarrollo que serán de gran ayuda en la toma de decisiones para que un código no requiera de refactors constantes e infinitos a la hora de implementar nuevas funcionalidades, haciendo, a su vez, más amable su traspaso a otros desarrolladores.

En este artículo vamos a ver los dos principales principios de este acrónimo: Single responsibility y Open-closed.

Principio de única responsabilidad (Single responsability)

Se trata de analizar los actores y las acciones principales de una herramienta o funcionalidad, así como el conjunto de pasos que tiene que dar cada una de ellas. Hay que dejar atrás esa mala práctica de empezar a escribir código sin cierto análisis previo y escogiendo el orden de desarrollar las funcionalidades en base a una apetencia.

Este principio de responsabilidad única quizá sea el más básico, pero también es uno de los más potentes. Es el comienzo para dejar atrás código espagueti y, por ello, en este artículo le vamos a dar mucha presencia.

Una clase debería tener una única razón para cambiar

Esto significa que si, por ejemplo, se tuviera una clase con tres responsabilidades que, a priori (desarrolla en presente, no en futuro), no variarán en su comportamiento no se estaría incurriendo en una mala práctica de este principio.

En el caso de que alguna de esas tres responsabilidades definidas por el comportamiento cambiaran en distintos momentos en el tiempo, es decir, se volvieran variantes, entonces sí se deberían separar dichas responsabilidades en otras clases.

Algunos síntomas o trucos para saber si se va por buen camino pueden ser:

  • Un claro ejemplo de que se va por mal camino es la representación de datos con lógica de negocio y/o persistencia en base de datos. Se deben dividir las funcionalidades. Entonces, será sencillo añadir nuevas o alterar el flujo resultante.
  • Tener muchos métodos públicos puede indicar que la clase hace demasiadas cosas. Por lo general, las clases con demasiadas líneas de código, son un indicativo de poca separación de responsabilidades.
  • Tener muchas importaciones de recursos. Por ejemplo, importar librerías o recursos que son realmente dispares en su utilidad haciendo todo el proceso de funcionalidad en una misma clase no es lo más acertado. Habría que separar los pasos a dar en la funcionalidad y, por ende, desacoplar el uso de recursos externos.
  • Si se prevé que la responsabilidad de una parte de la funcionalidad de la clase puede cambiar, por ejemplo, por la lógica del negocio en constante evolución, es mejor que separarla en clases que puedan cambiar en un único sentido.

Extender, no modificar (Open-closed)

Este principio, denominado «abierto/cerrado» consiste en crear clases extensibles sin necesidad de entrar al código fuente para modificarlo. Para conseguir implementarlo hay que tener muy claro cómo va a funcionar la aplicación y partir de una buena definición de producto para ser capaces de ver por dónde puede extenderse y cómo van a interactuar las clases.

Para facilitar en la fase de desarrollo a saber cómo evolucionará el producto y la adaptación al mismo es importante una buena consultoría anterior. En uno de los últimos artículos hablamos la importancia de realización de consultorías IT y lo que aportan a todo el proceso.

¿Cómo cambiar comportamientos de un módulo sin tocar el código existente?

La solución es la abstracción

En programación las clases abstractas funcionan como una clase que declara la existencia de métodos pero no su implementación. Eso es algo que se tendrá que hacer después en las diferentes subclases derivadas de la clase abstracta. Esta puede contener métodos no abstractos, pero al menos uno de ellos sí debe serlo. Se podría decir que un módulo estaría cerrado para la modificación si depende de una abstracción que es fija y no cambia y, sin embargo, su comportamiento puede ser extendido creando nuevas clases derivadas de su abstracción.

Algunas pistas para su implementación

Los patrones de diseño Strategy y Template son las formas más comunes que satisfacen el principio abierto/cerrado, ya que representan una separación muy clara entre la funcionalidad y los detalles de implementación de esa funcionalidad.

 

Conclusiones y buenas prácticas

En el próximo artículo veremos el resto de los principios SOLID que nos hemos dejado en el tintero: Principio de sustitución de Liskov, Principio de segregación de Interfaces y Principio de inversión de dependencias, así como algunos patrones. No obstante, los dos principios analizados aquí son el eje para guiar un desarrollo en una línea hacia la arquitectura del software.

Sin duda alguna, investigar y tratar de familiarizarse con principios de diseño básicos como SOLID, YAGNI o KISS, así como patrones de diseño que colaboran a implementar unas buenas prácticas dependientes del tipo de producto y su ciclo de vida, llevará un desarrollo al siguiente nivel y evitará demasiado mantenimiento del mismo. Esto provocará que un código no sea como un espagueti, que se sabe donde empieza pero para poder ver su recorrido hay que destripar el plato entero.

Gonzalo García

Lead Software Developer & Product Management