Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Simplificación de Condicionales

Técnicas para clarificar y simplificar lógica condicional compleja

Universidad Nacional de Rio Negro - Sede Andina

Introducción

Los condicionales son una parte fundamental de la programación, pero también son una fuente común de complejidad y errores. Un código con lógica condicional compleja es difícil de leer, mantener y testear. La refactorización de condicionales busca hacer la lógica más clara, expresiva y mantenible.

Este apunte presenta técnicas sistemáticas para simplificar expresiones booleanas, reducir anidamiento, y hacer que las condiciones sean auto-explicativas.

Problemas Comunes con Condicionales

1. Anidamiento Excesivo

// Problemático: pirámide de la perdición
if (usuario != NULL) {
    if (usuario->activo) {
        if (usuario->edad >= 18) {
            if (usuario->saldo > 0) {
                procesar_compra(usuario);
            } else {
                printf("Saldo insuficiente\n");
            }
        } else {
            printf("Usuario menor de edad\n");
        }
    } else {
        printf("Usuario inactivo\n");
    }
} else {
    printf("Usuario inválido\n");
}

2. Condiciones Complejas

// Difícil de entender de un vistazo
if ((estado == ACTIVO || estado == PENDIENTE) && 
    (tipo != TEMPORAL && tipo != PRUEBA) &&
    (saldo > 1000 || credito_disponible > 500) &&
    !(bloqueado || suspendido))
{
    // ...
}

3. Lógica Duplicada

if (edad >= 18 && edad <= 65 && !jubilado) {
    precio = PRECIO_ADULTO;
}

// Más adelante en el código...
if (edad >= 18 && edad <= 65 && !jubilado) {
    aplicar_descuento();
}

4. Booleanos Implícitos

// Redundante
if (es_valido() == true) {
    // ...
}

if (contador > 0) {
    return true;
} else {
    return false;
}

Técnicas de Refactorización

1. Guardia de Cláusulas (Guard Clauses)

Invertir condiciones para manejar casos especiales temprano y reducir anidamiento.

Antes:

void procesar_pedido(pedido_t* pedido) {
    if (pedido != NULL) {
        if (pedido->items_count > 0) {
            if (pedido->cliente != NULL) {
                if (pedido->cliente->saldo >= pedido->total) {
                    // Lógica principal de procesamiento
                    realizar_cargo(pedido);
                    actualizar_inventario(pedido);
                    enviar_confirmacion(pedido);
                } else {
                    printf("Saldo insuficiente\n");
                }
            } else {
                printf("Cliente inválido\n");
            }
        } else {
            printf("Pedido vacío\n");
        }
    } else {
        printf("Pedido nulo\n");
    }
}

Después:

void procesar_pedido(pedido_t* pedido) {
    // Guardia de cláusulas - validaciones tempranas
    if (pedido == NULL) {
        printf("Pedido nulo\n");
        return;
    }
    
    if (pedido->items_count == 0) {
        printf("Pedido vacío\n");
        return;
    }
    
    if (pedido->cliente == NULL) {
        printf("Cliente inválido\n");
        return;
    }
    
    if (pedido->cliente->saldo < pedido->total) {
        printf("Saldo insuficiente\n");
        return;
    }
    
    // Lógica principal ahora está al mismo nivel
    realizar_cargo(pedido);
    actualizar_inventario(pedido);
    enviar_confirmacion(pedido);
}

Beneficios:

2. Extracción de Condiciones a Variables Booleanas

Antes:

if (usuario->edad >= 18 && usuario->edad <= 65 && 
    !usuario->jubilado && usuario->activo &&
    (usuario->tipo == REGULAR || usuario->tipo == PREMIUM)) {
    aplicar_beneficio(usuario);
}

Después:

bool es_adulto_en_edad_laboral = usuario->edad >= 18 && 
                                  usuario->edad <= 65 && 
                                  !usuario->jubilado;

bool es_usuario_activo_valido = usuario->activo &&
                                 (usuario->tipo == REGULAR || 
                                  usuario->tipo == PREMIUM);

if (es_adulto_en_edad_laboral && es_usuario_activo_valido) {
    aplicar_beneficio(usuario);
}

Beneficios:

3. Extracción de Condiciones a Funciones

Para lógica compleja o reutilizable:

Antes:

