Componentes poco acoplados en la era de la integración de aplicaciones

Publicado por Norberto Herz el
Introducción

Existen conceptos tan importantes en el mundo del desarrollo de aplicaciones, que no solo no pasan de moda, sino que generan una gran cantidad de problemáticas (y sus consecuentes resoluciones) posibilitando la creación de nuevos negocios y productos.


Bajo acomplamiento

El concepto de "bajo acoplamiento" entre dos componentes podría describirse como una situación en donde un coponente A interactúa con un componente B, y ambos conocen lo mínimo indispensable del otro. Es una característica deseable principalmente (pero no exclusivamente) al momento de comenzar a trabajar con nuevos requerimientos (o cambios en los existentes) en una aplicación.
Como consecuencia de dos componentes con bajo acoplamiento, al modificar la implementación de uno, el impacto en el otro debería ser menor. Generalizando, si un componente dentro de una solución, se encuentra poco acoplado con todos los componentes que interactúa, al modificarlo, la aplicación sufriría un bajo impacto.

Nota: Existen técnicas para diseñar componentes poco acoplados. Por ejemplo, en Programación orientada a objetos, se suele utilizar el concepto de encapsulamiento para referirse a una técnica de ocultamiento de información. Gracias a que la implementación de un objeto está oculta, otras clases no pueden conocerla, favoreciendo (pero no necesariamente logrando) bajo acoplamiento. Es importante conocer, pero no confundir estos conceptos.


Una forma forma popular de medir el acoplamiento entre dos componentes es analizar qué ocurre cuando:
- Se agregan parámetros en la firma de un mensaje.
- Se cambia el orden de los parámetros.
- Se cambia el nombre de los parámetros.
- Se cambia la estructura de datos de los parámetros.
- Se omite algún parámetro.

El estudio de las métricas de acoplamiento (así como las de cohesión, complejidad ciclomática, etc) ameritaría un artículo separado. Si en algún momento lo escribo, prometo incluir el link aquí. Mientras tanto, recomiendo la lectura independiente de estos conceptos.


Entre un buen diseño y la sobreingeniería

Durante las épocas donde solía desarrollar frecuentemente, he realizado tareas para garantizar un bajo nivel de acoplamiento. Esto me ha costado discusiones con líderes de proyectos, managers, y distintos involucrados, en donde lo que se intentaba analizar era el "esfuerzo" necesario para realizar dichas tareas en oposición al beneficio obtenido. Un ejemplo clásico es el de crear una capa de abstracción respecto de la base de datos. La primer pregunta que suele surgir (o solía en esa época): "¿Cuántas veces te enfrentaste ante el escenario de que el cliente decida cambiar la base de datos?". Quizás no es la pregunta más feliz para realizar, pero siendo justo, tiene sentido. Una compañía invierte una buena suma en las licencias de un motor de bases de datos: Es dificil que decidan migrar de fabricante. No obstante, mi respuesta para este ejemplo, siempre era la misma: "El costo de introducir una capa de abstracción es muy bajo, y las ventajas no se limitan a disminuir el acoplamiento".
Pero fuera de este ejemplo, nunca debemos dejar de lado este análisis. De otra forma, podríamos pasar rápidamente de un buen diseño a una sobreingeniería.


La era de la integración

Si analizamos hacia donde se dirigió el desarrollo de aplicaciones en los "últimos" tiempos (sobretodo si ponemos el foco en las arquitecturas web), podremos notar que es cada vez más frecuente el consumo de servicios de otras aplicaciones de las que solo conocemos sus APIs (Application Programming Interface).
Los escenarios son variados, pero en su mayoría, no se trata de un esfuerzo conjunto por crear aplicaciones que "se conozcan". Por lo general, alguna aplicación se hace popular, y otras aplicaciones intentan interactuar con ellas "consumiendo sus servicios". Supongamos que quisiéramos crear una aplicación que se conecte a facebook y actualice el estado de un usuario. Facebook publica sus APIs brindando esta posibilidad a toda aplicación a la cual se le haya garantizado el permiso necesario. Luego, Facebook evoluciona, y si bien informará cambios en sus APIs, no realizará una encuesta para preguntar a las aplicaciones consumidoras "qué opinan al respecto".
Sin duda, si la lógica de nuestra aplicación que se encarga de comunicarse con Facebook, no se encuentra debidamente diseñada, apuntando al bajo acoplamiento, cualquier cambio que la gente de Palo Alto realice, requerirá un gran esfuerzo por nuestra parte. Utilicé Facebook como ejemplo, ya que es una de las aplicaciones que más rápido cambian. Supongo que desde que comencé a escribir esta oración, hasta este punto, ya habrán cambiado algo.
Aquí resultaría un sinsentido analizar si "nos conviene" invertir tiempo en desacoplar nuestra lógica de la de Facebook. De hecho, creo que es más trabajoso comenzar a pensar "cómo sería la versión NO desacoplada de nuestra aplicación".
El siguiente ejemplo, muestra laevolución desde una aplicación fuertemente acoplada hacia una que componentiza los posibles cambios, e identifica su propio funcionamiento (y motivo de ser).

