La Evolución de las APIs de Acceso a Datos de Microsoft - Parte I
En este increíblemente amplio mundo del desarrollo de software existen temas que realmente me fascinan por su gran impacto en la forma como construimos software hoy en día. Entre estos temas están las metodologías de desarrollo, orientación a servicios, arquitecturas de referencia, clientes inteligentes y acceso a datos, entre otros. Este último tema, en particular, es uno de los que más llama mi atención, puesto que, por años, la forma en que accedemos a los datos y los transformamos para utilizarlos en nuestra aplicación cliente ha sido motivo de grandes frustraciones y mucha, pero mucha polémica.
En vista de ello, recientemente he estado revisando las últimas propuestas de Microsoft en torno al tema de acceso a datos y me he topado con que actualmente existe toda una revolución en la forma como pensamos y trabajamos con los datos. Esto se origina en la Plataforma de Datos y Entidades (Entity Data Platform) que Microsoft ha planificado y que estará implementando incrementalmente en futuras versiones de ADO.NET, SQL Server y varias tecnologías y herramientas relacionadas.
Me gustaría entonces, antes de empezar a abordar toda esta nueva serie de innovaciones, transcribir aquí un resumen de la evolución de las APIs de acceso a datos que Microsoft ha desarrollado hasta la fecha. Esto permitirá tener una mejor comprensión de cómo llegamos hasta aquí y hacia dónde vamos. Dado que yo ingresé al mundo del desarrollo de software apenas un poco antes del advenimiento de la plataforma .NET, me es imposible describir por mi mismo esta evolución, y es por ello que más bien me apoyaré en la experiencia de alguien que estuvo presente durante todo este trayecto, como Mike Pizzo, Arquitecto en el equipo de Data Programmability de Microsoft. Mike ha escrito una excelente serie de artículos que transcribiré (y resumiré un poco) en este y en un siguiente post.
Los Primeros Años
Uno de las primeras tecnologías que ofreció una forma estándar de conectarse a bases de datos fue ODBC (Open DataBase Connectivity). ODBC fue diseñado con un propósito específico: ser una interfaz común hacia una base de datos relacional y ha sido tan exitoso y popular que incluso se lo incorporó como anexo a la especificación SQL 92.
Más adelante, Visual Basic se convirtió en un lenguaje muy popular por sus capacidades de automatización y, como era de esperarse, la gente empezó a requerir invocar las APIs ODBC desde Visual Basic. Sin embargo, la interfaz de de tipo C de ODBC no podía ser consumida por VB. Afortunadamente Microsoft Access sí soportaba la ejecución de queries contra orígenes de datos ODBC y también soportaba el tipo de automatización que utiliza VB a través de su API Data Access Object (DAO). Con ello ya era posible escribir aplicaciones contra ODBC utilizando VB.
El problema de DAO radicaba en que necesitaba pasar por el motor "Jet" (Joint Engine Technology), el cual construía conjuntos de claves para cada resultado para así lograr hacer luego queries más avanzados contra datos remotos. Esto constituía una sobrecarga en rendimiento (por sucesivos viajes de ida y vuelta) para quienes no necesitaban la funcionalidad adicional.
Fue entonces cuando, respondiendo a la creciente demanda de una forma más eficiente de conectarse a ODBC, el equipo de Visual Basic creó RDO (Remote Data Objects). RDO ofrecía los mismos patrones de programación que DAO pero consumiendo directamente a ODBC (en lugar de pasar por Jet). RDO se hizo muy popular, pero así mismo dió inicio a la confusión entre cuál es la forma apropiada de acceder a orígenes de datos ODBC. Esto empeoró cuando se introdujo ODBCDirect, que no era más que una nueva modalidad de DAO que no creaba conjuntos de claves de forma predeterminada, mejorando así considerablemente el rendimiento.
Luego de eso la industria introdujo una gran oleada de ideas acerca de la construcción de componentes orientados a objetos que pudieran trabajar de forma distribuida. Llegó entonces el momento de agregar soporte para acceso a datos al popular Component Object Model (COM) de Microsoft.
Componentes de Acceso a Datos
COM encajó muy bien con la idea de construir componentes de acceso a datos reutilizables y fué así que nació OLE DB (OLE DataBase). OLE DB no solo era una interfaz basada en COM especialmente diseñada para trabajar con datos, sino que también soportaba el concepto de base de datos "federada" (o componetizada). Esto significa que podía definirse una interfaz base común llamada "Rowset" que pudiera usarse para representar una serie de "tuplas" (filas) sin importar de dónde vinieran ó qué representaran (el resultado de un query, una tabla o vista, un ISAM, un archivo de texto ó de Excel, el Registro de Windows, un email, servicios de directorio, etc). Y sobre esta interfaz Rowset base, se podía usar la QueryInterface de COM para detectar si se soportaba alguna funcionalidad adicional, como scrolling, actualizaciones, navegación por índices, etc.
Gracias a esta representación común de datos, ahora era posible construir componentes comunes para agregar funcionalidad contra cualquier tipo de dato, como por ejemplo un motor común de indexamiento, un componente común para manejo de cursores, un procesador de queries común que pudiera proveer funcionalidad de bases de datos sobre una multitud de orígenes de datos tanto relacionales como no relacionales. Así mismo, el hecho de que la representación de los datos de origen fuera la misma de los resultados finales agregaba beneficios de rendimiento así como un modelo común para que código y herramientas puedan trabajar con conjuntos de datos.
Esta habilidad de OLE DB de exponer interfaces comunes sobre una multitud de tipos de orígenes de datos facilitó la creación de servicios distribuidos. De hecho, Microsoft SQL Server usa un OLE DB Rowset hoy en día como su interface interna entre el Motor Relacional y el Motor de Almacenamiento, así como soporta queries distribuidos entre SQL Server y otros orígenes de datos heterogéneos.
Tal como ODBC, OLE DB era una interfaz de "bajo nivel" que usaba punteros, manejo explícito de memoria y control del tiempo de vida explícito. Así mismo, requería de una API que lo envuelva (wrapper) para que pueda estar disponible para lenguajes de automatización como Visual Basic. Fue por ello que llegó ADO (ActiveX Data Objects).
ADO seguía el mismo modelo de Conexión/Comando/Recordset de DAO, pero incluía tecnología de equipo de Fox para proveer un motor de cursores local avanzado. Este "Recordset Desconectado" exponía el modelo del Recordset en la forma de un cursor sobre un flujo (stream) de resultados desde la base de datos y las propiedades del Recordset se utilizaban para determinar si los resultados eran "scrollable" ó actualizables y qué tipo de aislamiento tenían los resultados con respecto a los cambios hechos al almacén de datos. El Recordset Desconectado usaba metadatos del query original para generar sentencias de inserción, actualización y eliminación para propagar los cambios locales de regreso al almacén de datos.
Juntos, ADO y OLE DB formaron lo que Microsoft denominó "Microsoft Universal Data Access".
Y una vez más, vino un momento de grandes cambios. Microsoft reconoció que estaban perdiendo popularidad entre los desarrolladores en favor de Java, dado que COM, en su forma original, era complejo y cosas como el conteo de las referencias, manejo de memoria, etc, eran difíciles de manejar. Así, Microsoft inició un proyecto ambicioso para desarrollar un nuevo framework administrado, independiente del lenguaje, para escribir aplicaciones (.NET Framework), junto con un nuevo lenguaje de programación (C#). Una de las fortalezas de esta nueva plataforma era que sus varios componentes y APIs fueron diseñados y revisados como un todo, en lugar de una serie de tecnologías semi-relacionadas creadas por equipos aislados.
En el próximo post cubriré la parte restante del artículo de Mike en la cual veremos cómo Microsoft concibió ADO.NET y recientemente las nuevas ADO.NET Entities y LINQ.