01 · Punto de partida
Programar un error conceptual lo vuelve más rápido, no más correcto
En el Tema 1 distinguimos verificar (¿construimos bien?) de validar (¿construimos lo correcto?). La verificación empieza mucho antes del código: en el modelo conceptual, es decir, el documento —texto, diagrama, ecuaciones y supuestos— que dice qué se va a programar.
Si ese documento dice «las llegadas son constantes» cuando hay hora pico, o «el tanque es infinito» cuando tiene tope, ningún test unitario lo detectará: el programa será fiel a una mala idea.
- ¿Las reglas son coherentes entre sí o se contradicen?
- ¿Falta algún evento, estado o condición de borde?
- ¿Los supuestos están escritos o viven solo en tu cabeza?
- ¿Las unidades y rangos cierran de punta a punta?
02 · Definición
Qué es y qué no es
El modelo conceptual incluye: objetivo, frontera, variables y parámetros con unidades, reglas de actualización, condiciones iniciales y de contorno, supuestos y rango de validez declarado.
Completo
Todo estado tiene una regla. No hay «después vemos qué pasa si el tanque se vacía o la cola explota».
Coherente
Ninguna regla contradice a otra. Si la entrada es por minuto, la salida no puede estar por hora sin conversión.
Explícito
Cada simplificación está escrita como supuesto numerado (S1, S2…), con su riesgo si se viola.
Verificar esto no usa datos reales ni código: usa lectura cruzada, diagramas, análisis dimensional y recorridos mentales de casos borde. La validación con datos vendrá después (Temas 5–8).
03 · Técnicas
Cinco chequeos que siempre rinden
- 1Lectura estructurada (walkthrough).
Otra persona recorre la especificación en voz alta con un checklist. El autor no defiende: anota. 30 minutos detectan el 60% de los defectos conceptuales.
- 2Diagrama de estados y flujos.
Dibujar cajas y flechas obliga a decidir: ¿qué entra, qué se acumula, qué sale? Toda flecha sin origen o destino es un hueco conceptual.
- 3Análisis dimensional.
Revisar unidades: nivel [litros] + caudal [litros/paso] × pasos [pasos] = [litros]. Si sumás litros con litros/minuto, el concepto está roto.
- 4Casos borde mentales.
Probar en papel: cero, tope, negativo, infinito, primer y último paso. ¿Qué hace la regla? Si no lo dice, falta especificación.
- 5Matriz de supuestos.
Tabla S1…Sk con columnas: supuesto, por qué se asume, qué lo rompería, qué pasa si se rompe. Lo no escrito no existe.
| ID | Supuesto | Se rompe si… | Efecto |
|---|---|---|---|
| S1 | Flujos constantes por paso | Hay hora pico o evaporación | Balance real ≠ supuesto → sesgo |
| S2 | Nivel entre 0 y tope | Tope mal medido | Desborde o piso no modelado |
| S3 | Sin pérdidas ni retrasos | Hay filtración | Sobreestima el nivel |
04 · Defectos típicos
El catálogo de horrores del papel
Incompletitud
Falta qué hacer
Sin condición inicial, sin regla cuando la cola está vacía, sin tope. El programador inventa sobre la marcha y cada versión inventa distinto.
Incoherencia
Reglas que chocan
«Llegadas Poisson» en el texto pero «llegadas constantes» en la fórmula. Unidades mezcladas. Horizonte de 12 pasos con calentamiento de 20.
- Supuesto oculto
- Decisión no escrita que el código asume igual («nadie abandona la fila»). Se verifica obligando a escribir S1…Sk.
- Ambigüedad
- «Atención rápida» sin número. Se verifica pidiendo rango y unidad: «atención ~ Exp(media 4 min)».
- Alcance difuso
- Sin rango de validez («vale para 0–30 clientes/hora»). Se verifica exigiendo la frase «este modelo no debe usarse cuando…».
05 · Representación en Python
Auditar la especificación con código
Paradójico pero útil: usamos Python no para simular, sino para verificar el documento. La especificación se escribe como datos y un verificador chequea completitud, rangos y unidades antes de programar el simulador.
Python en tu navegador. Este verificador corre localmente con Pyodide. Rompé a propósito un campo y observá qué chequeo falla.
spec = {
"nombre": "Tanque con tope",
"variables": {"nivel": {"unidad": "litros", "min": 0, "max": 14}},
"parametros": {
"entrada": {"valor": 3, "unidad": "litros/paso"},
"salida": {"valor": 2, "unidad": "litros/paso"},
"tope": {"valor": 14, "unidad": "litros"},
"nivel_inicial": {"valor": 10, "unidad": "litros"},
},
"supuestos": ["S1: flujos constantes", "S2: nivel en [0, tope]"],
"regla": "nivel(t+1) = max(0, min(tope, nivel(t) + entrada - salida))",
}
def verificar_spec(spec):
errores = []
p = spec["parametros"]
v = spec["variables"]["nivel"]
if not spec.get("supuestos"):
errores.append("Falta lista de supuestos S1..Sk")
if not spec.get("regla"):
errores.append("Falta regla de actualización")
if p["tope"]["valor"] <= 0:
errores.append("Tope debe ser > 0")
if not (v["min"] <= p["nivel_inicial"]["valor"] <= v["max"]):
errores.append("Condición inicial fuera de [min, max]")
if p["tope"]["valor"] != v["max"]:
errores.append("Tope inconsistente con max de la variable")
u = {p["entrada"]["unidad"], p["salida"]["unidad"]}
if u != {"litros/paso"}:
errores.append(f"Unidades de flujo inconsistentes: {u}")
return errores
print(verificar_spec(spec) or "Spec OK: completa y coherente")
Probá cambiar el tope a 10 sin cambiar el max, o borrar los supuestos: el verificador lo detecta antes de simular.
Chequeo de casos borde en papel, ejecutado
def regla(nivel, entrada, salida, tope):
return max(0, min(tope, nivel + entrada - salida))
# Casos borde que la especificación debe definir
bordes = [
(0, 3, 2, 14, 1), # arranca vacío
(14, 3, 2, 14, 14), # arranca lleno y quiere desbordar
(2, 1, 5, 14, 0), # quiere ir a negativo
]
for niv, e, s, tope, esperado in bordes:
r = regla(niv, e, s, tope)
estado = "OK" if r == esperado else f"FALLA (dio {r})"
print(f"nivel={niv} +{e}-{s} tope={tope} -> {r} [{estado}]")
06 · Exploración
Laboratorio: ¿pasa tu especificación la auditoría?
Mové los parámetros de la especificación del tanque y observá los 5 chequeos conceptuales. El gráfico muestra la trayectoria que la regla promete, la línea de tope y el piso en cero. Los puntos rojos son violaciones que un buen papel jamás debería permitir.
Auditoría del modelo conceptual
5 chequeos · 0 violaciones = spec verificada
Especificación verificada: inicial dentro del rango, tope positivo y regla con piso y techo.
La curva muestra el nivel prometido por la regla con piso en cero y techo en el tope. La línea punteada es el tope declarado. Si el nivel inicial supera el tope o el tope es inválido, la especificación se rechaza antes de programar.
Preguntas para explorar
- Subí el nivel inicial a 20 con tope 14. ¿Qué chequeo falla? ¿Por qué ningún código puede arreglarlo?
- Bajá el tope a 4 con inicial 10. ¿Qué le pasa a la trayectoria? ¿Qué supuesto (S2) quedó violado?
- Poné entrada 0 y salida 6 con inicial 10. ¿La regla con piso en cero está bien especificada? ¿Qué pasaría si el papel no mencionara el piso?
Ver respuestas sugeridas
- Falla «inicial en [0, tope]». Es un defecto del papel: el programador no puede adivinar si debe recortar, rechazar o ampliar el tope. Se devuelve a la especificación.
- La trayectoria queda aplastada contra el techo: el sistema vive saturado. S2 («nivel en [0, tope]») se cumple a duras penas, pero el diseño es inútil: hay que revisar el tope o el horizonte.
- Con piso bien especificado el nivel baja 10, 4, 0, 0… Sin piso, el papel permitiría niveles negativos (−2, −8…), físicamente imposibles: cada implementación inventaría su propio parche.
07 · Comprensión
Confusiones frecuentes
«Verificar el papel es perder tiempo»
Es la actividad con mayor retorno: una hora de walkthrough evita días de depuración y semanas de recalibración sobre un concepto roto.
«Si el diagrama es lindo, el modelo es correcto»
Un diagrama prolijo puede ocultar supuestos no escritos. La verificación exige checklist, unidades y casos borde, no solo estética.
«Los supuestos son obvios, no hace falta escribirlos»
Lo obvio para vos es invisible para el que programa y para el que valida. S1…Sk siempre escritos, siempre numerados.
«La verificación conceptual usa datos»
No: usa coherencia interna. Los datos aparecen en la validación (Temas 5–8). Mezclarlas lleva a ajustar el papel a los datos sin declarar la calibración.
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: detectar la especificación incompleta
Esta spec no declara qué hacer cuando la cola está vacía. Ejecutá el verificador y completá la regla.
spec_cola = {
"variables": {"clientes_en_cola": {"min": 0, "max": 100}},
"parametros": {"llegadas": 5, "atendidos": 3, "inicial": 0},
"supuestos": [],
"regla": "",
}
def auditar(spec):
faltas = []
if not spec["supuestos"]:
faltas.append("sin supuestos")
if not spec["regla"]:
faltas.append("sin regla para cola vacía")
if spec["parametros"]["inicial"] < 0:
faltas.append("inicial negativo")
return faltas
print(auditar(spec_cola))
Ver solución razonada
Devuelve ['sin supuestos', 'sin regla para cola vacía']. La spec debe agregar S1 («llegadas y atenciones constantes por paso») y la regla cola(t+1) = max(0, cola + llegadas − atendidos). Sin eso, cada programador implementa su propio piso.
Ejercicio 2: cazar la incoherencia de unidades
La entrada está por minuto y la salida por hora, pero la regla las suma directo. Encontrá el error con el verificador.
spec_mix = {
"parametros": {
"entrada": {"valor": 3, "unidad": "litros/minuto"},
"salida": {"valor": 120, "unidad": "litros/hora"},
}
}
e = spec_mix["parametros"]["entrada"]["unidad"]
s = spec_mix["parametros"]["salida"]["unidad"]
print("entrada:", e, "| salida:", s)
print("¿Coherente?", e == s, "-> convertir antes de sumar")
Ver solución
No son coherentes: litros/minuto ≠ litros/hora. La spec debe fijar una unidad común (ej. litros/paso) y la conversión explícita (120 litros/hora = 2 litros/minuto si el paso es 1 minuto). Defecto conceptual, no de tipeo.
Ejercicio 3: escribir la matriz de supuestos
Convertí esta frase vaga en tres supuestos numerados con condición de ruptura.
Ver una posible respuesta
supuestos = [
"S1: llegadas constantes = 5/paso; se rompe si hay hora pico",
"S2: nadie abandona la fila; se rompe si la espera > 15 min",
"S3: un solo servidor sin fallas; se rompe si hay cortes",
]
for s in supuestos:
print(s)
Cada supuesto declara su ruptura y, por tanto, el límite de validez. Cuando la sucursal abra una segunda caja o haya abandonos, sabrás que S2–S3 cayeron y el modelo debe revisarse.
09 · Síntesis
Ideas para recordar
- La verificación conceptual audita el papel: completitud, coherencia y explicitud, sin datos ni código.
- Walkthrough, diagramas, análisis dimensional, casos borde y matriz S1…Sk son las cinco herramientas básicas.
- Todo lo no escrito (supuesto oculto, regla de borde, unidad) será inventado por el programador de forma inconsistente.
- En Python, la spec puede verificarse como datos antes de simular: el verificador corre primero.
- Un papel verificado no garantiza validez real, pero un papel no verificado garantiza problemas.
En el próximo tema pasaremos a la verificación de la implementación: cómo comprobar que el programa ejecuta fielmente ese papel ya auditado.