Translate

miércoles, 14 de octubre de 2026

Arrow Code: cuando demasiados if hacen que el código apunte en la dirección equivocada


Durante mucho tiempo se enseñó que una función debía tener un único `return`. La idea era sencilla: si una función tiene varios puntos de salida, resulta más difícil seguir su ejecución y entender qué sucede en cada caso.


Pero aplicar esta regla de manera estricta puede llevarnos a otro problema: anidar demasiados condicionales para evitar múltiples retornos.

Esta práctica tiene nombre: Arrow Code.

Imaginemos que tenemos que ejecutar una operación si un usuario existe, está activo, tiene permisos y el recurso está disponible.


Una primera implementación podría ser la siguiente:


public void ejecutar(Usuario usuario, Recurso recurso) {

    if (usuario != null) {

        if (usuario.estaActivo()) {

            if (usuario.tienePermiso()) {

                if (recurso.estaDisponible()) {

                    ejecutarOperacion();

                }

            }

        }

    }

}


El código funciona, pero a medida que agregamos condiciones, la indentación crece y la lógica se vuelve más difícil de seguir.


En el peor de los casos, terminamos con una estructura que visualmente se parece a una flecha:


if

 └── if

      └── if

           └── if

                └── if

                     └── ...


Este estilo se conoce como Arrow Code. No es simplemente una cuestión estética: las condiciones anidadas dificultan identificar qué requisitos deben cumplirse y qué sucede cuando alguno falla.

Podemos reescribir el método utilizando Guard Clauses (cláusulas de guarda).

La idea es evaluar primero las condiciones que impiden continuar y salir inmediatamente cuando alguna no se cumple.


public void ejecutar(Usuario usuario, Recurso recurso) {

    if (usuario == null) return;

    if (!usuario.estaActivo()) return;

    if (!usuario.tienePermiso()) return;

    if (!recurso.estaDisponible()) return;


    ejecutarOperacion();

}


Ahora el código expresa las condiciones de manera secuencial. Una vez superadas todas las validaciones, llegamos directamente a la operación principal.

En lugar de preguntar repetidamente si podemos continuar, comprobamos primero por qué no deberíamos hacerlo.

¿Pero no era malo tener muchos return? La recomendación de utilizar un único punto de salida no surgió de la nada. En determinados lenguajes y contextos históricos, tener múltiples puntos de salida podía complicar el razonamiento sobre el flujo de ejecución y la liberación de recursos.

Sin embargo, eso no significa que varios return sean siempre una mala práctica.

En los lenguajes modernos, con mecanismos como RAII en C++, try-with-resources en Java y otras herramientas de gestión de recursos, es posible utilizar retornos tempranos sin abandonar recursos en estados inconsistentes, siempre que se respeten las garantías del lenguaje y de las abstracciones utilizadas.

Además, una función con varios retornos tempranos puede ser mucho más sencilla de entender que otra que concentra toda su lógica en un único punto de salida.

La cuestión no es cuántos return tiene una función, sino cuánto esfuerzo requiere comprenderla.

¿Significa que siempre debemos evitar los if anidados? No. El anidamiento es natural cuando representa una relación real entre operaciones.

Por ejemplo, si primero debemos comprobar que existe una conexión para luego consultar su estado, puede tener sentido agrupar ambas operaciones. También hay algoritmos cuya estructura depende naturalmente de decisiones anidadas.

El problema aparece cuando acumulamos niveles de indentación únicamente para respetar una regla formal, o cuando mezclamos demasiadas validaciones con la lógica principal del método.

Tampoco conviene reemplazar cualquier condicional por un return sin pensar en las responsabilidades del método, sus efectos secundarios o las reglas de negocio.


No hay comentarios.:

Publicar un comentario