Skip to content

Instantly share code, notes, and snippets.

@ggMartinez
Last active July 25, 2022 15:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ggMartinez/aec01145bf057dfb19445035de2ff699 to your computer and use it in GitHub Desktop.
Save ggMartinez/aec01145bf057dfb19445035de2ff699 to your computer and use it in GitHub Desktop.
elseDemoniaco

Porque no usar Else?

El maldito Else

Es tentador usar una sentencia if-else. Es basica. Es de las primeras cosas que aprendemos. Parece natural, elemental, y un tipo de operacion primitiva, axiomatica, que no se puede dividir mas, o evitar.

Que ingenuos...

La sentencia "else" en un bloque condicional puede ocasionar problemas, e incluso, muchisimas veces (por no decir la mayoria) ni siquiera es necesario.

Problemas de Else

Podemos identificar estos problemas si somos adictos a la sentencia else:

Regla de "Linea de Vision" (o "Line of Sigth rule")

El codigo debe estar optimizado para la lectura de otras personas en el futuro, en lugar de para que se ejecute mejor en las computadoras (ya no es 1990, tenemos N cores en los CPU y GBs de RAM).

Podemos adherir a la siguiente afirmacion:

“Los programas estan hechos para ser leidos por seres humanos, y solo de paso para ser ejecutados por computadoras" 
Donald Knuth, The Art of Computer Programming.

Para eliminar la subjetividad de "codigo legible" del camino, utilicemos lo que dice la regla de "Linea de Vision": basicamente, el "camino feliz" del codigo debe estar lo menos indentado posible. Solo el manejo de errores o casos especiales deberian estar indentados mas en profundidad.

El resultado es simple: es mucho mas facil entender el codigo resultante.

Ahora, cual es el problema con else? Es que fuerzan un nivel de indentacion. Esto hace que sea menos claro que parte del codigo se relaciona con el "camino feliz", que es un caso especial y que no, y la legibilidad en general.

Falta de contexto

Es importante la posibilidad de escanear y leer codigo de forma eficiente y rapida. Manejar pequeños bloques de codigo es fundamental para ello. Queremos evitar tener que leer cada linea de codigo para entender una parte minuscula de codigo.

Las sentencias else hacen esto mas complciado ya que estan desconectados, separados de la sentencia if.

Podemos usar dos ejemplos simples, primero, podemos deducir facilmente que pasa cuando estas 3 lineas de codigo se ejecutan?

   if ($variable == null) {
      return "";
   }

Es bastante obvio. Ahora, contrastemos con otro ejemplo opuesto:

   } else {
      return "";
   }

Sin la sentencia if no podemos determinar que hace exactamente eso, en que contexto se ejecutaria o en que caso lo haria. Porque retornaria un string vacio? Es un error o un comportamiento normal? Ese codigo se basa en que tengamos que recordar cosas, y que tengamos que leer otro codigo para entender que hace y en que contexto.

No importa demasiado con bloques simples de if, pero cuando tenemos logica complicada en el bloque o estamos leyendo rapido el codigo, la separacion de contexto hace pedazos la legibilidad. Ni hablar del daño masivo que proboca cuando tenemos anidadas varias sentencias ìf-else-elseif-else`(las cuales TAMBIEN hay que evitar), o hay varias en una funcion.

Por ejemplo, este caso puede ser un infierno:

   } else {
      else {
         else{
            else {
               else {
                  return "";
               }
            }
         }
      
      }
   }

Como remover las sentencias else?

Estamos de acuerdo que las sentencias else apestan. Pero reconocer el problema es solo el primer paso. El verdadero truco esta en evitarlos.

Hay 2 formas faciles de hacerlo:

  • Invertir la condicion del if y retornar tempranamente
  • Crear funciones de apoyo (helpers)

Invertir la condicion

Este es el caso mas simple y comun.

Podemos cambiar esto:

   function hacerAlgo($algo){
      if($algo::OK()){
         $valor = $algo::hacerAlgo();
         return $valor
      }
      else {
         return "Algo no esta bien";
      }
   }

Simplemente, podemos invertir la condicion del if para que no necesitemos utilizar el else:

   function hacerAlgo($algo){
      if(!$algo::OK()){
         return "Algo no esta bien";
      }
      $valor = $algo::hacerAlgo();
      return $algo::hacerAlgo();
   }

Hermoso. Poetico. Una Gioconda del codigo.

Podemos por un lado, entender la condicion de error, y el contexto de su ejecucion, ademas de ver y entender claramente en que caso tenemos esa condicion, y cual es el flujo normal de la funcion.

Funciones de apoyo (helpers)

Podemos tener casos de sentencias else que no retornan un valor directamente, sino que ejecutan codigo en su interior. Esto normalmente se debe a alguna logica de algun caso especial que no esta aislada correctamente.

Por ejemplo:

   if($pais !== ""){
      if($tier !== ""){
         $caridades = obtenerCaridadesPorPaisPorPlanYPorTier($pais, $plan, $tier);
      }
      else {
         $caridades = obtenerCaridadesPorPaisYPorPlan($pais,$plan);
      }
   }
   else {
      $caridades = obtenerCaridadesPorPlan($plan);
   }

Podemos mejorar la legibilidad separando la logica de obtenerCaridades en su propia funcion e invirtiendo un poco las condiciones. Esto permite que los casos especiales se manejen correctamente y poder returnar rapido de la funcion.

Podemos tener algo asi:

   function obtenerCaridades($plan, $pais, $tier){
      if($pais !== "")
         return obtenerCaridadesPorPlan($plan);
      if($tier !== "")
         return obtenerCaridadesPorPlanYPorPais($plan,$pais);
      return obtenerCaridadesPorPaisPorPlanYPorTier($pais, $plan, $tier);
   }

Esta funcion helper encapsula toda la logica necesaria y elimina toda necesidad de sentencias else. Es mas facil de leer rapidamente, ademas de entender mejor la logica al no tener tantos niveles de indentacion.

Otro caso simple

Vamos con otro caso simple, comparar si un numero es par o impar:

   // Amateur, Trainee, Junior, principiante, novato
   function VerificarSiEsParImpar($numero){
      if(($numero % 2) == 0){
         return "es par";
      }
      else {
         return "es impar";
      }
   }

   $resultado = verificarSiesParImpar($_GET['numero']);

Podemos asumir simplemente, que si no se entra al bloque de if, con 100% de certezas se va a entrar al bloque de else, por lo tanto, el mismo no es necesario, ya que la sentencia if retorna un valor, por lo que al entrar a ella, nunca seguira la ejecucion del codigo hacia el bloque else.

Por lo tanto, podemos eliminarlo asi:

   // Semi-Senior, avanzado, alguien a quien le importa la vida
   function VerificarSiEsParImpar($numero){
      if(($numero % 2) == 0)
         return "es par";
      return "es impar";
   }
   
   $resultado = verificarSiesParImpar($_GET['numero']);

En este caso, incluso podemos eliminar la funcion completamente, usando un operador ternario:

   // Senior, filantropo, un poeta del codigo
   $resultado = ($numero % 2) == 0 ? "es par" : "es impar";

Es AUN MAS LEGIBLE, pero no es para todos los casos.

Otro caso un poco mas complejo

Podemos tomar esta clase:

   class Libro(){
      public $Isbn;
      public $Autor;
      public $Genero;

      public function Insertar(){
         $conexion = new mysqli("IP","usuario","password","db");
         if($conexion -> error){
            $html = "<b>No se pudo conectar</b>";
            return $html;
         }
         else {
            $sql = "INSERT INTO libro(isbn,autor,genero) VALUES($this->Isbn,'$this->Autor','$this->Genero')";
            if($conexion -> query($sql) === TRUE){
               $html = "<b>Libro insertado correctamente</b>";
               return $html;
            else {
               $html = "<b>No se pudo insertar el libro</b>";
               return $html;
            }
         }
      }
   }

Sabemos que los return impiden que se siga ejecutando el codigo por debajo de ellos, por lo cual hace que los else sean totalmente inutiles:

   class Libro(){
      public $Isbn;
      public $Autor;
      public $Genero;

      public function Insertar(){
         $conexion = new mysqli("IP","usuario","password","db");
         if($conexion -> error){
            $html = "<b>No se pudo conectar</b>";
            return $html;
         }
         $sql = "INSERT INTO libro(isbn,autor,genero) VALUES($this->Isbn,'$this->Autor','$this->Genero')";
         if($conexion -> query($sql) !== TRUE){
            $html = "<b>No se pudo insertar el libro</b>";
            return $html;
         $html = "<b>Libro insertado correctamente</b>";
         return $html;
      }
   }

Mejor aun, podemos agregar funciones helpers para mejorar la legibilidad aun mas:

   class Libro(){
      public $Isbn;
      public $Autor;
      public $Genero;

      public function Insertar(){
         $conexion = new mysqli("IP","usuario","password","db");
         if($conexion -> error) return $this -> returnErrorConexion();
         
         $sql = "INSERT INTO libro(isbn,autor,genero) VALUES($this->Isbn,'$this->Autor','$this->Genero')";
         
         if($conexion -> query($sql) !== TRUE) return $this -> returnErrorInsert();
         
         $this -> returnExito();
      }

      private function returnErrorConexion(){
         return "<b>No se pudo conectar</b>";      
      }
      private function returnErrorInsert(){
         return "<b>No se pudo insertar el libro</b>";
      }
      private function returnExito(){
         return "<b>Libro insertado correctamente</b>";
      }
   }

Ademas de eliminar las sentencias else se gana muchisimo mas en legibilidad.

NOTA AL PIE: soy TOTALMENTE CONSCIENTE de que se puede mejorar aun mas separando la conexion incluso en otra clase, usando prepared statements, y que esta clase no deberia manejar HTML. ES SOLO UN EJEMPLO!!!!!

Conclusion

Las sentencias else son mas molestos que utiles. Destruyen la legibilidad del codigo forzando niveles de identacion, e igualando en indentancion los casos de error y los caminos felices, lo cual no deberia pasar. Ademas, aislan un bloque de codigo de su contexto de ejecucion y, la logia que lleva a su ejecution.

Referencia

https://dev.to/dglsparsons/write-better-code-and-be-a-better-programmer-by-never-using-else-statements-4dbl#:~:text=Else%20statements%20are%20problematic%20as,through%2C%20and%20hurts%20the%20readability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment