Skip to main content

Inicia sesión en CleanKata

Sigue tu progreso, gana XP y desbloquea todas las lecciones.

Al iniciar sesión aceptas nuestros Términos de uso y Política de privacidad.

Arquitectura Limpia70 XP7 min

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

Programación como Ciencia: Falsificabilidad y Testing — CleanKata — CleanKata