Este post va en parte como respuesta a una duda manifestada por Lily, de México, en la Sección de Preguntas y Respuestas.

El Paradigma Relacional de modelado ya tiene algunas décadas de recorrido. Han sido muchas las discusiones que se han librado así como las conclusiones que se han conseguido en la comunidad internacional de profesionales de informática. A estas alturas ya contamos con un conjunto de prácticas bien aceptadas consideradas inclusive como normas de buen diseño.

Sin embargo, constantemente me encuentro con violaciones a estas supuestas normas. Violaciones no apenas en el mundo laboral sino que también en el mundo académico, lo que me entristece. Pero una profesora amiga me hizo ver el otro dia la razón de por qué ocurren algunas de estas violaciones a las buenas prácticas en el mundo académico. Y lo quiero compartir con ustedes.

Una de las principales Buenas Prácticas a las que me refiero que es pasada a llevar diariamente tanto en empresas como en universidades latinoamericanas es la siguiente: “NO USAR COMO LLAVE PRIMARIA DE UNA TABLA UN CAMPO CON SIGNIFICADO DE NEGOCIO“. Así de simple. Ya no hay discusión seria acerca de este punto.

Y no obstante aún me encuentro con diseños de modelos relacionales donde la llave primaria de alguna tabla es un Rut (documento de identificación chileno), o un RG (el homólogo brasileño), o un DNI argentino, o un Doc ecuatoriano o un código cualquiera que tiene significado dentro del negocio modelado. Peor aún: me encuentro con la combinación de varios atributos de alguna entidad del negocio componiendo a la llave primaria de una tabla. ¿La razón? Y aquí viene el motivo de por qué esto ocurre tanto en el mundo académico como en el laboral: los profesores seguimos enseñando a nuestros alumnos a que modelen el mundo real bajo el paradigma relacional. Pero claro, si les decimos que para guardar los datos de un cliente deben crear una tabla con todos esos campos y que deben poner como llave primaria aquél atributo que no debe repetirse jamás, es obvio que pondrán el identificador del Cliente (el RUT, o el RG o lo que sea) como llave primaria. Y en la medida que vayan creando las demás tablas del modelo con información que cuelga de esta primera, veremos cómo el Código Identificador nacional del cliente se irá esparciendo por el modelo en las llaves foráneas.

¿Y cuál es el problema? No faltará quien lo piense. El problema es que los identificadores únicos del mundo real solo son inmutables en la teoría, porque en la práctica cambian todo el tiempo. Lo veo en los sistemas de mis clientes: Ruts que cambian por equivocación de quien lo digitó, o porque se tuvo que crear uno ficticio temporal ya que en el momento que se ingresó la información no se contaba con el dato y así por el estilo. LOS ATRIBUTOS IDENTIFICADORES CON SIGNIFICADO DE NEGOCIO SOLO SON INMUTABLES EN LA TEORÍA. Imagínese el problema de tener que cambiar ese ID no solo en la tabla principal sino que en todo el resto del modelo donde ese identificador esté esparcido. De hecho algunos motores de base de datos ni siquiera lo permiten. Requieren que los registros se eliminen y se vuelvan a ingresar, y en el orden correcto según la jerarquía de llaves foráneas. Horripilante solución.

¿Entonces qué debe modelar el Paradigma Relacional? ¿No es precisamente el mundo real? La respuesta es simple: YA NO. Exactamente lo que lees: ya no. Para eso llegó y se quedó el Paradigma Orientado a Objetos. El Relacional está lleno de limitaciones siendo una de ellas la ya mencionada. Mientras que la Orientación a Objetos cubre precisamente esas deficiencias (tampoco es la panacea pero es lo mejor que tenemos por el momento). Y ya hace rato que supuestamente aceptamos este nuevo Paradigma de modelado. No obstante seguimos enseñando ambos a nuestros alumnos. No es de extrañar que no aprendan bien ninguno de ellos. Porque los confundimos.

El Relacional aparenta ser la forma más fácil de partir con un nuevo proyecto y, gracias a la ayuda de abundantes herramientas, rápidamente el desarrollador ya puede empezar a llenar de datos sus tablas gracias a alguna grilla al estilo Excel o Access. Pero cuando el modelo se complejiza, o cuando se deben hacer modificaciones, o simplemente al momento de mantener el modelo, lo que era fácil en un principio se convierte en un problema de siete cabezas.