Diagrama de alto nivel


Supongamos que queremos desarrollar una aplicación que, además de ejecutar su propia lógica, sea capaz de comunicarse con Facebook, Twitter y LinkedIn para publicar algun resultado en dichas redes sociales.

Sin más información, y sin considerar ningún principio de diseño (en este caso acoplamiento), una primera versión de nuestra aplicación podría verse de la siguiente manera:
A notar: La aplicación se encuentra 100% orientada a la integración con dichas redes sociales. La lógica de la aplicación se ve distribuida en componentes como "Lógica Facebook", "Lógica Twitter" y "Lógica LinkedIn".
Si bien es un escenario exagerado (quizás nadie desarrollaría una aplicación de esta forma), a este diseño se podría llegar de diversas maneras. Un ejemplo que me viene a la mente es: Se requiere una aplicación que realice su lógica y publique en Facebook los resultados. Un tiempo más tarde, Twitter y LinkedIn se hacen populares, y se solicita la publicación en estos sitios. Alguien podría duplicar (o en este caso triplicar) la lógica propia de la aplicación, para poder cumplir sus objetivos.
En su lugar, una persona con más experiencia podría permitirse pensar, que es conveniente identificar cuál es la lógica que corresponde a nuestra aplicación y diferenciarla de aquella que se incluye para lograr la comunicación con las tres redes sociales, con el objetivo de separar los componentes. Esta segunda aproximación, daría un resultado como el siguiente:
A notar: Nuestra aplicación debe tener una lógica propia e independiente de la publicación en las redes sociales (es el negocio de nuestra aplicación. Sin el, la misma no tendría propósito). Se separa la lógica común, de aquella que sirve para realizar la comunicación.
El siguiente paso, consiste tan solo en un cambio de nomenclatura:
A notar: Solo se ha cambiado el nombre "Lógica" por el de "Integración" para los tres componentes encargados de la comunicación. Puede parecer irrelevante, pero "deja picando" el siguiente paso. Si mi aplicación tiene una lógica "A", que podría existir sin la necesidad de las redes sociales u otro tipo de aplicación, correspondería que el alcance de la misma llegue hasta su propia lógica. En otras palabras, sería correcto separar los componentes de integración y colocarlos en otra "área" fuera del alcance de "MI APP".
A notar: En los diagramas y diseños, esta separación parece simplemente un detalle teórico. Pero si se piensa desde el punto de vista de "unidades de deploy", es posible cambiar estos componentes por separado y liberar sus releases de forma independiente. Por ejemplo: Twitter puede cambiar su API, y requerir el envío de un parámetro en un nuevo formato. No sería necesario realizar una nueva versión de "MI APP" ni tampoco de los componentes de integración con Facebook y LinkedIn.

Pero quizás el detalle más importante: Los componentes de integración, pueden ser deployados en una herramienta de integración. O dicho con mayor propiedad: En lugar de escribir el código completo de integración, podríamos utilizar una herramienta (o producto) que facilite esta tarea. Esta herramienta debería brinarnos funcionalidades comunes frecuentemente utilizadas para la comunicación  de aplicaciones.

La existencia de este tipo de herramientas es posible, ya que quienes desarrollan una aplicación que publica una API para ofrecer servicio a otras, se basan en standards abiertos de comunicación (protocolos de comunicación como HTTP, JMS, etc y lenguajes de representación de datos como XML y JSON).
Un producto de integración, deberá brindar funcionalidades de transformación, autenticación y validación, pero principalmente, deberá ser "extensible", es decir, deberá permitirnos desarrollar nuestros propios componentes que utilicen estas "funcionalidades comunes" y deployarlas de manera independiente.

Esto es básicamente lo que hace un Enterprise Service Bus (ESB). Actúa como intermediario entre distintas aplicaciones para facilitar la integración de las mismas bajo el principio de bajo acoplamiento.



Conclusión

En el contexto actual, la integración de aplicaciones se ha vuelto un proceso tan frecuente, que empresas entras se dedican a esta problemática. Es un "nuevo" negocio. Se puede realizar mediante la oferta de soluciones de integración, servicios de consultoría, o incluso, combinar ambos negocios ofreciendo el producto y el soporte para la implementación.
Lo claro es que ya no puede dejarse de lado el concepto de acoplamiento, y que el mismo, está presente en los diseños de aplicaciones más recientes.