void procesar_descuento(cliente_t* cliente, double total) {
    if ((cliente->compras_totales > 10000 && cliente->antiguedad > 365) ||
        (cliente->referidos >= 5) ||
        (cliente->tipo == VIP && cliente->activo)) {
        aplicar_descuento_premium(total);
    }
}

Después:

bool es_cliente_fiel(const cliente_t* cliente) {
    return cliente->compras_totales > 10000 && 
           cliente->antiguedad > 365;
}

bool es_buen_referidor(const cliente_t* cliente) {
    return cliente->referidos >= 5;
}

bool es_vip_activo(const cliente_t* cliente) {
    return cliente->tipo == VIP && cliente->activo;
}

bool califica_para_descuento_premium(const cliente_t* cliente) {
    return es_cliente_fiel(cliente) ||
           es_buen_referidor(cliente) ||
           es_vip_activo(cliente);
}

void procesar_descuento(cliente_t* cliente, double total) {
    if (califica_para_descuento_premium(cliente)) {
        aplicar_descuento_premium(total);
    }
}

Beneficios:

4. Simplificación de Booleanos

Antes:

bool es_valido(int valor) {
    if (valor > 0 && valor < 100) {
        return true;
    } else {
        return false;
    }
}

// Comparación redundante
if (esta_activo() == true) {
    // ...
}

if (contador > 0 == false) {
    // ...
}

Después:

bool es_valido(int valor) {
    return valor > 0 && valor < 100;
}

// Uso directo del booleano
if (esta_activo()) {
    // ...
}

if (!esta_activo()) {
    // ...
}

if (contador == 0) {
    // ...
}

5. Reemplazo de Condicionales con Polimorfismo (simulado en C)

Para casos donde múltiples if-else determinan comportamiento:

Antes:

double calcular_area(figura_t* figura) {
    if (figura->tipo == CIRCULO) {
        return PI * figura->datos.circulo.radio * 
               figura->datos.circulo.radio;
    } else if (figura->tipo == RECTANGULO) {
        return figura->datos.rectangulo.ancho * 
               figura->datos.rectangulo.alto;
    } else if (figura->tipo == TRIANGULO) {
        return 0.5 * figura->datos.triangulo.base * 
               figura->datos.triangulo.altura;
    }
    return 0;
}

Después (con punteros a función):

typedef double (*calcular_area_fn)(const void* datos);

typedef struct {
    int tipo;
    calcular_area_fn calcular_area;
    void* datos;
} figura_t;

double calcular_area_circulo(const void* datos) {
    const circulo_t* c = (const circulo_t*)datos;
    return PI * c->radio * c->radio;
}

double calcular_area_rectangulo(const void* datos) {
    const rectangulo_t* r = (const rectangulo_t*)datos;
    return r->ancho * r->alto;
}

double calcular_area_triangulo(const void* datos) {
    const triangulo_t* t = (const triangulo_t*)datos;
    return 0.5 * t->base * t->altura;
}

double calcular_area(const figura_t* figura) {
    return figura->calcular_area(figura->datos);
}

6. Tabla de Decisión

Para lógica compleja con múltiples combinaciones:

Antes:

char* obtener_categoria(int edad, bool estudiante, bool empleado) {
    if (edad < 18 && estudiante) {
        return "ESTUDIANTE_MENOR";
    } else if (edad < 18 && !estudiante) {
        return "MENOR";
    } else if (edad >= 18 && edad < 65 && estudiante) {
        return "ESTUDIANTE_ADULTO";
    } else if (edad >= 18 && edad < 65 && empleado) {
        return "EMPLEADO";
    } else if (edad >= 18 && edad < 65) {
        return "ADULTO";
    } else if (edad >= 65 && empleado) {
        return "JUBILADO_ACTIVO";
    } else {
        return "JUBILADO";
    }
}

Después (con tabla):

typedef struct {
    bool (*condicion)(int edad, bool estudiante, bool empleado);
    const char* categoria;
} regla_categoria_t;

bool es_estudiante_menor(int edad, bool estudiante, bool empleado) {
    return edad < 18 && estudiante;
}

bool es_menor(int edad, bool estudiante, bool empleado) {
    return edad < 18 && !estudiante;
}

bool es_estudiante_adulto(int edad, bool estudiante, bool empleado) {
    return edad >= 18 && edad < 65 && estudiante;
}

