Manejo Limpio de Errores
El manejo de errores es una preocupación separada — mantenla aislada para que tu algoritmo principal sea legible.
Excepciones vs. Códigos de Retorno
Los códigos de retorno obligan al invocador a verificar cada resultado inmediatamente, contaminando el punto de llamada con condicionales. La lógica de manejo de errores se entrelaza con la lógica de negocio. Las excepciones separan el camino feliz de los casos de error, permitiendo escribir el algoritmo una vez, con claridad, y manejar los fallos en un lugar enfocado.
Códigos de retorno — el manejo de errores domina
result = db.connect()
if result == ERROR_NO_CONNECTION:
log("connection failed")
return ERROR_NO_CONNECTION
result = db.query(userId)
if result == ERROR_NOT_FOUND:
log("user not found")
return ERROR_NOT_FOUND
result = db.save(result)
if result == ERROR_SAVE_FAILED:
log("save failed")
return ERROR_SAVE_FAILED
Excepciones — el camino feliz es legible
try:
connection = db.connect()
user = db.query(userId)
db.save(user)
catch NoConnectionError:
log("connection failed")
catch UserNotFoundError:
log("user not found")
catch SaveFailedError:
log("save failed")
El Bloque Try-Catch-Finally
Piensa en try-catch-finally como una transacción de base de datos: define un ámbito. El bloque try es el cuerpo de la transacción. El catch maneja el rollback. finally siempre se ejecuta (limpieza de conexión, handles de archivos). Extrae el cuerpo de los bloques catch en funciones con nombre: un bloque catch de más de 2 líneas es una función esperando nacer.
Lógica enterrada dentro del catch
try:
processPayment(order)
catch PaymentError as e:
log("Payment failed: " + e.code)
notifyFinanceTeam(order, e)
order.status = "failed"
db.update(order)
sendFailureEmail(order.user, e.message)
metrics.increment("payment.failures")
Extrae el cuerpo del catch a una función
try:
processPayment(order)
catch PaymentError as e:
handlePaymentFailure(order, e)
function handlePaymentFailure(order, error):
log("Payment failed: " + error.code)
order.status = "failed"
db.update(order)
notifyFinanceTeam(order, error)
sendFailureEmail(order.user, error.message)
metrics.increment("payment.failures")
El Peligro del Null
Devolver null obliga a cada invocador a comprobarlo. Un null check olvidado = crash en runtime. Pasar null como argumento es igual de peligroso: la función receptora debe protegerse contra él. En su lugar: lanza una excepción, devuelve una colección vacía o usa el patrón de Caso Especial (Null Object).
// ✗ Returns null — caller must remember to check
function findUser(userId):
row = db.query(userId)
if not row:
return null // ← every caller must null-check
user = findUser("123")
if user: // easy to forget
process(user)
// ✓ Option 1: raise an exception
function findUser(userId):
row = db.query(userId)
if not row:
raise UserNotFoundError(userId)
return User.fromRow(row)
// ✓ Option 2: Special Case / Null Object
class GuestUser:
name = "Guest"
function canCheckout(): return false
function findUser(userId):
row = db.query(userId)
if row:
return User.fromRow(row)
return new GuestUser()
// ✓ Option 3: empty collection (for list results)
function findOrders(userId):
return db.queryOrders(userId) or []Desafío de Código
Reemplaza Códigos de Retorno con Excepciones — reescribe para separar el camino feliz del manejo de errores.
💡Conclusión clave
El manejo de errores es una preocupación separada. Escribe primero el camino feliz, luego trata los fallos en un lugar enfocado.
🔧 Algunos ejercicios pueden tener errores. Si algo parece incorrecto, usa el botón Feedback (abajo a la derecha) para reportarlo — nos ayuda a corregirlo rápido.
Pista: Escribe primero el camino feliz como si nada pudiera salir mal. Luego pregunta en cada paso: ¿qué podría fallar aquí? Cada fallo se convierte en una excepción lanzada. El llamador decide cómo manejarlo, no el llamado.
✗ Tu versión