Lección 16 de 16 · Invariantes de DDD
Agregado: un objeto que se protege
Ver que el agregado verifica su regla antes de modificar su estado, así un error no lo deja a medias.
Metodología · Criterio
Pre-mortem y post-mortem (contrafactual)
Antes de ejecutar: si el append estuviera antes del if, ¿qué estado inconsistente quedaría tras el error?
Metodología · Criterio
Casos con protagonista
Piensa en Ana: el script de administración hacía pedido._lineas.append(...). ¿Qué regla se saltaba?
Metodología · Práctica
Aprendizaje para el dominio (mastery learning)
Es la lección final: si fallas el repaso, vuelve a funciones y excepciones antes de seguir.
t<0 Antes de ejecutar
Lee el código y comprométete con una predicción
Mientras tanto, Python ya hizo su parte de t<0: leyó y compiló el archivo completo. Ninguna variable existe todavía.
programa.py
1class LimiteExcedido(Exception): 2 pass 3 4class Pedido: 5 def __init__(self, limite): 6 self._lineas = [] 7 self._limite = limite 8 9 def agregar(self, producto, precio): 10 if self.total() + precio > self._limite: 11 raise LimiteExcedido(producto) 12 self._lineas.append((producto, precio)) 13 14 def total(self): 15 suma = 0 16 for _, precio in self._lineas: 17 suma = suma + precio 18 return suma 19 20pedido = Pedido(limite=10) 21pedido.agregar("pan", 4) 22pedido.agregar("leche", 5) 23try: 24 pedido.agregar("cafe", 9) 25except LimiteExcedido as error: 26 print("Rechazado:", error) 27print(pedido.total())
t=0 t>0 Ejecución paso a paso
Qué se ejecuta primero y dónde vive cada variable
Avanza con Siguiente paso o las flechas del teclado. Pasa el mouse por una variable para ver a qué objeto apunta.
t=-1
Antes de ejecutar
Python lee y compila el archivo
1class LimiteExcedido(Exception):2 pass3 4class Pedido:5 def __init__(self, limite):6 self._lineas = []7 self._limite = limite8 9 def agregar(self, producto, precio):10 if self.total() + precio > self._limite:11 raise LimiteExcedido(producto)12 self._lineas.append((producto, precio))13 14 def total(self):15 suma = 016 for _, precio in self._lineas:17 suma = suma + precio18 return suma19 20pedido = Pedido(limite=10)21pedido.agregar("pan", 4)22pedido.agregar("leche", 5)23try:24 pedido.agregar("cafe", 9)25except LimiteExcedido as error:26 print("Rechazado:", error)27print(pedido.total())
Salida
(vacía)
Qué pasó
- Antes de ejecutar nada, Python lee el archivo completo y lo compila a bytecode: instrucciones que su máquina virtual entiende.
- Si hubiera un error de sintaxis, el programa fallaría aquí, sin ejecutar ni una sola línea.
- Nombres que aparecen en el código: Exception, LimiteExcedido, Pedido, _limite, _lineas, agregar, append, error, limite, pedido, precio, print, producto, self, suma, total. Ninguno existe todavía en memoria.
Pila de marcos · dónde viven los nombres
Todavía no hay marcos: ninguna variable existe.
Montón · dónde viven los objetos
Ningún objeto todavía.
Idea clave
La regla (no superar el límite) vive dentro de Pedido. agregar verifica antes de tocar _lineas: cuando el café excede, la excepción sale antes del append y el pedido queda con 2 líneas, consistente. Nadie de afuera modifica _lineas directamente.
t>0 Después: repaso sin mirar
Recupera de memoria
Responde sin volver al paso a paso. Para dominar la lección necesitas 3 de 3.
Explícalo con tus palabras (Feynman)
Dominio de la lección
Aún no
- Falta la predicción (t<0)
- Repaso: 0 de 3 (se necesitan 3)