Programación como Ciencia: Falsificabilidad y Testing
Las pruebas no demuestran corrección, demuestran ausencia de incorrecciones conocidas. La buena arquitectura produce módulos fácilmente falsificables.
Por qué importa
Dijkstra demostró que las pruebas nunca pueden demostrar que un programa es correcto — solo que no se ha encontrado incorrecto todavía. Esto cambia el marco científico: los programas son hipótesis falsificables, y una suite de pruebas es el intento continuo de falsificarlas. Una suite de pruebas que pasa no significa que tu código sea correcto; significa que no ha sido demostrado incorrecto todavía.
Esto tiene una consecuencia arquitectónica directa: si un módulo no puede falsificarse fácilmente, es un fallo arquitectónico. El código que mezcla E/S, análisis, validación y llamadas de red en una sola función tiene demasiadas razones para estar mal y demasiadas dependencias para probarse en aislamiento. Una buena arquitectura obliga a que la lógica importante quede en unidades puras y aisladas que pueden probarse desde cualquier ángulo con cualquier entrada — haciendo que la hipótesis sea fácil de intentar falsificar.
✗El problema
A function that reads a file, parses it, validates data, and sends email cannot be unit-tested without a real file system and a live SMTP server. It is architecturally unfalsifiable.
Bad
import smtplib, csv
def process_user_file(path: str) -> None:
with open(path) as f:
for row in csv.DictReader(f):
if "@" not in row["email"]:
raise ValueError(f"Bad email: {row['email']}")
with smtplib.SMTP("smtp.example.com") as smtp:
smtp.sendmail("no-reply@app.com", row["email"], "Welcome!")
async function processUserFile(path: string): Promise<void> {
const rows = parseCSV(fs.readFileSync(path, "utf8"));
for (const row of rows) {
if (!row.email.includes("@")) throw new Error(`Bad email: ${row.email}`);
await smtp.sendMail({ to: row.email, subject: "Welcome!" });
}
}
✓La solución
Extract the core logic into a pure function. Now it is fully falsifiable — any input, any environment, no infrastructure required.
Good
def is_valid_email(email: str) -> bool:
"""Pure function — testable with any input, no I/O, no side effects."""
return "@" in email and "." in email.split("@")[-1]
# Tests need nothing but the function itself
assert is_valid_email("user@example.com") is True
assert is_valid_email("not-an-email") is False
assert is_valid_email("missing@dot") is False
function isValidEmail(email: string): boolean {
const [local, domain] = email.split("@");
return !!local && !!domain && domain.includes(".");
}
// Falsifiable with any input — no mocks, no network, no files
console.assert(isValidEmail("user@example.com") === true);
console.assert(isValidEmail("not-an-email") === false);
💡Conclusión clave
Una función que no puede probarse en aislamiento es un defecto arquitectónico — la incapacidad de falsificarla es el síntoma, y la mala separación de preocupaciones es la causa.
🔧 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: Una función que no se puede probar en aislamiento es un problema arquitectónico, no de testing.
✗ Tu versión