Un diseño Orientado a Objetos por otro lado demanda un mucho mayor conocimiento inicial de lo que se desea modelar. Es un poco más difícil de empezar pero a las horas de iniciado ya es altamente apreciado por su gran versatilidad, reusabilidad y mantenibilidad. Mientras que el modelo relacional empieza apegado al concepto del dominio a modelar, en poco tiempo tiene que ser destruido (conceptualmente hablando) en pro de la eficiencia. El modelo Orientado a Objetos, en cambio, siempre se mantendrá conceptual, y las modificaciones que se le hagan en el futuro también serán conceptuales primero. Con el tiempo no se echará a perder, solo será potenciado.

¿Quiere decir que ya no usaremos para nada el Paradigma Relacional? Eso quisiera uno pero aún no es posible dejarlo completamente. Todavía estamos forzados a utilizar bases de datos relacionales para persistir nuestros objetos en el tiempo. “Persistir nuestros objetos en el tiempo…” Eureka!!! PARA ESO utilizaremos el Paradigma Relacional, no para modelar el mundo real, sino para soportar un modelo orientado a objetos. Esto significa para nosotros profesores que les enseñaremos a nuestros alumnos a tomar un modelo orientado a objetos, como un diagrama UML estático ojalá, y que lo plasmen en un modelo relacional con tablas. Pero primero deben hacer el modelo orientado a objetos. Así es como debería ser.

Y esto se condice perfectamente con las nuevas técnicas, patrones y tecnologías para el mapeo de modelos de objetos a relacional, más conocidos como OR (Object-Relational). Herramientas como el tan renombrado Hibernate (NHibernate para .NET), iBatis, TopLink de Oracle, Kodo de BEA, pronto el nuevo ADO.NET Entity Framework de Microsoft, entre otras, hacen precisamente eso: Mapean y administran las relaciones entre un modelo OO y uno Relacional.

Martin Fowler en su famoso libro Patterns for Enteprise Applications Architecture (el PEAA) recompila los patrones de diseño más ampliamente usados en el mundo para resolver este problema tan en boga: cómo crear esta capa de abstracción que expone hacia la aplicación únicamente funciones y objetos del dominio, pero que internamente oculta toda la interacción con el modelo relacional. Tan aplaudidos han sido estos patrones propuestos que las herramientas ya mencionadas no hacen más que aplicar y automatizar estas ideas. Obviamente esto da para mucha conversación así que volverá a nuestro tema inicial.

Donde quiero llegar es que si miramos ahora el Paradigma Relacional desde la perspectiva recién expuesta, es decir, desde la Orientación a Objetos y las técnicas citadas, nos encontraremos por ejemplo con el Patrón de Diseño Identity Field, el cual propone la creación de un atributo Id por cada una de nuestros objetos principales. Este atributo no tendrá ningún significado de negocio dentro del dominio de nuestro sistema. Será un identificador único generado de acuerdo a alguna de las varias estrategias existentes (autogenerado por la base de datos, generado por algún algoritmo de GUID o simplemente a partir de algún contador que manejemos). Y este atributo Id será llevado al modelo relacional como la llave primaria de la tabla correspondiente a nuestro objeto. Y será el mismo que será arrastrado probablemente através de todo nuestro modelo de datos como llave foránea.

En el ejemplo antes mencionado, nuestro objeto Cliente tendrá por lo tanto un atributo Id. Este Id se corresponderá con el campo cliente_id dentro de la tabla Clientes. Ese campo cliente_id será llave primaria y será arrastrado como llave foránea (obedeciendo el patrón de diseño Foreign Key Mapping) a tablas como por ejemplo facturas, liquidaciones, pólizas, etc. Pero estas últimas también tendrán sus correspondientes factura_id, liquidacion_id, poliza_id, etc, como llaves primarias. Lo anterior no quiere decir que si existe un atributo con significado de negocio que no debe repetirse en toda la tabla, no podamos definirlo como un Unique Index. Podemos definir todos los constraints que necesitemos.

Se acaban las llaves foráneas compuestas por lo tanto, excepto cuando necesitemos crear una tabla que solamente sirva para expresar una relación varios-a-varios, probablemente una tabla con solo 2 campos: cada uno correspondiente al id de la tabla de origen obedeciendo al patrón de diseño Association Table Mapping.

Mis alumnos que han preguntado por qué herramientas generadoras de código de mapeo entre objetos y tablas relacionales, como Netbeans o Eclipse por ejemplo, generan código para llaves primarias simples (con un solo campo id) y no dan buen soporte para llaves compuestas, ya saben el motivo. Sigan estas buenas prácticas expuestas y las herramientas les servirán sin problemas.

Para aquellos que tengan opiniones distintas o deseen discutir más acerca de estos temas, les invito cordialmente a que lo hagamos aquí mismo. En mi siguiente post haré mi propuesta de cómo pienso que debería ser un programa académico para ingenieros informáticos en cuanto a desarrollo de software se refiere, tomando en consideración las opiniones expresadas anteriormente.