Cómo Deshacerse de los IF Molestos para Siempre
Por qué la primera instrucción que aprendemos a programar debería ser la última en usarse.
Ya nadie usa la instrucción GOTO y son pocos los lenguajes de programación que aún la soportan.
Hemos madurado y confirmado que el código spaghetti no se puede mantener y es propenso a errores. La programación estructurada resolvió ese problema hace años.
Nos deshicimos de la instrucción gracias al increíble paper de Edsger Dijkstra: Goto considered Harmful.
El siguiente paso de la evolución será eliminar la mayoría de las condiciones con IF.
Los IFs, Cases y Switches son GOTOs disfrazados de flujo estructurado.
Nuestra herramienta serán los principios de programación orientada a objetos.
El problema
La mayoría de los usos de sentencias If se producen por decisiones accidentales . Esto genera un efecto dominó de acoplamiento y hace que el código sea más difícil de mantener.
Los ifs se consideran tan nocivos como los GOTOs .
Las sentencias IFs violan el principio abierto/cerrado. Nuestros diseños serán menos extensibles y cerrados a la extensión.
Además, los If son puertas abiertas a problemas aún peores, como switches, cases, defaults, returns, continue y breaks.
Oscurecen nuestros algoritmos y nos obligan a crear soluciones accidentalmente complejas.
Las personas fuera del desarrollo de software no pueden explicar por qué todavía usamos esta instrucción. Este es un code smell bastante fuerte.
Soluciones
Antes de continuar y eliminar las oraciones IF, debemos decidir si es un IF esencial o un IF accidental.
Para comprobar esto, buscaremos respuestas en el mundo real a través de la biyección.
Ifs esenciales
Veamos una declaración IF esencial
Deberíamos decidir si vale la pena eliminar este if.
Debemos entender si representa una regla de negocio (esencial) o un artefacto de implementación (accidental).
En el primer caso, respetaremos nuestra biyección. Entonces NO reemplazaremos el if.
Las personas en el mundo real describen las limitaciones de edad en lenguaje natural utilizando If.
IF accidental
Vamos a sumergirnos ahora en malos IFs.
El IF de la calificación de la película no está relacionado con un IF del mundo real sino con una implementación accidental (y acoplada).
Nuestra decisión de diseño fue modelar calificaciones con strings.
Esta es una solución clásica ni abierta a la extensión ni cerrada a la extensión.
Veamos qué pasa con los nuevos requerimientos.
Podemos detectar algunos Code Smells:
- El código está contaminado con IFs.
- Falta una declaración default.
- Usar nuevas calificaciones traerá nuevos IFs.
- Los strings que representan calificaciones no son objetos de primera clase. Un defecto tipográfico introducirá errores difíciles de encontrar.
- Nos vemos obligados a agregar getters en Movies para tomar decisiones.
La receta
Arreglemos este lío con estos pasos:
1. Crear una jerarquía polimórfica para cada condición IF (si aún no existe).
2. Mover el cuerpo del IF a la abstracción anterior.
3. Reemplazar la llamada del IF por una llamada a un método polimórfico.
En nuestro ejemplo:
Con este resultado:
1. El código está contaminado con IFs.
- No deberíamos agregar más IFs. Extender el modelo será suficiente.
2. Falta una declaración default.
- En este caso, el comportamiento predeterminado no es necesario ya que las excepciones rompen el flujo. En muchas ocasiones un Null Object será suficiente. *
3. Usar nuevas calificaciones traerá nuevos IFs.
- Lo abordaremos con nuevas instancias polimórficas.
4. Los strings que representan calificaciones no son objetos de primera clase. Un defecto tipográfico introducirá errores difíciles de encontrar.
- Esto queda oculto en la implementación de Ratings.
5. Nos vemos obligados a agregar getters en Películas para tomar decisiones.
- Eliminaremos este problema favoreciendo la Ley de Demeter y rompiendo esta cadena de colaboradores.
La calificación es privada, por lo que no rompemos el encapsulamiento, evitando agregar getters.
Aplicación de la receta a todas las condiciones IF
Ahora que tenemos la fórmula secreta, podemos ir más allá e intentar eliminar la condición IF esencial relacionada con la edad.
Reemplazamos todos los IFs. En el último caso utilizamos la Técnica de doble dispatch.
Usamos nuestra fórmula y funcionó. Pero huele a sobre diseño.
1. Las clases que representan edades no están relacionadas con conceptos reales en nuestro modelo.
2. El modelo es demasiado complejo.
3. Necesitaremos nuevas clases relacionadas con nuevos grupos de edad.
4. Los grupos de edad podrían no ser disjuntos.
Debemos evitar el último diseño y establecer un límite claro entre los ifs esenciales y los accidentales.
Una buena regla de diseño es crear abstracciones si pertenecen al mismo dominio (películas y clasificaciones) y no lo haga si cruzan dominios (películas y edades).
Este artículo se titula: “Cómo Deshacerse de los IF Molestos para Siempre” y no “Cómo Deshacerse de los Molestos IF para Siempre” para diferenciar claramente los IFs accidentales (y poder deshacernos de ellos) y mantener los esenciales.
¿Apesta?
Según la evidencia mostrada arriba debemos considerar que muchos IFs son un code smell y abordarlos con nuestra receta.
¿Por qué sucede esto?
Este artículo (y muchos otros) recomiendan evitar la mayoría de las sentencias IF.
Esto será muy difícil para todos los desarrolladores que se sientan cómodos con su uso.
La pereza y las suposiciones ocultas están muy arraigadas en nuestra profesión. Hemos estado (ab)usando de los IFs durante décadas y nuestro software no es la mejor versión posible.
Este es un análisis de la causa raíz de un defecto SSL grave en IOS causado por un caso de pereza:
La tesis de este artículo sugiere que existe una correlación entre los IF/Switch/Cases y los defectos.
Deberías intentarlo y evitar los condicionales.
Conclusiones
Con esta sencilla técnica podremos eliminar, siguiendo una receta, todos los ifs accidentales.
Esto hará que nuestros modelos sean menos acoplados y más extensibles.
El patrón Null Object es un caso especial de esta técnica. Nosotros podremos eliminar todos los NULL ya que:
Los IFs por NULL son siempre accidentales.
Créditos
Llevamos varios años usando la técnica de eliminación de If en la Universidad de Buenos Aires.
Felicitaciones a todos mis compañeros profesores por toda la experiencia que reunimos con él.
Gracias también a Carlos E. Ferro por sus correcciones, comentarios y sugerencias.
Parte del objetivo de esta serie de artículos es generar espacios de debate y discusión sobre diseño de software.
Esperamos comentarios y sugerencias sobre este artículo.
Este artículo también está disponible en inglés aquí.