bool es_empleado(int edad, bool estudiante, bool empleado) {
    return edad >= 18 && edad < 65 && empleado;
}

bool es_adulto(int edad, bool estudiante, bool empleado) {
    return edad >= 18 && edad < 65 && !estudiante && !empleado;
}

bool es_jubilado_activo(int edad, bool estudiante, bool empleado) {
    return edad >= 65 && empleado;
}

bool es_jubilado(int edad, bool estudiante, bool empleado) {
    return edad >= 65 && !empleado;
}

const regla_categoria_t REGLAS_CATEGORIA[] = {
    {es_estudiante_menor, "ESTUDIANTE_MENOR"},
    {es_menor, "MENOR"},
    {es_estudiante_adulto, "ESTUDIANTE_ADULTO"},
    {es_empleado, "EMPLEADO"},
    {es_adulto, "ADULTO"},
    {es_jubilado_activo, "JUBILADO_ACTIVO"},
    {es_jubilado, "JUBILADO"}
};

const int NUM_REGLAS = sizeof(REGLAS_CATEGORIA) / sizeof(REGLAS_CATEGORIA[0]);

const char* obtener_categoria(int edad, bool estudiante, bool empleado) {
    for (int i = 0; i < NUM_REGLAS; i++) {
        if (REGLAS_CATEGORIA[i].condicion(edad, estudiante, empleado)) {
            return REGLAS_CATEGORIA[i].categoria;
        }
    }
    return "DESCONOCIDO";
}

7. Uso de switch en lugar de if-else en cadena

Para comparaciones de igualdad con un valor:

Antes:

void procesar_comando(char comando) {
    if (comando == 'A') {
        avanzar();
    } else if (comando == 'R') {
        retroceder();
    } else if (comando == 'I') {
        girar_izquierda();
    } else if (comando == 'D') {
        girar_derecha();
    } else if (comando == 'P') {
        parar();
    } else {
        printf("Comando inválido\n");
    }
}

Después:

void procesar_comando(char comando) {
    switch (comando) {
        case 'A':
            avanzar();
            break;
        case 'R':
            retroceder();
            break;
        case 'I':
            girar_izquierda();
            break;
        case 'D':
            girar_derecha();
            break;
        case 'P':
            parar();
            break;
        default:
            printf("Comando inválido\n");
            break;
    }
}

Casos Prácticos Completos

Caso 1: Validación de Formulario

Código Original:

bool validar_formulario(const char* nombre, 
                         const char* email,
                         const char* telefono,
                         int edad) {
    if (nombre != NULL) {
        if (strlen(nombre) >= 3) {
            if (email != NULL) {
                if (strchr(email, '@') != NULL) {
                    if (strlen(email) >= 5) {
                        if (telefono != NULL) {
                            if (strlen(telefono) >= 8) {
                                if (edad >= 18) {
                                    if (edad <= 120) {
                                        return true;
                                    } else {
                                        printf("Edad muy alta\n");
                                    }
                                } else {
                                    printf("Debe ser mayor de edad\n");
                                }
                            } else {
                                printf("Teléfono muy corto\n");
                            }
                        } else {
                            printf("Teléfono nulo\n");
                        }
                    } else {
                        printf("Email muy corto\n");
                    }
                } else {
                    printf("Email sin @\n");
                }
            } else {
                printf("Email nulo\n");
            }
        } else {
            printf("Nombre muy corto\n");
        }
    } else {
        printf("Nombre nulo\n");
    }
    return false;
}

Código Refactorizado:

bool validar_nombre(const char* nombre) {
    if (nombre == NULL) {
        printf("Nombre nulo\n");
        return false;
    }
    
    if (strlen(nombre) < 3) {
        printf("Nombre muy corto\n");
        return false;
    }
    
    return true;
}

bool validar_email(const char* email) {
    if (email == NULL) {
        printf("Email nulo\n");
        return false;
    }
    
    if (strlen(email) < 5) {
        printf("Email muy corto\n");
        return false;
    }
    
    if (strchr(email, '@') == NULL) {
        printf("Email sin @\n");
        return false;
    }
    
    return true;
}

bool validar_telefono(const char* telefono) {
    if (telefono == NULL) {
        printf("Teléfono nulo\n");
        return false;
    }
    
    if (strlen(telefono) < 8) {
        printf("Teléfono muy corto\n");
        return false;
    }
    
    return true;
}

