La tabla no es el concepto

Podés definir el concepto a la perfección y aun así modelarlo mal.

Un reporte de márgenes en una empresa manufacturera levantó la alarma. Cientos de productos se vendían por debajo del costo. Algunos sin precio de venta del todo, solo un costo interno y un margen negativo que hacía ver todo el dashboard de rentabilidad como si estuviera roto. Finanzas abrió una investigación. Alguien estaba poniendo precios para perder plata, o los datos de costo estaban mal, o ambas cosas.

Ninguna de las dos. La definición de “producto” estaba bien. Cualquiera en esa sala te podía decir con exactitud qué era un producto. El problema era la tabla.

La tabla Productos tenía productos, y también tenía materiales intermedios, productos en proceso, muestras, códigos internos de cosas que se mueven entre plantas pero nunca llegan a un cliente. Ninguno de esos tiene precio de venta, porque ninguno se vende. Corré un reporte de márgenes sobre esa tabla y te salen cientos de “productos” sin ingreso y con costo completo. El número no estaba mal calculado. La población tenía la forma equivocada.

Este es el antipatrón que se esconde debajo del anterior. Podés ponerte de acuerdo en lo que una cosa es y aun así estar en desacuerdo (en silencio, de forma estructural) sobre cuáles filas son esa cosa. Ponerse de acuerdo en la definición es la parte fácil. La tabla codifica una respuesta distinta, y la tabla es la que tus reportes leen de verdad.

El flag que la demo sí acertó

Acá viene la parte que debería doler, porque invierte la queja de siempre.

La mayoría de las veces la demo del vendor se saltan la parte difícil. El camino feliz corre, los datos vienen limpios, y la realidad sucia en la que vivís nunca aparece en la diapositiva. Acá no. Abrí AdventureWorks (la base de datos de ejemplo de Microsoft, la de todos los tutoriales) y mirá la tabla Product. Hay una columna que se llama FinishedGoodsFlag. La demo modeló la distinción. Sabía, de fábrica, que no toda fila en una tabla de productos es un producto vendible.

Y después las bases de datos de producción reales la tiran a la basura. El flag existe, o una columna parecida, y nadie la llena, nadie filtra por ella, y en unos pocos años la tabla se llena de productos terminados, intermedios, muestras y códigos obsoletos, todo plano, todo igual de “producto”. La demo modeló bien y los practitioners se olvidaron. Eso es lo contrario de lo que suelo argumentar: la herramienta te entregó la distinción y la disciplina la botó.

El mecanismo es simple. Un material intermedio tiene costo y no tiene precio. Una muestra no tiene ninguno de los dos. Contalos como productos y tu conteo de productos se infla. Sacá un promedio de margen sobre ellos y el promedio es ficción. Armá un catálogo con ellos y la mitad no se puede vender. El concepto “producto que vendemos” nunca cambió. La extensión (las filas reales en la tabla) dejó de coincidir con él, sin que nadie se diera cuenta.

Nadie definió “producto” mal. La tabla dejó entrar cosas que el concepto excluye, y nadie estaba cuidando la puerta.

La falla opuesta: la tabla que borra la diferencia

La tabla de productos falló amontonando tipos distintos en una sola pila indiferenciada. La siguiente falla es su imagen en el espejo: colapsar conceptos genuinamente distintos en un solo tipo porque resulta que comparten algunas columnas.

Tomemos como ejemplo una universidad. Profesores y estudiantes comparten atributos: un ID, un nombre, un correo, una fecha de nacimiento. Así que la movida tentadora es una sola tabla Persona que tenga a ambos. Más limpio, menos tablas, menos duplicación. Y cuando el diseño no es disciplinado, y muchas veces no lo es, ahí se queda: la diferencia entre un profesor y un estudiante deja de existir en cualquier parte del esquema.

Un profesor y un estudiante no son la misma cosa, aunque ambos sean personas. Tienen relaciones distintas con la institución, ciclos de vida distintos, reglas distintas, todo lo que importa distinto una vez que pasás de nombre y correo. El traslape termina en las columnas. Aplanalos en Persona y optimizaste para las columnas que comparten y botaste el significado de lo que cada uno es.

Así que la reparación obvia es especializar: mantener Profesor y Estudiante como tablas propias con una llave foránea hacia Persona, atributos compartidos en el padre, distinción preservada. Esa es la respuesta que yo te habría dado, y es la respuesta que escribí primero en esta sección. Está mal, y lo que la delata es la misma regla que condena la fusión.

Los subtipos tienen que ser mutuamente excluyentes y exhaustivos: cada instancia del padre cae en exactamente uno, y ninguna se queda afuera. (Simsion y Witt lo argumentan en Data Modeling Essentials, y vale leer su versión.) Es una restricción estricta y se gana el sueldo, porque una partición limpia es lo que te permite decir algo del padre.

Ahora corré la universidad contra eso. ¿Una persona es exactamente uno de profesor o estudiante? No. El asistente de posgrado es los dos al mismo tiempo, y no es un caso borde que haya que manejar: es una población entera con oficina propia. ¿Toda persona es uno de los dos? Tampoco: la registradora, el conserje, el egresado, el postulante que rechazaron, el papá que paga la matrícula.

La partición falla en las dos pruebas, y ese fallo es lo más útil de todo el ejercicio. Te está diciendo que las cosas que llamaste subtipos nunca fueron tipos del padre. Profesor y Estudiante no son especies de persona. Son roles que una persona sostiene respecto de la institución: adquiridos en una fecha, sostenidos por un período, sostenidos junto con otros roles, entregados y a veces retomados. Un subtipo es lo que algo es. Un rol es lo que algo está haciendo, por ahora, en relación con alguien más.

Modelá el rol y todo lo que te estaba peleando se calla. Persona guarda al ser humano: el nombre, el ID, la fecha de nacimiento, los hechos que siguen siendo ciertos exista o no la universidad. Matrícula y Nombramiento guardan los roles, cada uno con su inicio, su fin, sus reglas, su ciclo de vida. El asistente de posgrado saca dos filas y ninguna contradicción. El conserje saca un tercer tipo de rol sin deformar ninguno de los dos primeros. A nadie hay que archivarlo mal para que quepa en la tabla.

“Entonces nunca subtipo personas.” No. El supertipo nunca fue el enemigo. Hace la prueba sobre otro para de entidades y pasa sin problemas, usando casi la misma palabra.

Casi todos los sistemas legales parten al sujeto de derecho en persona física (o natural) y persona jurídica. El ser humano de un lado; del otro, la entidad que existe porque alguien la inscribió. Esa partición no se traslapa, y no es cuestión de gusto ni de conveniencia: un sujeto es un ser humano o es una ficción legal, nunca los dos, ningún día, en ninguna jurisdicción. Nada se pasa de un lado al otro. Y los subtipos cargan peso real, que es la señal de que se están ganando el lugar: fecha de nacimiento y cédula de un lado, fecha de constitución y registro fiscal del otro, nada compartido y nada puesto en nulo porque el otro tipo no lo usa. La exhaustividad es la mitad que tu jurisdicción sí puede doblar, así que verificala en lugar de asumirla: los fideicomisos y los patrimonios autónomos son donde viven las sorpresas. Lo de no traslaparse aguanta igual.

El empresario individual parece el contra-ejemplo y termina siendo el argumento. Se siente como que debería ser los dos a la vez. No lo es: el sujeto de derecho es la persona física, y “el negocio” es un rol que esa persona sostiene. La excepción aparente es el modelo de roles llegando por otro camino.

Así que la diferencia nunca fue generalizar contra especializar. Era el nivel de abstracción, y el test es lo que lo encontró. Profesor y estudiante eran los subtipos equivocados porque nunca fueron tipos de nada. Física y jurídica son los correctos porque no son otra cosa.

Y fijate qué te abre el subtipo legítimo. Una vez que la empresa está modelada como lo que es, una persona jurídica, quedás libre de modelar aparte lo que te está haciendo. Que lo vas a necesitar, porque las organizaciones rompen la regla del traslape con la misma constancia que las personas. Una empresa en tus datos es cliente y proveedor y competidor, muchas veces en el mismo trimestre. Tipificala como uno de los tres y vas a estar manteniendo la excepción mientras el modelo viva. Eso no son tipos de empresa. Son roles que sostiene hacia vos, y los roles son la parte de la que de verdad tenés datos.

Hay un nombre para el primo de este instinto en el mundo de las tablas de catálogo. Joe Celko pasó años advirtiendo sobre la One True Lookup Table: el impulso de meter todo código y categoría en una sola tabla todo-propósito. (Paul Keister acuñó el término; Celko hizo famosa la crítica.) Una tabla de catálogo no es una tabla de entidad, así que no es exactamente la misma falla. Pero el instinto sí lo es: una tabla para gobernarlas a todas, cómoda para el que la construye y ruinosa para todos los que la leen.

