El problema de la diferencia de impedancia
Víctor Manuel Jáquez LealLa gran mayoría de los programadores estarán de acuerdo que las aplicaciones que ponen comida en la mesa son las aplicaciones con acceso a bases de datos, ya sean aplicaciones web, de escritorio, o a través de cualquier otra presentación. Entonces desde que estudiamos programación, nuestra primera ambición es conectarnos a un manejador de bases de datos (DBMS). Pero, aunque nos emocione saber utilizarlo, aún permanecemos en un estado de inocencia programativa, la mayoría de nosotros, que haría reír a muchos programadores de primer nivel.
Aunque la programación de aplicaciones con acceso a bases de datos es algo que existe desde varias décadas, los programadores seguimos enfrentando un problema aún sin solución definitiva: el diferencial de impedancia (impedance mismatch). Éste término fue acuñado en la ciencias computacionales a mediados de los años ochenta y se refiere a un problema electrónico cuando no podemos conectar dos componentes con diferente impedancia. Esto mismo pasa cuando intentamos hacer sinergia entre nuestra aplicación, escrita de manera procedural, con nuestros manejador de base de datos, que trabaja de manera relacional. El mundo procedural y relacional son dos universos paralelos para trabajar con datos, sin intersección natural aparente.
La solución ad-hoc que la mayoría de los programadores usa, sin sentarse a pensar seriamente en esta cuestión, es cocinar cadenas de texto con las instrucciones SQL a partir de las estructuras de datos utilizadas en nuestro código procedural. Sin embargo este enfoque tiene fuertes limitantes: primero, no podemos evaluar la instrucción SQL cocinada sino hasta tiempo de ejecución, lo que retrasa el ciclo de programación, además resulta muy difícil asegurar que toda instrucción SQL elaborada sea siempre válida y correcta. Es por esta limitante que vienen los clásicos ataques de seguridad basados en inyección del SQL. Por último, cuando trabajamos con este esquema, terminamos por colocar nuestras operaciones a la base de datos por cualquier lado de nuestro código, en donde nos demos cuenta al momento de programar que necesitemos una, lo que hace muy costoso de modificar nuestro código cuando llega la hora de darle mantenimiento. En otras palabras, es un problema de semántica, ya que por un lado tenemos el significado de nuestro programa, verificado por nuestro compilador, y la semántica del SQL, que sólo conocerá nuestro DBMS en momento de ejecución.
Al hacerse patente este problema, en los años noventa surgió una alternativa de solución, a la que se le conoce como Mapeo Objeto/Relacional. Esta es una técnica de programación en la cual vinculamos nuestra base de datos con nuestra aplicación orientada a objetos, creando objetos virtuales de nuestra base de datos. Es decir, si existe una tabla llamada empleado, creamos un objeto empleado, el cual se encargará de hacer las operaciones necesarias con la base de datos para insertar, extraer y actualizar tuplas de dicha tabla. Esta técnica se ha ido depurando hasta llegar a un patrón de diseño de software conocido como DAO (Data Access Object), del cual me gustaría hacer un artículo más adelante. Actualmente existen alternativas, tanto comerciales como libres, para automatizar la creación de los esqueletos de código necesarios para montar este tipo de soluciones.
En mi corta experiencia como programador he visto aplicaciones que intentan hacer uso de esta alternativa de solución, pero las implementaciones no hacen uso completo del patrón DAO, quedándose muy limitadas y terminan haciendo caso omiso del patrón para volver a la inserción espaguetti de instrucciones SQL. Lo que busca el patrón DAO es encapsular las llamadas a la API del DBMS para lograr un menor acoplamiento entre las clases, facilitando los cambios en el código, pero no se elimina el problema de la semántica.
A partir de la aparición de Java en el mercado, en la segunda mitad de los 90s, junto con el resto de los lenguajes que funcionan dentro de una máquina virtual que permite operaciones de introspección y otras dulzuras en tiempo de ejecución, surgieron otras alternativas de solución a este problema. En primera instancia, aparecieron marcos de trabajo (frameworks) que buscaron automatizar la generación del patrón DAO, en busca de lo que se conocerían como objetos persistentes, tal como los EJB de entidad. Ya entrado en el siglo XXI, ha aparecido una nueva tecnología que busca una persistencia más transparente al programador conocido como hibernación. La persistencia busca que, de manera declarativa, establezcamos los objetos persistentes y su reglas relacionales, entonces el marco de trabajo se encarga de hacer las operaciones sobre la base datos, haciendo aun lado el problema de la semántica para el programador, pero perdiendo de vista las distintas capacidades de procesamiento que ofrece cada DBMS específico.
Volviendo y refraseando el problema de la diferencia de impedancia, podemos decir que “Cualquiera que sea el modelo de programación utilizado, este debe permitir que, complejas e intensivas operaciones en datos, puedan ser lanzadas por los programas para ejecutarse en un DBMS”.
Si nos fijamos en las soluciones propuestas observaremos dos principios:
- Todo el programa, incluidas las consultas al DBMS, deben estar especificadas dentro de una semántica unificada. Es decir, que no existan desconexiones de significado entre las operaciones que se envían al DBMS y lo que se realizan dentro de la aplicación.
- Buscar la eficiencia en la ejecución delegando las operaciones intensivas en datos al DBMS y las intensivas en cálculos a la aplicación, aunque no necesariamente sea así.
Entonces el problema del diferencial de impedancia nos obliga a resolver ambos problemas de manera simultánea, no obstante las soluciones propuestas sólo resuelven una en detrimento de la otra. Por ejemplo, el mapeo objeto/relacional (con sus derivados deformes que pululan), resuelve la eficiencia en la ejecución, pero rompe con al semántica, en cambio, la persistencia elimina las diferentes semánticas pero no tiene mecanismos claros para definir dónde se ejecutar las operaciones intensivas en datos.
El problema presentado aquí es un campo abierto para la investigación en la ingeniería del software y las ciencias computacionales. Si a alguien se le ocurre una solución que acabe con ambos puntos del problema de sólo brochazo, será famoso y deseado por el sexo opuesto.
Bibliografía:
Googlazos ahora anónimos, pero en especial el artículo Safe Query Objects: Statically-Typed Objects as Remotely-Executable Queries.