bool validar_edad(int edad) {
    if (edad < 18) {
        printf("Debe ser mayor de edad\n");
        return false;
    }
    
    if (edad > 120) {
        printf("Edad muy alta\n");
        return false;
    }
    
    return true;
}

bool validar_formulario(const char* nombre, 
                         const char* email,
                         const char* telefono,
                         int edad) {
    return validar_nombre(nombre) &&
           validar_email(email) &&
           validar_telefono(telefono) &&
           validar_edad(edad);
}

Caso 2: Cálculo de Descuento Complejo

Código Original:

double calcular_descuento(double monto, 
                           int cantidad,
                           bool es_miembro,
                           bool es_primera_compra,
                           const char* codigo_promo) {
    double descuento = 0;
    
    if (cantidad > 10 && monto > 1000) {
        if (es_miembro) {
            if (strcmp(codigo_promo, "VERANO") == 0) {
                descuento = 0.30;
            } else if (strcmp(codigo_promo, "FLASH") == 0) {
                if (cantidad > 20) {
                    descuento = 0.35;
                } else {
                    descuento = 0.25;
                }
            } else {
                descuento = 0.20;
            }
        } else {
            if (es_primera_compra) {
                descuento = 0.15;
            } else {
                descuento = 0.10;
            }
        }
    } else if (cantidad > 5 || monto > 500) {
        if (es_miembro) {
            descuento = 0.15;
        } else {
            descuento = 0.05;
        }
    } else {
        if (es_primera_compra) {
            descuento = 0.10;
        }
    }
    
    return descuento;
}

Código Refactorizado:

bool es_compra_grande(double monto, int cantidad) {
    return cantidad > 10 && monto > 1000;
}

bool es_compra_mediana(double monto, int cantidad) {
    return cantidad > 5 || monto > 500;
}

double descuento_miembro_compra_grande(int cantidad, const char* codigo_promo) {
    if (strcmp(codigo_promo, "VERANO") == 0) {
        return 0.30;
    }
    
    if (strcmp(codigo_promo, "FLASH") == 0) {
        return cantidad > 20 ? 0.35 : 0.25;
    }
    
    return 0.20;
}

double descuento_no_miembro_compra_grande(bool es_primera_compra) {
    return es_primera_compra ? 0.15 : 0.10;
}

double calcular_descuento(double monto, 
                           int cantidad,
                           bool es_miembro,
                           bool es_primera_compra,
                           const char* codigo_promo) {
    if (es_compra_grande(monto, cantidad)) {
        if (es_miembro) {
            return descuento_miembro_compra_grande(cantidad, codigo_promo);
        } else {
            return descuento_no_miembro_compra_grande(es_primera_compra);
        }
    }
    
    if (es_compra_mediana(monto, cantidad)) {
        return es_miembro ? 0.15 : 0.05;
    }
    
    return es_primera_compra ? 0.10 : 0.0;
}

Leyes de De Morgan

Útiles para simplificar expresiones booleanas complejas:

Leyes:

Ejemplo:

// Antes
if (!(activo && validado)) {
    return;
}

// Después (más claro en contexto de guardia)
if (!activo || !validado) {
    return;
}
// Antes
if (!(edad < 18 || edad > 65)) {
    aplicar_tarifa_regular();
}

// Después (más claro)
if (edad >= 18 && edad <= 65) {
    aplicar_tarifa_regular();
}

Combinación con el Patrón de Único Retorno

Cuando se aplica el patrón de único retorno (ver ref-unico-retorno), las técnicas de simplificación de condicionales deben adaptarse para mantener un solo punto de salida.

Guardia de Cláusulas con Único Retorno

Guard Clauses tradicionales (múltiples returns):

int procesar_pago(usuario_t* usuario, double monto) {
    if (usuario == NULL) {
        return ERROR_USUARIO_NULL;
    }
    
    if (!usuario->activo) {
        return ERROR_USUARIO_INACTIVO;
    }
    
    if (usuario->saldo < monto) {
        return ERROR_SALDO_INSUFICIENTE;
    }
    
    // Procesar pago
    usuario->saldo -= monto;
    return EXITO;
}

Adaptado a único retorno:

int procesar_pago(usuario_t* usuario, double monto) {
    int resultado = ERROR_DESCONOCIDO;
    
    if (usuario == NULL) {
        resultado = ERROR_USUARIO_NULL;
    } else if (!usuario->activo) {
        resultado = ERROR_USUARIO_INACTIVO;
    } else if (usuario->saldo < monto) {
        resultado = ERROR_SALDO_INSUFICIENTE;
    } else {
        // Procesar pago
        usuario->saldo -= monto;
        resultado = EXITO;
    }
    
    return resultado;
}

Variables de Estado para Control de Flujo

Cuando se combina único retorno con condicionales complejos, usar variables de estado explícitas mejora la claridad.

Antes (múltiples returns):

bool validar_transaccion(transaccion_t* trans) {
    if (trans->monto <= 0) {
        return false;
    }
    
    if (trans->origen == NULL || trans->destino == NULL) {
        return false;
    }
    
    if (trans->origen->saldo < trans->monto) {
        return false;
    }
    
    if (trans->origen->bloqueada || trans->destino->bloqueada) {
        return false;
    }
    
    return true;
}

Después (único retorno con variable de estado):

bool validar_transaccion(const transaccion_t* trans) {
    bool es_valida = true;
    
    if (trans->monto <= 0) {
        es_valida = false;
    } else if (trans->origen == NULL || trans->destino == NULL) {
        es_valida = false;
    } else if (trans->origen->saldo < trans->monto) {
        es_valida = false;
    } else if (trans->origen->bloqueada || trans->destino->bloqueada) {
        es_valida = false;
    }
    
    return es_valida;
}

Combinando Predicados y Único Retorno

Con múltiples returns:

bool puede_realizar_compra(const usuario_t* u, double monto) {
    if (!es_usuario_valido(u)) return false;
    if (!tiene_saldo_suficiente(u, monto)) return false;
    if (!esta_dentro_limite_diario(u, monto)) return false;
    return true;
}

Con único retorno:

bool puede_realizar_compra(const usuario_t* u, double monto) {
    bool puede = false;
    
    if (es_usuario_valido(u) &&
        tiene_saldo_suficiente(u, monto) &&
        esta_dentro_limite_diario(u, monto)) {
        puede = true;
    }
    
    return puede;
}

O de manera más concisa:

bool puede_realizar_compra(const usuario_t* u, double monto) {
    return es_usuario_valido(u) &&
           tiene_saldo_suficiente(u, monto) &&
           esta_dentro_limite_diario(u, monto);
}

Caso Práctico: Autenticación con Único Retorno

Antes (múltiples returns):

int autenticar(const char* usuario, const char* password) {
    if (usuario == NULL || password == NULL) {
        return AUTH_ERROR_PARAMETROS;
    }
    
    usuario_t* u = buscar_usuario(usuario);
    if (u == NULL) {
        return AUTH_ERROR_USUARIO_NO_EXISTE;
    }
    
    if (u->intentos_fallidos >= MAX_INTENTOS) {
        return AUTH_ERROR_BLOQUEADO;
    }
    
    if (!verificar_password(u, password)) {
        u->intentos_fallidos++;
        return AUTH_ERROR_PASSWORD_INCORRECTO;
    }
    
    u->intentos_fallidos = 0;
    u->ultimo_acceso = time(NULL);
    return AUTH_EXITO;
}

Después (único retorno con flujo claro):

int autenticar(const char* usuario, const char* password) {
    int resultado = AUTH_ERROR_DESCONOCIDO;
    usuario_t* u = NULL;
    
    // Validación de parámetros
    if (usuario == NULL || password == NULL) {
        resultado = AUTH_ERROR_PARAMETROS;
    } else {
        u = buscar_usuario(usuario);
        
        if (u == NULL) {
            resultado = AUTH_ERROR_USUARIO_NO_EXISTE;
        } else if (u->intentos_fallidos >= MAX_INTENTOS) {
            resultado = AUTH_ERROR_BLOQUEADO;
        } else if (!verificar_password(u, password)) {
            u->intentos_fallidos++;
            resultado = AUTH_ERROR_PASSWORD_INCORRECTO;
        } else {
            // Autenticación exitosa
            u->intentos_fallidos = 0;
            u->ultimo_acceso = time(NULL);
            resultado = AUTH_EXITO;
        }
    }
    
    return resultado;
}

Manejo de Recursos con Único Retorno

El patrón de único retorno es especialmente útil cuando se manejan recursos que deben liberarse.

Antes (múltiples returns, riesgo de fugas):

char* leer_archivo(const char* ruta) {
    FILE* f = fopen(ruta, "r");
    if (f == NULL) {
        return NULL;
    }
    
    fseek(f, 0, SEEK_END);
    long tam = ftell(f);
    if (tam < 0) {
        fclose(f);  // Fácil olvidar esto
        return NULL;
    }
    
    char* buffer = malloc(tam + 1);
    if (buffer == NULL) {
        fclose(f);  // Y esto
        return NULL;
    }
    
    fseek(f, 0, SEEK_SET);
    size_t leidos = fread(buffer, 1, tam, f);
    if (leidos != tam) {
        free(buffer);  // Y esto
        fclose(f);     // Y esto
        return NULL;
    }
    
    buffer[tam] = '\0';
    fclose(f);
    return buffer;
}

Después (único retorno, liberación garantizada):

char* leer_archivo(const char* ruta) {
    char* resultado = NULL;
    FILE* f = NULL;
    char* buffer = NULL;
    
    f = fopen(ruta, "r");
    if (f != NULL) {
        fseek(f, 0, SEEK_END);
        long tam = ftell(f);
        
        if (tam >= 0) {
            buffer = malloc(tam + 1);
            
            if (buffer != NULL) {
                fseek(f, 0, SEEK_SET);
                size_t leidos = fread(buffer, 1, tam, f);
                
                if (leidos == tam) {
                    buffer[tam] = '\0';
                    resultado = buffer;
                    buffer = NULL;  // No liberar si exitoso
                }
            }
        }
    }
    
    // Limpieza centralizada
    if (buffer != NULL) {
        free(buffer);
    }
    if (f != NULL) {
        fclose(f);
    }
    
    return resultado;
}

Variables de Control para Lazos

El patrón de único retorno se combina bien con variables de control en lazos.

Antes (con break/return):

int buscar_elemento(const int* arr, int n, int valor) {
    for (int i = 0; i < n; i++) {
        if (arr[i] == valor) {
            return i;  // Retorno temprano
        }
    }
    return -1;
}

Después (único retorno):

int buscar_elemento(const int* arr, int n, int valor) {
    int indice = -1;
    
    for (int i = 0; i < n && indice == -1; i++) {
        if (arr[i] == valor) {
            indice = i;
        }
    }
    
    return indice;
}

Balance entre Claridad y Único Retorno

Funciones simples - múltiples returns aceptables:

bool es_par(int n) {
    return n % 2 == 0;
}

int maximo(int a, int b) {
    return (a > b) ? a : b;
}

Funciones complejas - único retorno preferible:

int procesar_pedido_complejo(pedido_t* pedido, contexto_t* ctx) {
    int resultado = ERROR_DESCONOCIDO;
    recurso_t* recurso = NULL;
    
    // Múltiples validaciones y manejo de recursos
    if (validar_pedido(pedido)) {
        recurso = adquirir_recurso(ctx);
        
        if (recurso != NULL) {
            if (procesar_con_recurso(pedido, recurso)) {
                resultado = EXITO;
            } else {
                resultado = ERROR_PROCESAMIENTO;
            }
        } else {
            resultado = ERROR_RECURSO;
        }
    } else {
        resultado = ERROR_VALIDACION;
    }
    
    // Limpieza garantizada
    if (recurso != NULL) {
        liberar_recurso(recurso);
    }
    
    return resultado;
}

Resumen

Técnicas para simplificar condicionales:

  1. Guard Clauses: Validaciones tempranas para reducir anidamiento

  2. Variables Booleanas: Dar nombres descriptivos a condiciones complejas

  3. Funciones de Predicado: Encapsular lógica condicional reutilizable

  4. Simplificación Booleana: Retornar expresiones directamente

  5. Polimorfismo: Reemplazar condicionales con despacho dinámico

  6. Tablas de Decisión: Para lógica compleja con muchas combinaciones

  7. Switch: En lugar de cadenas if-else para valores discretos

  8. Único Retorno: Combinar con condicionales para mejor manejo de recursos

Principios clave:

La claridad en los condicionales es esencial para código mantenible y libre de bugs.