EAFP vs LBYL: me evito el dolor de cabeza o cuando cruce el puente vemos?

José A. Fernández
5 min readMar 15, 2024

--

Parte de la descripción de nuestro trabajo como desarrolladores es manejar errores y excepciones cuando nos encontramos traduciendo reglas de negocio a instrucciones en nuestro código.

Hoy hablaremos de dos aproximaciones o estrategias para este tipo de problema en particular:

  1. Easier to Ask Forgiveness than Permission(EAFP): Damos manejo a la condicion de error o situación excepcional despues que suceda
  2. Look Before You Leap(LBYL): Evitamos los errores o situaciones excepcionales antes que sucedan.

La mayoría de nosotros (los veteranos) aprendimos a evitar las condiciones de error antes que sucedieran, esto es porque algunos lenguajes con los que iniciamos como Assembler o C carecían del manejo de excepciones.

Hoy en día, los lenguajes de programacion proveen capacidades de manejo de excepciones (try/catch), pero debemos considerar que las excepciones se tratan de condiciones excepcionales y no contempladas, cuyo tratamiento puede ser costoso desde el punto de vista de desempeño y de recursos de computo. Si hay chance de divisar el posible fallo en la implementación y manejarlo como error, es mejor hacerlo de esa forma (P.ej: Result pattern).

Vamos a adentrarnos en las estrategias antes listadas.

Easier to Ask Forgiveness than Permission - EAFP

Perdoname - Gilberto Santa Rosa - En Vivo Desde El Carnegie Hall

En esencia, lo que propone esta aproximación es: “Haga lo que esperas que funcione”, y si se presentan errores o excepciones, estas se capturan y se tratan de forma correcta o adecuada en vez de validar antes si es posible ejecutar la acción o no.

Aunque este tipo de aproximación podría usarse con lenguajes de programación que soporten manejo de excepciones, es muy popular en Python dado que su manejo de excepciones es rápido y eficiente (leí en algun lugar que Python tendría “Zero Cost Exceptions”, eliminando el costo de sentencias try cuando no se levanta ninguna excepción).

Listemos algunas características de EAFP:

  • EAFP nos ofrece un código más conciso y legible comparado con LBYL.
  • EAFP podría tener mejor desempeño que LBYL: Los condicionales siempre deben ser evaluados; en cambio, las condiciones excepcionales de error no son comunes.
  • La posición del manejo de errores o validaciones va al final.
  • Con EAFP, las excepciones se convierten en condicionales, lo cual añade otro uso a las mismas, ya que no solo podrían ser usadas para manejo de condiciones de error imprevistas, también podrían ser usadas como parte de la lógica de programación (similar a estructuras de control).

Mira este ejemplo en donde usamos el manejo de excepción también como un condicional:

try 
{
// Haga esto
result = await service.Execute()
}
catch(ExecutionException ex)
{
// falló? entonces esto
result = "Object Not found";
}

Veamos otro ejemplo :

string filePath = "example.txt";
try
{
// Vaya y lea el contenido del archivo.
string content = File.ReadAllText(filePath);
Console.WriteLine("Contenido del archivo: " + content);
}
catch (FileNotFoundException)
{
Console.WriteLine("El archivo no existe.");
}
catch (IOException e)
{
Console.WriteLine("Error leyendo el archivo: " + e.Message);
}

Como se explicó previamente: hacemos lo que esperamos que funcione, y si falla, entonces tratamos las condiciones excepcionales y/o errores que surjan.

Look Before You Leap - LBYL

Con esta estrategía primero validamos si la tarea puede realizarse, y solo procedemos cuando hay certeza que funcionará. Se trata de realizar o probar precondiciones antes de hacer invocaciones o llamados.

LBYL, como convención, es muy usada en lenguajes de programación como C# y Java, y aunque C# es un lenguaje dotado de capacidades de manejo de excepciones, la recomendación de Microsoft es la de “realizar validaciones sin lanzar excepciones” en su Guía de mejores prácticas para Excepciones.

Entre sus características, encontramos:

  • LBYL ubica la validación de condiciones al inicio y habilita Fail fast (que enfatiza en detectar y responder a errores o condiciones excepcionales tan temprano como sea posible en el proceso de ejecución de la aplicación).
  • Uso de condicionales explícitos para validar si cierta condicion se cumple antes de ejecutar una(s) instruccion(es).
  • El control de flujo de un programa puede ser cambiado/alterado basado en la salida de la evaluación de los condicionales.
  • Como se mencionó antes, es posible que de cara al desempeño el rendimiento sea menor que EAFP, especialmente si las validaciones son muchas y muy frecuentes.
  • El código tiende a ser muy verboso, no tan conciso y legible como EAFP.

Mira este ejemplo :

string filePath = “example.txt”;
// Valide si el archivo existe en la ruta antes de obtener su contendo
if (File.Exists(filePath))
{
// lea el contenido
string content = File.ReadAllText(filePath);
Console.WriteLine("Contenido del archivo: " + content);
}
else
{
Console.WriteLine("El archivo no existe.");
}

O este otro ejemplo :

SqlConnection connection = new SqlConnection("your_connection_string_here");
// Check if the connection is open before attempting to close it
if (connection.State == System.Data.ConnectionState.Open)
{
// Close the connection
connection.Close();
Console.WriteLine(“Database connection closed.”);
}
else
{
Console.WriteLine(“Database connection is already closed.”);
}

Ahora la pregunta del millón: cuando uno u otro ?

La respuesta corta: depende. Si lo que estas tratando de resolver se beneficia mas de una u otra estrategia, entonces elija la mejor y al usarla no te vuelvas loco pensando en si es un antipatrón o si estas violando una regla, recuerda que hay mas de una forma de solucionar un problema.

Podrías tener en cuenta estas preguntas antes de decidir cual de las 2 aproximaciones es mejor:

  1. ¿Es más conveniente prevenir los errores antes que sucedan?
  2. ¿Puedo manejarlos si eventualmente suceden?

Otras consideraciones:

  1. Desempeño: como ya lo establecimos previamente en algunos casos, EAFP puede tener mejor desempeño que LBYL al no tener que hacer validaciones previas.
  2. Evitar condiciones de carrera (Race Conditions): una condición de carrera ocurre cuando la salida de la ejecución de un programa depende de una secuencia u otro evento incontrolable. Muy a menudo, esto esta relacionado con ejecuciónes concurrentes, donde multiples hilos operan de forma simultanea. LBYL apunta a prevenir errores, incluidas las condiciones de carrera. Por ejemplo, un desarrollador puede validar si un recurso, que solo puede ser usado por un cliente al mismo tiempo, esta disponible antes de accederlo para evitar la condición de error cuando hayan multiples procesos tratando de acceder a ese recurso de forma simultánea.
  3. Mejorar la claridad y legibilidad del codigo : EAFP es bueno con esto, LBYL podría hacer mas difícil la tarea sobre todo si hay muchas validaciones(no tan conciso).

Creo que no se debería bajar de la mesa ninguna de las estrategías y probablemente podríamos beneficiarnos de emplear una combinación de ambas.

XOXO! Déjame tu comentario.

--

--

José A. Fernández
José A. Fernández

Written by José A. Fernández

Software Developer/Architect/Coach @Ceiba Software House with many years of experience(since 2001). Linux/Unix lover. Mtb rider. Cheff amateur.

No responses yet