Thursday, September 29, 2011

La (des)integración entre aplicaciones


Escribo este post en la previa a un parcial. Por suerte, hoy me ha tocado algo simple para cualquier programador: Unos 5 patrones de diseño, y algunas cosas de encriptación y algunos conceptos básicos de OO. Lo que nos mata de esta materia es el trabajo de campo que hay que armar (una suerte de tesina) por lo que al menos los parciales no son tan pesados (repito, para los que ya son programadores).

Es muy común que en nuestras empresas se tenga más de un sistema en pleno desarrollo, e inevitablemente alguien una vez va a pedirnos que compartan datos. Y empezamos con la primera etapa de integración de aplicaciones. Parece inocente, inofensiva, un poco de trabajo para pasar datos de una tabla a otra en bases de datos diferentes. Es como primero lo vé el project leader. Se propone una solución simple, a veces con unos scripts de sql, unos triggers y listo.

Todo marcha bien después de resolver varias inconsistencias como claves que no coinciden, datos que están de un lado y no del otro, y esa clase de cosas que no previmos antes porque simplemente nos tomamos todo a la ligera.

Pasan unas semanas, o incluso unos días, ya vemos que necesitamos más que compartir datos. Por ejemplo, una base de datos requiere que cuando se ejecute cierta lógica de negocio, se impacte inmediatamente en ambos sistemas, y no se puede esperar a ningún proceso ni nada. Aquí la mayoría toma una de estas dos decisiones:

* Encapsular todo en stored procedure y que la base dueña sea X.
* Lo resuelven con triggers

Pero lo menos común es que nos pidan sólo una vez esto. Nos pedirán todo tipo de cosas. Pronto habremos inundado nuestra base de datos de un maremagnum incontrolable de instrucciones de tsql cada vez más confusas. Triggers que pisan el compartamiento de otros, resultados indeseables, clientes insatisfechos, y lo peor, horas largas después de oficina para tratar de resolver el problema. Nótese como puse que lo peor es quedarse y no que el cliente esté insatisfecho. Seamos sinceros, el cliente nunca estará satisfecho si estamos trabajando así, no hay vuelta que darle.

Entonces llega la reunión, con trompetas y banderines. Se nos acerca en su caballo real una persona de alto rango que va a participar con los líderes de ambos sistemas y sus programadores principales. Hay que resolver el problema. Nuestras aplicaciones no se integran.

Pero el primer error que todos cometen es absurdamente nefasto:

* No se miran casos de éxito.

Sin querer decir que la estrategia de implementación que utilizan es excelente, podemos igualmente ver a los productos de Office integrándose entre si e integrándose con sharepoint e internet explorer. Podemos ver aplicaciones extensibles por plugins y sistemas empresariales robustos modularizados en varios pequeños sistemas que han hecho un relativo buen trabajo (o al menos les ha funcionado, sin decir que eso es un éxito).

Y si realmente queremos integración podemos ver a Google con todas sus aplicaciones cada vez mas complejas, podemos ver como Facebook y Twitter, entre otros, permiten a cualquiera integrarse con ellos.

Tenemos de donde sacar ideas. Pero no, lo primero que hacemos es pensar que nuestro problema es único y que debemos resolverlo con nuestra inteligencia. Porque nosotros somos los cerebros del presente y no hay nadie más capacitado para planear el siguiente paso.

Y lamentablemente en la Argentina, así como en muchísimos países donde el IT ha tenido un gran auge, el personal está poco calificado y terminamos encontrándonos con ideas bizarras, no probadas y que no están lo suficientemente pensadas. Pronto entramos en el ciclo vicioso que yo llamo Anti patrón de desintegración de aplicaciones. Ok, acabo de inventar ese nombre, pero nos sirve.

Entonces en vez de iniciar con la integración de nuestros sistemas, los estamos desintegrando. Pronto habremos aumentado la complejidad en el mantenimiento, y con ello, los costos y tiempos. ¿Acaso es el precio a pagar para que nuestras aplicaciones trabajan juntas? No, sería un concepto erróneo pensar que la integración no es una inversión para obtener una ganancia futura, tanto en tiempo como dinero.

¿Cómo lograr la integración entonces?

Cada problema responde a uno o varios patrones. No son difundidos como los patrones de arquitectura, de diseño o de programación. Debemos plantearnos con qué contamos, cuales son todos los problemas, y qué se necesita. Y todo es mejor pensarlo como si todavía no tuviéramos las aplicaciones construídas. Entonces si somos capaces de ello, vendremos con una idea bastante buena.

Lo que puede pasar luego es que, por pensar que los sistemas no han sido creados, nuestra idea no puede aplicarse sin realizar una gran cantidad de breaking changes. Bueno, entonces podríamos plantearnos tres alternativas:

* Realizamos los breaking changes de manera inrcremental. A romper todo señores!
* Modificamos nuestra estrategia original para que pueda adecuarse a la situación actual. Es mejor partir de una idea buena e irla "adulterando" que partir directamente de una mala idea. De esa forma nos acercaremos más a lo que "hubiera sido" ideal.
* Si podemos, planteamos un plan de integración desacoplada, creando e implementando componentes separados de nuestras aplicaciones que se encarguen de la lógica de integración. Concepto que puede ser peligroso, pero al menos no nos inunda la base de datos de triggers.

Es un tema que dá mucho para hablar. Pero no quiero hacer un post gigantesco debido a que las posibilidades son infinitas en cuanto a integración. Y acá podría sonar a que me estoy contradiciendo ya que dije que los escenarios no son únicos. En realidad los factores lo son pero los patrones a aplicar generalmente ya existen.

Todos nos enfrentamos tarde o temprano a la integración de aplicaciones. Al menos con este post quizás alguno pueda pensarlo mejor antes de mandarse a realizarla.

Tuesday, September 13, 2011

Lógica de Negocios en Base de Datos

En algún momento nos hemos preguntado si la lógica de negocio debería ir en la base de datos o en la aplicación. A muchos nos ha pasado de ponernos en una postura y luego pensar "La verdad es que no investigué tanto en el tema como para decidirme por una postura". Y entonces cumplimos con una de las mas importantes tareas de los profesionales de IT: Investigar.

Con una rápida búsqueda en nuestro buscador de preferencia vamos a encontrar threads de diversos foros discutiendo si la base de datos debería tener lógica de negocios o no. Es realmente dificil tener una postura definitiva y única que funcione para el 100% de los escenarios. Sin embargo, siempre es bueno tener una ideología firme y saber CÓMO argumentarla.

Además, he notado que muchos (especialmente en threads nacionales, no ocurre tanto afuera) no entienden la diferencia entre estos conceptos:

  • Lógica de Acceso a Datos
  • Lógica de Negocio
  • Acceso a Datos

Nótese cómo puse que acceso a datos es diferente a la lógica de acceso a datos. Antes de comenzar a divagar sobre la lógica ubicada en las bases, vamos primero a ponernos de acuerdo en estos conceptos.

Lógica de Acceso a Datos: Son el conjunto de rutinas, instrucciones o comandos (dicho de una forma muy old-school) a partir de las cuales una aplicación accede a los datos que se encuentran resguardados en algún resguardo;  archivos de texto, bases de datos, clouds, xml, o lo que fuere. Aquí es donde cae la famosa capa "DAL", Data Access Logic, tan común en las aplicaciones empresariales de hoy en día.

Lógica de Negocio: Es el conjunto de validaciones, directivas y algoritmos (entre otras cosas) que componen al core de la aplicación y para lo cual la aplicación fué construída. Es lo que abstrae nuestra aplicación de su sistema de acceso a datos subyacente. Aquí se ubica nuestra capa de negocio, o la Business Component como Microsoft le gusta decir.

Acceso a Datos: Es el hecho de obtener datos y comunicarlos a través de algún medio para que estén disponibles a quien los solicitó. Aquí podríamos decir que nos encontramos con el servidor de base de datos y su sistema que nos abstrae del bajo nivel administrativo. Léase Oracle, SQL Server, MySql, etc.

Los datos no son más que bits almacenados. Accedemos a ellos gracias al Acceso a Datos que nos proveen los servidores y clientes de hoy en día. Accedemos a ellos con una abstracción llamada Lógica de Acceso a Datos, o DAL, la cual recibe peticiones y devuelve resultados, mensajes o simplemente ejecuta una determinada acción sobre los datos. Finalmente tenemos nuestra Lógica de Negocio que es donde más debería focalizarse un programador. Sin embargo, hoy no ocurre así debido a las pobres prácticas implementadas, muchas que tienen que ver con la arquitectura y el proceso de desarrollo. Pero todo eso lo dejaremos para otros posts.

En fin, en esto casi el 60% estará de acuerdo conmigo, el 20% no entenderá a qué me refiero exactamente, y el otro 20% estará en desacuerdo o pensará que esta forma de trabajar está llegando a su fin o que nunca funcionó. O que el hecho de que en cierta medida destruya la orientación a objetos la hace obsoleta y poco versátil, o que no aprovecha todas las herramientas que tenemos hoy en día. Nuevamente, cómo las típicas capas empresariales (donde su mayor exponente creo debe ser la Arquitectura Marco promocionada por Microsoft) destruyen o minimizan la orientación a objetos y sus consecuencias es tema de otro post.

Veamos el siguiente diagrama de lo que acabamos de decir.

Una típica arquitectura de aplicación empresarial
Esto es lo que nos enseñan en la universidad. La lógica de negocios separada de todo lo que es datos. Sin embargo, en la base de datos poseemos herramientas muy útiles e interesantes como controles de que un campo no sea vacío, o que los datos sean de cierta forma, triggers, stored procedures, etc. ¿Está mal usarlos? ¿Cuándo es bueno y cuándo no?

Por otro lado, si estamos poniendo la lógica de negocio en la base de datos nos encontramos ante la siguiente arquitectura:

La arquitectura cuando ponemos negocio en la base
Apa, es algo que a más de un fanático de poner el negocio en la base de datos no se percató. Estaríamos rompiendo nuestras sagradas enseñanzas. Ahora, eso no es algo malo en sí, puede ser muy útil. Sabemos que poner la lógica de negocio en la base de datos tiene ventajas y desventajas. Pero cuando se trata de dar mi opinión digo que hay pocas cosas tan aburridas como volverse un "Analista Programador SQL Server" (inserte link a aviso en computrabajo aquí).

Siempre todo es un "depende", pero nuestras decisiones tienen que tener una mezcla balanceada entre extensibilidad , reutilización y seguridad. Ya llegados a este momento entenderán que soy un purista de ubicar la lógica de negocios como un componente separado tanto de la aplicación como de la base de datos. Tiene sus pro y sus contra, pero a mi modo de ver, más pro que contras. Sin embargo, hay ciertos escenarios donde puede ser bueno tener la lógica en la base.

Vamos a enumerar y luego daremos ejemplos.

Ventajas:

  •  Los lenguajes de programación son mucho más versátiles y flexibles que los lenguaje de consulta (TSQL).
  • Es más fácil encontrar gente con buenas capacidades para .NET/JAVA/ETC que para SQL/ORACLE/DB2/MYSQL.
  • Para nosotros, como profesionales e individuos, programar nos brinda un mejor futuro profesional que simplemente pasárnosla revisando datos, armando scripts y realizar la penosa tarea de debuguear 8 stored procedures gigantes que se llaman entre sí, algunos recursivamente.
  • Con buenas prácticas, el copy paste anti pattern tiende a nulo.
  • Un lenguaje de programación nos pemite trabajar con cualquier sistema de base de datos subyacente. Nos dá mas libertad en este sentido.
  • Algoritmos matemáticos son más fácilmente aplicables en un lenguaje de programación que en un lenguaje de consultas.
  • Las clases, métodos, propiedades, eventos, y demases son una forma mucho mas organizada de tener la lógica de negocios que con stored procedures, donde como mucho podemos organizar por Schema y Nombre.
  • Manejar una o cien base de datos, dentro de una arquitectura correctamente pensada, es indiferente para nosotros.
  • Cuando la aplicación es una y las bases de datos son miles, la lógica de negocio en BD es muy cara y nada práctica.
  • Permite utilizar todo el poder de la orientación a objetos.
  • Provee una forma mucho más eficiente y simple de Reflexión (Disculpen que no conozca los equivalentes en otros lenguajes de programación, que los tienen obvio).
  • La escalabilidad en algoritmos y componentes es algo propio de las aplicaciones bien armadas. Las bases de datos tienen escalabilidad de OTRAS COSAS.
  • Fácil reutilización y muchos patrones de diseño de cuales elegir.
  • Más fácil conseguir componentes hechos, ayuda, soporte, e ideas que si tuvieramos que buscar lo mismo en base de datos.
  •  No mezclamos las aguas. Poniendo la lógica de negocio en la BD nunca puede hacerse en un 100%, siempre tendremos que tener algo en la aplicación.

Desventajas:

  • La reutilización debe hacerse a mano. Es decir, si tenemos 20 aplicaciones contra la misma base de datos, vamos a tener que disponer del componente de lógica de negocio en las 20.
  • Para implementar cambios debemos re-implementar.

Algunos dirán que la base de datos es más performante, pero lo cierto es que estamos poniendo toda la carga de procesamiento en el servidor y no lo estamos distribuyendo. Las bases de datos distribuídas son un recurso MUY poderoso, pero no fueron hechas simplemente para repartir carga, se usan con muchas mas aplicaciones. Tener que hacer bases de datos distribuidas para cualquier cosa no está bueno.

Sinceramente no se me ocurren muchas más, ya que tengo la mente un poco ya seteada para pensar que todo debería ir en la aplicación. Asi que mientras se me ocurren otras, vamos a empezar a analizar los escenarios.

Imaginemos que tenemos la siguiente tabla donde guardamos algo llamado Categoria:

IdCategoria NUMERIC(18, 0) IDENTITY(1, 1) NOT NULL PRIMARY KEY,
Nombre NVARCHAR(300) NOT NULL,
IdUsuarioAlta NUMERIC(18, 0) NOT NULL,
IdUsuarioModificacion NUMERIC(18, 0) NULL,
FechaAlta SMALLDATETIME NOT NULL,
FechaModificacion SMALLDATETIME NULL,
Timestamp TIMESTAMP NULL

Primer escenario que se me ocurre. El nombre es NOT NULL, es decir, obligatorio. Bueno, en la aplicación deberíamos validar que el dato Nombre que nos llega no sea vacío ni nulo. De repente ya la validación por base de datos no es suficiente: Un simple valor vacío no nulo sería incorrecto y sin embargo está permitido. Podríamos tener un Stored Procedure para cada operación (INSERT, UPDATE, DELETE) y tener aparte un stored procedure que valide los datos que nos vienen, como el Nombre. Bien, logramos solucionarlo, a un alto costo, y dificilmente reutilizable entre varias tablas.

Si fuese por la aplicación, podríamos utilizar componentes de validación que nos ayuden con la capa de presentación, y si aún así el campo llega vacío a nuestra lógica de negocio, lo validamos allí. Y si el día de mañana hacemos algo dinámico (porque no sé, quizás nuestro producto es un empaquetado que usan muchos clientes) entonces podríamos tener aparte toda la configuración para cada Entidad (generalmente 1 a 1 con las tablas). Y allí diríamos si Nombre es Obligatorio o no. Ya de repente no tenemos que programar, simplemente configurar (ojo, si nuestra interfaz para configurar es mala, tardaremos mucho, aunque no perdamos la escalabilidad).

Ahora, tenemos el Id de Usuario Alta que está relacionado a la tabla USUARIO. Bien, una FK nos viene PERFECTO. Es un excelente recurso de normalización que no deberíamos nunca dejar de usar: SIN EXCEPCIÓN! Desde la lógica de negocios no veo tan necesario que validemos que el usuario exista como tal en la base de datos. Sin embargo, en un escenario donde nuestras aplicaciones cliente son 20 y no solo una, podríamos querer centralizar toda la lógica de negocio (los WebServices son útiles para ello por ejemplo) y ahí podríamos ver la necesidad de validar que el dato exista antes de mandarlo, ya que nos serviría para mejorar nuestro mensaje al usuario o simplemente la confiabilidad de que los datos serán consistentes incluso si la base de datos no tiene el FK. Esto siempre es "DEPENDE DEPENDE". Pero suponiendo que debamos hacerlo, vamos a tener que validar contra la BD, realizando un acceso por cada validación. Algo incómodo.

Mi consejo, que la base de datos se encargue de la consistencia y referencia integral de los datos. NOSOTROS nos encargaremos de la validación y estado de los mismos. Se tratan de cosas MUY diferentes señores.

Ahora, pensemos que tenemos una aplicación web con webservices distribuidos. Los clientes no son de intranet sino que son clientes de la empresa que adquieren información a través de nuestro sitio. Nosotros debajo poseemos 3 o 4 bases de datos relacionales y unos 20 cubos con información masiva. ¿Dónde ponemos la lógica de negocios? Sería impráctico repartirla entre cubos y bases de datos relacionales. Aquí es un claro ejemplo para poner la lógica en la aplicación (probablemente en los web services). Recordemos que tenemos muchas arquitecturas cliente-servidor. No se queden con una sola. Mi consejo es una recomendación.

Ahora imaginemos que tenemos una base de datos relacional gigante que engloba contabilidad, administración, despacho de mercadería, depósito y almacenaje, recursos humanos (alguien quiere modificar el campo sueldo de su legajo :P?), y demases cosas que puede tener una empresa. Por otro lado, tenemos 1 aplicación para cada dominio. Evidentemente acá estamos en una encrucijada. Más de uno diría "Ves, acá te conviene poner todo en la base de datos porque es una sola, mientras que el resto son varias aplicaciones". Incorrecto, en este ejemplo las aplicaciones forman parte de lo que llamamos Solución. Cada aplicación aplica una lógica de negocios diferente, y se integra (debería) con el resto, ya sea por servicios o lo que fuere. Entonces, administración carga e imputa facturas, y le avisa a contabilidad para que las registre (es más complejo que eso, pero es un ejemplo). Los dos sistemas interactúan. La solución es la misma. Tengamos 7 exes o 1 solo es una decisión de diseño que no modifica el problema real. Tenemos 1 CONTEXTO (empresa), un grupo de PROBLEMAS y un RESGUARDO. Vemos que aquí se trata de un 1 a 1. Por ende también recomiendo poner la lógica de negocios en las aplicaciones.

Ahora, lo que vemos que necesitamos para dar más crédito a la lógica de negocio en las bases de datos es LÓGICA DE NEGOCIO REPETIDA. Es decir, necesitamos crear la necesidad de reutilizar la lógica de negocio en más de una aplicación. Un ejemplo fácil sería una web de red social. La podemos acceder desde una PC de escritorio, por WAP, por Iphone/BlackBerry/Celulares avanzados, llamando a Tinelli por teléfono y lo vemos holográficamente en el espejo de nuestro baño cuando vamos a hacer nuestras necesidades. Lamentablemente para cada ÁMBITO debimos desarrollar una interfaz de PRESENTACIÓN diferente. La reutilización de todo lo que está debajo de la presentación debería ser posible; es decir, tener un assembly (o varios) que todos referencien. Sin embargo, me he topado que (en .NET) no puedo usar assemblies hechos para PC en una apicación de Windows CE. Los namespaces, clases e interfaces son iguales, pero hay 2 problemas:

* Hay funcionalidad que no está (interfaces iguales pero incompletas)
* Referencias a assemblies no aptos para CE

Entonces sí, terminamos copy pasteando todo porque casi no hay que hacer cambio salvo que usemos cosas que no estén disponibles en CE, por ejemplo encriptación SHA256. Si encriptamos las contraseñas de usuarios con SHA256 para guardarlas en base de datos vamos a estar un buen rato a los gritos hasta encontrar un componente por internet o hasta que desarrollemos y probemos uno propio. Ahora, imaginemos que tuvimos que copy pastear todo entre 5 aplicaciones. Es impráctico, no estamos REUTILIZANDO. Podría servirnos poner todo en la base de datos.. Sí. Pero les doy una mejor alternativa: WebServices. Que cada aplicación tenga su capa de presentación y una capa de agentes de servicio y listo, que todo vaya a WebServices, que pueden estar distribuidos.

Para los que no sepan, la capa de agentes de servicio es una capa que nos maneja las comunicaciones entre nuestras peticiones y los servicios que están detrás, para que nuestro código no tenga que tener lógica de eso.

¡Casi íbamos a poder decir que la lógica de negocios estaba bien en la base de datos! Y es que cada mundo tiene sus desventajas, y esperé hasta aquí para mencionar esta. La reutilización de lógica de negocio entre diferentes plataformas no es tan simple. Pero estoy convencido que la base de datos no es lugar para el negocio.

Finalmente, vamos a abordar el motivo número 1 por el cual ciertos programadores ponen todo en la base de datos: CORRO UN SCRIPT Y YA ESTÁ.

Ese es el gran problema. Estamos pensando que está perfecto hacerlo así para ahorrar tiempo y dinero en implementación. Lo cierto es que esto es una incorrepta percepción de lo que se está haciendo: No hiciste una gran decisión de diseño, estás aprovechando la capacidad de SQL Server para implementación rápida de elementos.

Vamos a explicarnos. Yo en una aplicación instalo varios componentes (Configs, Dlls, Exes, etc). En una base de datos yo tengo un nivel mucho más granular: Tablas, Vistas, Stored Procedures, Triggers, Datos. Cada uno es accesible y modificable por script. Si pudiéramos simplemente reemplazar una clase, o un grupo de clases, de repente implementar sería mucho más rápido. Imaginen correr un script que sea ALTER CLASS y abajo todo el código C#. Obviamente es un tema mucho más complejo. La naturaleza y las HERRAMIENTAS de las bases de datos nos permiten implementar objetos de base de datos casi instantáneamente. El día que tengamos algo igual para componentes de aplicación (lo va a haber, y se puede hacer hoy en día, pero es un desarrollo avanzado) entonces vamos a ver que era lo mismo.

Con una MALA decisión, ganamos TIEMPO. Ahora, esto es porque tuvimos una visión mediocre, o al menos poco informada. Si nosotros planeamos correctamente nuestra aplicación no necesitaremos vivir codeando en base de datos. Veamos las aplicaciones más complejas y completas con actualizaciones automáticas que se descargan desde internet. La mayoría de estas actualizaciones realizan cambios en el filegroup, no en la base de datos (salvo que justamente cambie el modelo relacional de entidades). Además, podría ser muy mala idea que el cliente tenga acceso a nuestro código fuente de negocios. Es decir, ellos podrán acceder a su propia base de datos por lo que lo que para vos es lógica de negocios es también tu código fuente (probablemente no controlado por un sistema de versionamiento).

Seamos honestos, nos persiguen y corren con el tiempo para cerrar todo rápido y nunca nos permiten tener al menos 1 hora al día para desarrollar las ideas que tenemos todos los programadores día a día. Yo trato siempre de hacerme tiempo. Hacer un patcher, un framework, controles personalizados de interfaz de usuario, librerías de diversas cosas, etc. Si pudiéramos dedicar un poco de tiempo todos los días a incrementar la calidad de nuestros desarrollos, creando nuevas herramientas para escalar aún más en el futuro, entonces ya no estaríamos tan tentados a trabajar por base de datos.

Y este tipo de calidad es un doble filo. Por un lado incrementa los costos porque estamos usando tiempo para desarrollar las herramientas. Sin embargo, a mediano y largo plazo, los costos disminuyen al aplicar dicha herramienta. Claro, estamos hablando de que hicimos algo que realmente funciona y sirve. Es un gran problema si desarrollamos un framework y al año nos damos cuenta que no sirve, y ya es tarde porque migramos nuestras apicaciones al mismo. Habremos perdido tiempo desarrollándo y lo que es peor, la CONFIANZA en nuestro trabajo y en nuestras ideas.

Y otra cosa, recordemos que el control de fuentes está hecho para proyectos de aplicaciones. El control de fuente para base de datos ha sido siempre un lugar complicado, y ademáse es mucho menos explorado y estudiado. En control de fuente de aplicación nadie dice "no es bueno". En cambio, en base de datos siguen habiendo muchas controversias y opiniones encontradas.

Mi consejo: Las aplicaciones que hoy ya están por base de datos, continuar manteniéndolas así. Salvo que sean Core o algo que se sabe que se va a tener que estar desarrollando para siempre. En ese caso, informarse sobre procesos de refactoración para ir mutando la aplicación hacia otra arquitectura de manera paulatina. Ahora si se trata de una nueva aplicación, dejemos los lenguajes de consultas para los datos, y los lenguajes de programación para todo lo demás.

Y finalmente, si aún no logré convencerlos, recomiendo leer algunos libros de arquitecturas para aplicaciones empresariales de diverso tipo. Lean casos de éxito y pregunten a otros qué tan bueno les parece el IDE de la base de datos como plataforma de desarrollo.

PD: Este post lo dedico a mi amigo Fabián y a otros defensores del Stored Procedure Business.

No se enojen si no coincidimos :).