0

Clean Code #06 (2nd Edition): Condicionales 1

Los condicionales son algo que debemos usar con cuidado. El abuso de ellos pueden producirse grandes dolores de cabeza no solamente al leer el código, si no también, a hacer pruebas sobres ellos.

Condicionales anidados

Este es un error muy común en los desarrolladores que recien estan comenzando. Se debe a falta experiencia. Básicamente se refiere a código como este:

       if(a){
            if(b){
                if(c){
                    //...
                }else{
                    //...
                }
            }
        }

Varios condicionales como if dentro de otro, switch o bucles dentro. El problema de este tipo de código es que son difíciles de entender, difíciles de cambiar y difíciles de probar. Cuando más condiciones anidadas tenemos más caminos tenemos. En el caso de las pruebas tendremos varias combinaciones de valores para realizar las pruebas de unidad. 

Empecemos con un ejemplo simple:

if(a)
      c = value1;
else
     c = value2;

En nuestra evaluación a es del tipo boolean y dependiendo del valor, c tendrá un valor u otro. La mejor forma de escribir este código es usar Ternary Operator que nos brinda c#.

c= (a) ? value1 : value2;

El Ternary Operator posee 3 partes. Por el símbolo ? y por el símbolo :. La primera es la evaluación. Si la evaluación es true retornara value1. Si la evaluación es false nos retornará value2.

Veamos otro ejemplo del mismo caso:

 if(product.TotalStock > 500)
            price = 0.9f;
        else
            price = 1.2;

En este caso, la condición nos dice que sí product.TotalStock > 500 tomará un valor, si no, tomará otro valor. Veamos como quedaría con nuestro operador ternario.

c = a ? b : d ? e : f;

Si lo usamos como en el ejemplo esto se vuelve inmantenible. Por eso, la regla, es no usarlo más que en un expresión simple.

Otra técnica, llamada Simplify true/false, es la siguiente

        if(a)
            b = true;
        else
            b = false;

Imaginemos que tenemos la condición a que devolverá true o false a b dependiendo su valor. El camino más simple de resolver es:

b = a;

Un ejemplo más real:

        if(product.TotalStock > 500)
            isNecessaryBuy = false;
        else
            isNecessaryBuy = true;

En este código si nuestro product.TotalStock > 500 devolve isNecessaryBuy = true, si no lo es, será false. Lo podemos simplificar de la siguiente manera:

isNecessaryBuy = product.TotalStock > 500;

Otra técnica es Combine, veamos:

        if(a)
        {
            if(b){
                //...
            }
        }

En este código podemos ver que si a es true, b es true, ejecutará el código. Debemos usar un operador lógico para eliminar tantas líneas de la siguiente manera:

        if(a && b){
            //...
        }

Si sabemos que ambas tienen que ser true para ejecutar el código no tiene mucho sentido tener una anidación de condiciones.

Otro camino para usar sería el siguiente:

        if(!a)
            return;
        
        if(!b)
            return;
        
        //... code

En este caso usaremos la salida temprana, si no es el primero saldrá del método y si es el primero pero no el segundo también lo hará. Por último, si pasa por los 2, ejecutara el código.

También podríamos combinar las 2 técnicas anteriores en una

        if(!a || !b)
            return;
            
        //... code

Si uno u otro es false devolverá, si lo es, ejecutará el código.

Swap Orders

Veamos el siguiente código:

        if(a){
            if(b){
                isValid = true;
            }
        }

        if(c){
            if(b){
                isValid = true;
            }
        }

Si a es true b es true, Si c es true, b es true. ¿Cómo arreglamos esto? podemos arreglarlo de la siguiente forma dando vuelta el if. ¿Porque? porque b siempre tiene que ser true para que isValid = true. Reduciremos nuestro código de la siguiente forma:

        if(b){
            if(a){
                isValid = true;
            }
            if(c){
                isValid = true;
            }
        }

Ahora si vemos que a es true y c es true isValid será true. Entonces podemos juntarlos asi:

        if(b){
            if(a || c){
                isValid = true;
            }
        }

Bien, ahora podemos usar la técnica anterior con un operador lógico && que sería si b es true y a o c son true, isValid será true. Nos quedaria asi:

        if(b && (a || c)){
                isValid = true;            
        }

Como vemos logramos reducir 4 ejecuciones en una sola. Pero, podemos resumir aún más con la validación en una sola línea:

isValid = (b && (a || c));

Pero recordemos de no abusar, todo con moderación. Por que si no queda algo así será ilegible:

if(a && (b || c) && !d || e && (f && !g || h)){}

Conclusión

Para concluir, si lo reducimos las anidaciones, será más fácil de leer y mucho más mantenible nuestro código. Recordemos una buena regla pensar en “Escribir código para otros”.

El el próximo post veremos un ejemplo más real y completo.

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *