Funciones Pequeñas
Las funciones deben hacer una sola cosa, hacerla bien y solo eso.
Haz Una Sola Cosa
Las funciones que hacen una sola cosa son fáciles de nombrar, fáciles de testear e imposibles de usar incorrectamente. "Una sola cosa" significa un solo nivel de abstracción — no una sola línea de código. Si puedes extraer una parte en una función con buen nombre sin que se sienta forzado, tu función original estaba haciendo dos cosas.
Hace muchas cosas
function processUserRegistration(data):
// validate
if not data.email or "@" not in data.email:
return { error: "invalid email" }
if not data.password or length(data.password) < 8:
return { error: "password too short" }
// hash password
hashed = hash(data.password)
// save to db
user = { email: data.email, password: hashed }
db.insert("users", user)
// send email
sendEmail(data.email, "Welcome!", "Thanks for joining.")
return { ok: true }
Una sola cosa cada una
function registerUser(data):
validateRegistration(data)
user = createUser(data.email, data.password)
db.save(user)
sendWelcomeEmail(user)
function validateRegistration(data):
requireValidEmail(data.email)
requireStrongPassword(data.password)
function createUser(email, password):
return { email: email, password: hash(password) }
Un Solo Nivel de Abstracción
Mezclar lógica de alto nivel (sendEmail()) con detalles de bajo nivel (hashlib) en la misma función es desconcertante. Los lectores no pueden distinguir qué es importante y qué es ruido de implementación. La Regla del Descenso: cada función debe leerse como un párrafo — cada línea llama a funciones un nivel más abajo.
// ✗ Mixed levels — high-level intent buried in low-level noise
function checkout(cart, user):
total = sum of (item.price * item.qty) for each item in cart.items
tax = total * 0.08
final = total + tax
conn = db.getConnection() // ← suddenly low-level
cursor = conn.cursor()
cursor.execute("INSERT INTO orders ...", user.id, final)
conn.commit()
http.post("https://mail.svc/send", { ... }) // ← even lower
// ✓ One level — each line is at the same altitude
function checkout(cart, user):
total = calculateTotal(cart)
order = saveOrder(user, total)
notifyUser(user, order)Argumentos y Efectos Secundarios
El número ideal de argumentos de una función es cero. Uno está bien. Dos es aceptable. Tres o más — considera un objeto de parámetros. Los argumentos bandera (is_admin=True) son un code smell: anuncian que la función hace dos cosas. Los efectos secundarios son mentiras — una función llamada check_password que también inicia sesión al usuario rompe el contrato de responsabilidad única y sorprende a cada invocador.
Arg bandera + efecto secundario
function getUser(userId, includeDeleted):
// does TWO things depending on flag
if includeDeleted:
return db.queryAll(userId)
return db.queryActive(userId)
function checkPassword(user, password):
if user.password == hash(password):
session.login(user) // ← surprise side effect!
return true
return false
Sin banderas, sin sorpresas
function getActiveUser(userId):
return db.queryActive(userId)
function getUserIncludingDeleted(userId):
return db.queryAll(userId)
function isCorrectPassword(user, password):
return user.password == hash(password)
function login(user): // side effect is explicit
session.start(user)
Desafío de Código
Esta función hace al menos 4 cosas. ¿Puedes nombrar cada responsabilidad y extraerla en su propia función?
💡Conclusión clave
Una función debe hacer una sola cosa, en un solo nivel de abstracción, con un nombre que haga innecesario cualquier comentario.
🔧 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: Empieza listando en papel todo lo que hace la función. Luego busca las 'costuras' naturales — donde termina una responsabilidad y empieza otra. Cada costura es un límite de función.
✗ Tu versión