Eric Evans le entra por el otro lado. El punto entero de un modelo, en Domain-Driven Design, es servir al lenguaje que los expertos del dominio realmente hablan. Cuando tu modelo fusiona dos conceptos que el negocio mantiene separados (cuando “profesor” y “estudiante” se vuelven una “persona” indiferenciada), dejaste de hablar el lenguaje del dominio. El modelo se volvió más simple y el significado se escapó. Como lo pone Evans, el uso persistente del lenguaje compartido obliga a los puntos débiles del modelo a salir a la luz. Una tabla Persona que no te puede decir quién enseña y quién se matricula es un punto débil escondido a plena vista. Y escuchá cómo lo dice el dominio, además: nadie en una universidad dice “es una persona de tipo profesor”. Dice que enseña, y que el otro se matricula. El negocio estaba hablando en roles desde el principio.

Mismo eje, extremos opuestos

Da un paso atrás y las dos fallas son el mismo error apuntando en direcciones opuestas.

Qué hace El costo
La tabla de productos No especializa: amontona tipos distintos Conteos y márgenes incluyen cosas que no son productos
La tabla de personas Tipifica un rol como si fuera un tipo de cosa Pierde el significado de profesor vs. estudiante

Una se niega a trazar una línea que existe. La otra borra una línea que importa. Las dos aplanan una taxonomía real en una sola tabla indiferenciada, y las dos te dejan con una tabla cuya forma ya no coincide con el concepto que dice contener.

Hay un lenguaje viejo para lo que está pasando. La intensión de un concepto es lo que significa: qué hace que algo sea un producto, o un profesor. La extensión es la población real: cuáles filas existen, y de qué tipo. Ponerse de acuerdo en la intensión no hace nada por la extensión. Podés escribir la definición perfecta y aun así construir una tabla que no esté de acuerdo con ella.

Porque acá está lo que una tabla realmente es: una afirmación sobre lo que existe. Cada fila asegura “esto es uno de estos”. Aplaná la tabla y hiciste una afirmación que nunca quisiste hacer (que los intermedios son productos, que los profesores son intercambiables con los estudiantes), y cada query río abajo toma esa afirmación al pie de la letra.

Toda métrica hereda la forma de la tabla

Por esto no es un problema cosmético. Una métrica es tan honesta como la población que tiene debajo. Conteo de productos, margen promedio, headcount, total de clientes activos: ninguno se calcula desde la definición de tu glosario. Se calculan desde las filas de la tabla. Si la forma de la tabla está mal, la métrica está mal, y no porque alguien haya cometido un error de aritmética. El error se cometió en tiempo de diseño y se ha heredado desde entonces.

Y como la mayoría de estos problemas, sobrevive porque se ve normal. La tabla siempre tuvo esta forma. Nadie recuerda haberlo decidido; así funciona el sistema y ya. Eso no es un hecho técnico, es deuda de modelado que se endureció hasta volverse una convención que nadie vuelve a examinar.

La cura: modelá la ontología, no la conveniencia

Las dos fallas se arreglan con la misma disciplina: modelá los límites reales del concepto en lugar de las columnas que casualmente se traslapan.

Para la tabla de productos, eso significa especializar. Producto terminado, material intermedio, muestra: tipos distintos bajo un padre común, cada uno con sus propias reglas sobre qué es y qué podés hacer con él. El FinishedGoodsFlag es la versión mínima viable de esto; una verdadera jerarquía de tipos de producto es el arreglo de fondo. De cualquier forma, la regla es la misma: un reporte de márgenes debería consultar “productos terminados”, no “todo lo que terminó en la tabla de productos”.

Y vale medir las herramientas contra eso, porque la industria por fin está construyendo para esto. Microsoft viene metiendo un ítem de Ontology en Fabric: tipos de entidad, propiedades, relaciones, todo amarrado a datos que ya viven en OneLake. El diagnóstico detrás es exactamente el correcto, y es el diagnóstico de este post: un concepto merece modelarse por encima de cualquier tabla individual.

La implementación, a agosto de 2026, está en preview, y cae del lado equivocado de este argumento en dos puntos. Un tipo de entidad acepta un solo binding de datos estáticos, y no podés combinar datos estáticos de más de una fuente en él. Tampoco hay un paso donde acotés la fuente a un subconjunto de sus filas: escogés una tabla y te llevás la tabla. Así que amarrá Product a esa tabla Productos y tu tipo de entidad Product va a contener los intermedios y las muestras, fielmente. Generá la ontología desde un semantic model y obtenés un tipo de entidad por tabla, por diseño. Y no hay subtipo (un tipo de entidad acepta un nombre y unas propiedades, sin padre), así que “producto terminado bajo producto” no es algo que hoy podás decir.

La mitad de la cura sí sobrevive, y no es la mitad que yo esperaba. Las relaciones cargan atributos, vigencia incluida, que es el modelo de roles funcionando como debe.

El workaround es la parte que vale la pena masticar. Construís tablas filtradas y modeladas a propósito, puramente para alimentar la ontología. Eso funciona. Y fijate lo que significa: el modelado no subió a la capa semántica. Se quedó abajo en la tabla, donde siempre estuvo, y la ontología heredó la forma que le entregaste.

Nada de esto es un veredicto. Usualmente Microsoft saca una versión mínima viable y le va agregando funcionalidades, esto es temprano en ese ciclo, y espero que estos huecos se cierren. La dirección es buena noticia de verdad para cualquiera que lleve años argumentando que los conceptos van por encima de las tablas. Solo que todavía es muy temprano para sacarle provecho alto. Y ninguna versión, por completa que llegue a ser, te va a eximir del modelado.

Eso hicimos, a mano, años antes de que existiera un ítem de ontología al que alimentar. La primera versión del filtro fue la obvia: en la capa analítica, incluir solo los productos que alguna vez se hubieran facturado.

select distinct ProductCode from Sales

Funcionó. Los intermedios se fueron, las muestras se fueron, y el reporte de márgenes dejó de reportar crímenes.

También tuvo un efecto colateral que yo no había previsto. Un producto perfectamente vendible que todavía no se vendió no está en esa lista. Los artículos nuevos, los de temporada, aquellos a los que el catálogo le está apostando para el próximo trimestre: todos se caían de un reporte sobre los productos que vendemos. La consecuencia fue leve y vivimos con eso un tiempo corto, pero mirá lo que había pasado. Arreglé una población demasiado ancha volviéndola demasiado angosta. La extensión seguía sin coincidir con el concepto. Solo que ahora fallaba para el otro lado.

Vale la pena nombrar ese error, porque es fácil de repetir. Filtrar por historial de ventas define el concepto por su extensión, por lo que pasó, cuando lo que yo necesitaba era su criterio. Haber vendido es evidencia de que un producto es vendible. No es lo que lo hace vendible.

Lo que finalmente lo arregló fue otra tabla: la lista de precios. Un producto con precio es uno que el negocio decidió vender, lo haya comprado alguien o no. Eso es una condición de pertenencia, mantenida por gente que la mantiene por sus propias razones, y dice lo que el FinishedGoodsFlag siempre estuvo tratando de decir. La población dejó de ser un residuo de transacciones pasadas y pasó a ser una afirmación sobre la intención.

Para la tabla de personas, significa correr el test de partición antes de decidir dónde va cualquier cosa. Mutuamente excluyentes, exhaustivos: ¿toda instancia cae en exactamente una cubeta, y toda instancia cae en alguna? Persona física contra persona jurídica pasa. Profesor contra estudiante no. Si pasa, especializá: subtipos distintos bajo un padre común, atributos compartidos en el padre, y el supertipo es legítimo precisamente porque los subtipos le sobreviven. Si falla, dejá de construir subtipos. Nunca estabas viendo tipos de una cosa. Modelá los roles: el sujeto en un lado, cada rol que sostiene como entidad propia con sus fechas y sus reglas. El test toma un minuto y te dice en cuál de los dos modelos estás de verdad.

Esa es la regla entera, y corta para tres lados: especializá lo que genuinamente difiere; generalizá solo lo que es genuinamente igual; y cuando ninguna de las dos calza porque las categorías se siguen traslapando, lo que tenés en la mano es un rol, no un tipo. Modelá los límites del concepto, no la conveniencia del esquema.

Cierre

La definición vive en el diccionario. El significado vive en la forma de la tabla.

Podés correr un taller impecable, hacer que cada stakeholder se ponga de acuerdo en qué es un producto y qué es una persona, escribirlo todo en un glosario limpio, y aun así entregar un modelo que contradice calladamente cada palabra de eso. Porque el acuerdo fue sobre lo que los conceptos significan, y la tabla es una afirmación sobre cuáles filas son esos conceptos. Esas son afirmaciones distintas, y solo una de ellas es la que tus reportes leen cada mañana.

Una tabla que respeta los límites reales del concepto dice la verdad por construcción. Una tabla que los aplana dice una mentira que nadie eligió decir, y la sigue diciendo, fila tras fila, hasta que alguien abre un reporte de márgenes y se encuentra con una escena del crimen que nunca fue un crimen.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *