Software Architect · Módulo 08

El código se puede reescribir en un trimestre. Los datos, los contratos y los errores históricos a veces viven toda la vida del producto.

Invariants · normalization · migration · OLTP · OLAP

§ 01

El modelo de datos tiene que proteger el sentido del negocio, no solo servir cómodamente a la pantalla del momento.

Los datos envejecen más lento que el código

El interior se puede rehacer rápido. Una cimentación mal vertida se queda con la casa por mucho tiempo.

El framework, la UI e incluso el lenguaje de programación pueden cambiar. Pero las tablas, los eventos, las claves, los registros históricos y los reportes externos siguen vivos. Por eso el modelo de datos es una de las decisiones arquitectónicas más caras.

El arquitecto tiene que ser explícito sobre los invariants — cosas que siempre deben ser verdad. Por ejemplo: un pedido no puede estar pagado sin un payment intent; una entrada del ledger no puede desaparecer; un balance no puede quedar en negativo sin un overdraft permitido.

Normalización y denormalización no son una religión

El archivo guarda los documentos originales. La vitrina hace copias para hojear rápido. Las dos formas hacen falta — para trabajos distintos.

La normalización reduce duplicación y el riesgo de drift. La denormalización acelera las lecturas y simplifica la read model. Los sistemas OLTP se preocupan por las transacciones y por la consistencia del estado actual. Los sistemas OLAP se preocupan por queries analíticas, historia y agregaciones.

El error es intentar servir perfectamente el checkout, el dashboard en realtime y el reporte contable con un solo modelo. A menudo necesitas un modelo source-of-truth y projection / read models aparte.

§ 02

Un buen modelo hace que los estados imposibles sean imposibles — o, al menos, explícitamente ilegales.

Ejemplo: pricing snapshot en el pedido

El ticket de la tienda guarda el precio en el momento de la compra, aunque mañana el producto suba.

Un order guarda no solo product_id, sino un snapshot de precio, moneda, impuestos, descuento y nombre en el momento de la compra. El catálogo puede cambiar, pero el pedido histórico sigue siendo correcto.

Es una denormalización pequeña que protege el sentido del negocio. Sin ella, el reporting y el soporte al cliente empiezan a depender del estado actual del catálogo.

Antiejemplo: la tabla universal events_json

Un almacén sin estantes parece flexible — puedes poner cualquier cosa en cualquier lugar. Después nadie encuentra lo que busca.

El equipo mete todas las entidades del negocio en una sola tabla con una columna JSON porque "es más flexible". Rápido al principio. Después aparecen migraciones dentro del JSON, schemas implícitos en el código, queries lentas, sin constraints y sin forma de saber qué datos son válidos.

JSON es útil para atributos extensibles y para eventos, pero no debería reemplazar el modelo donde hay invariants estrictos.

Autoevaluación
  • ¿Qué invariants protege la base de datos y cuáles solo el código? - ¿Qué datos son la source of truth? - ¿Qué le pasa a la historia cuando cambia una tabla de referencia? - ¿Cómo se ve una migración segura de este modelo?