Lenguajes & Paradigmas

Desarrollo & Construcción de Software

Programación Orientada a Servicios

Paradigmas & Modelos de Abstracción

Javier Vélez Nov 2023 21 mins

Introducción

En los mismos años en los que la comunidad académica estaba atribulada preocupándose por los nuevos modelos de orientación a componentes, la industria del software ponía foco de atención en un nuevo espacio tecnológico donde abrir oportunidades de negocio. Y es que por aquella época, casi estrenado el nuevo siglo, Internet se había convertido en una realidad estable tanto a nivel profesional como familiar y el índice de penetración de las comunicaciones telemáticas era una realidad cotidiana.

Microsoft promocionaba modelos de comunicación remota RPC entre máquinas a partir de un nuevo y revolucionario protocolo operado sobre http, que daría en llamarse servicios web. Con ayuda de dialectos expresados en XML, cualquier invocación a servicios remotos podría articularse a través de procesos simétricos de marshaling y unmarshaling.

Las corporaciones rápidamente entendieron el valor de este nuevo canal para realizar operaciones comerciales y fortalecer relaciones B2B y B2C. Ahora el valor no estaría exclusivamente focalizado en la construcción y mantenimiento de los clásicos canales web dirigidos al usuario final sino que se pondría un especial interés en crear APIs de servicios que permitieran articular procesos transaccionales de manera computable y segura con terceras partes. Había nacido el paradigma de orientación a servicios.

Objetivos

La llegada de las tecnologías de servicios fue amablemente recogida por la comunidad de desarrolladores que veían grandes oportunidades potenciales en exponer toda la lógica de negocio de una organización en términos de servicios. Los servicios se habían convertido en la piedra filosofal de la construcción de productos y soluciones digitales y pareciera que era el camino único de paso en todos los procesos de diseño e ideación de arquitecturas.

Más allá de entender esta nueva tecnología como un habilitador para crear nuevos canales de comunicación entre corporaciones a manos de los desarrolladores, estos entendieron que los servicios deberían ser el habilitador general para crear cualquier activo dentro de la corporación. Los procesos internos de la compañía, el soporte digital a las actividades de negocio, y en general, todas las tareas de digitalización internas también podían ser fácilmente expresadas en términos de servicios porque al mismo coste se obtendrían todos los beneficios del nuevo paradigma de programación.

Parecía olvidarse sin embargo, que el uso de las tecnologías basadas en servicios imputaría un alto coste en términos de rendimiento ya que las comunicaciones articuladas en el espacio de la computación distribuida siempre resultarían un orden de magnitud mas lentas y costosas. Pero, ¿cuáles eran todas las promesas de este nuevo paradigma? ¿Porque esa fiebre de una construcción digital fuertemente orientada a servicios? ¿Tanta era la ganancia? Tendrían que pasar años para que la comunidad de software advirtiera que no todo fueron aciertos en este entusiasmo ciego pero desde luego sí fue un cambio generacional sin parangón en la historia del desarrollo. Además, como ocurre frecuentemente, el hype supo operar de encantador de serpientes para los entusiastas. Estas fueron algunas de las promesas más relevantes.

  • Ubicuidad. Al exponer las capacidades empresariales de la organización como una colección de servicios públicos, otras entidades podrían hacer uso de las mismas con independencia de su ubicación. La ubicuidad universal de las arquitecturas orientadas a servicios se presentaría, tal vez, como una de las novedades más atractivas del nuevo paradigma de programación ya que hasta la fecha las comunicaciones entre máquinas habían sido desarrolladas en base a protocolos cerrados que requerían acuerdos y configuraciones preestablecidas.

  • Estandarización. La exposición de las capacidades de negocio en forma de una tecnología estándar en base a servicios permitiría universalizar la forma de acceso a los mismos por parte de cualquier corporación. La lógica de negocio ahora podía ser invocada en base a protocolos estándar con agnosticismo del stack tecnológico que, en su espacio interno de desarrollo arquitectónico, decidiera usar cada corporación.

  • Interoperabilidad. El uso de un modelo de comunicación homogéneo y estándar subiría el nivel de abstracción de los lenguajes a los contratos de servicios lo que habilitaría una comunicación potencial entre compañías a la vez que respetaría el carácter políglota en los procesos de desarrollo de servicios. Este hecho fomentaría el nivel de interoperabilidad entre organizaciones ya que la comunicación se haría posible con solo conocer la familia de contratos de los servicios, cuya documentación se convertiría en esfuerzo esencial dentro del paradigma.

  • Escalabilidad. Y de manera similar, el hecho de caracterizar una organización en base a una colección ordenada de servicios permitiría a los equipos de operación jugar con estrategias de escalado elástico de manera transparente sin afectar a los procesos de comunicación. Cuando un servicio estuviera recibiendo una excesiva carga de ataque concurrente, éste podría ser clonado para articular técnicas de balanceo de carga que mantuvieran una experiencia de uso adecuada.

Principios

Como había venido ocurriendo a lo largo de toda la historia del desarrollo del software, el paradigma de orientación a servicios se miró mucho en los principios, buenas prácticas y recomendaciones de la cultura imperante hasta la fecha. De manera preponderante, primero la orientación objetos y después la orientación a componentes que estaba cuajando en el ámbito de la academia, sentarían las bases de cómo debería ser desarrollado el nuevo paradigma.

Y es que, a la postre, la orientación a servicios podría ser interpretada en último término como una extensión de los paradigmas anteriores desplegada ahora dentro del nuevo espacio de computación distribuida. Los objetos y los componentes nos hablarían de modularidad, abstracción, reusabilidad, encapsulación, extensión, adaptación y un largo etcetera de ideas sobre las que desarrollar la base de construcción de un nutrido ecosistema de servicios que encontraban su actividad compositiva en el espacio de las comunicaciones en red. Aunque como discutiremos más adelante existirían distintas corrientes dentro de este paradigma, los principios de la orientación a servicios pueden resumirse en las siguientes ideas.

  • Principio de Diseño por Contrato. Este principio de diseño establece que la definición del contrato de un servicio debe preceder siempre a su implementación. La idea es que estos contratos proporcionen una descripción clara y completa del perfil de consumición del servicio lo que permite que los servicios sean fácilmente descubiertos y utilizados correctamente por otros equipos, incluso antes de que su lógica interna sea desarrollada.

  • Principio de Abstracción. En alineamiento con el principio anterior, el principio de abstracción establece que los detalles sobre la lógica de un servicio deben quedar ocultos a los consumidores del mismo. De acuerdo a esta idea, los consumidores del servicio no necesitan entender los detalles internos de cómo funciona el servicio sino tan solo conocer cómo hacer una adecuada consumición del mismo a través de su contrato. Éste principio de diseño se encontraría claramente enraizado en las ideas de abstracción y protección de la información propias de la orientación objetos y componentes.

  • Principio de Acoplamiento Débil. El principio de acoplamiento débil hace estrés en la idea de que los servicios de una arquitectura deben mantener siempre reducido el número de dependencias para operar. Esta afirmación presenta múltiples interpretaciones igualmente válidas ya que, al hablar de bajo acoplamiento hacemos simultáneamente referencia a mantener bajo el numero de dependencias con otros servicios de la arquitectura, pero también con elementos arquitectónicos de la tecnología de soporte subyacente.

  • Principio de Reutilización. El principio de reutilización establece que el diseño de servicios debe garantizar siempre un alto grado de reutilización de manera que cada servicio pueda ser consumido en diferentes contextos arquitectónicos de uso. En continuidad con el principio anterior cabe pensar que una alta reusabilidad se alcanza, en parte, manteniendo un acoplamiento bajo con el resto de servicios de la vecindad. De esta manera, los servicios deben ser siempre diseñados con agnosticismo de las necesidades particulares que presenten los servicios clientes en cada momento.

  • Principio de Composición. El principio de composición establece que, en el marco de la orientación a servicios, todo servicio se diseña para favorecer su uso compositivo con otros servicios dentro de la arquitectura. Según esta idea, las arquitecturas de orientación a servicio se construyen de acuerdo a un modelo de capas de manera que los servicios de cada capa se apoyan siempre en las capacidades ofrecidas por los servicios de la capa anterior.

  • Principio de Autonomía. El principio de autonomía establece que los servicios deben ser siempre diseñados para mantener un alto control sobre los recursos tecnológicos que los soportan. Esto significará que el servicio tendrá la capacidad de funcionar de manera independiente y gestionar su propia lógica y estado interno. Asi descrito, el principio de autonomía da lugar a arquitecturas de servicios más robustas y menos propensas a fallos ante cambios ambientales. Además, el carácter autónomo de los servicios facilita la escalabilidad y la distribución de los mismos en diferentes entornos y plataformas.

  • Principio de Diferimiento de Estado. Este principio se refiere a la idea de que los servicios deben minimizar el consumo de recursos difiriendo el manejo de su información de estado cuando sea necesario. Esta idea apunta a aumentar la escalabilidad y poder manejar más solicitudes de forma concurrente. En alineamiento con el principio anterior, el diferimiento de estado también apunta a que los servicios sean diseñados de tal manera que puedan manejar su estado interno para presentar un alto rendimiento y una alta disponibilidad.

  • Principio de Descubrimiento. El principio de descubrimiento establece que en una arquitectura de servicios cada servicio debe acompañarse de metadatos que faciliten su descubrimiento e interpretación. Estos metadatos permitirán a los consumidores descubrir los servicios disponibles en el ecosistema e conocer el contrato formal que permite su consumición en tiempo de ejecución. Este esfuerzo se encuentra estrechamente relacionado con la idea de reutilización ya que al facilitar el descubrimiento se evita la reconstrucción de servicios que solapen funcionalmente con otros previamente construidos.

Si bien la colección de principios de diseño que acabamos de describir resume de manera bastante nítida la colección de directrices que ponen marco a este paradigma de programación, lo cierto es que la relevancia de estos elementos se antoja variante en función de las corrientes y modelos arquitectónicos que describiremos en una sección posterior.

Mecanismos

Como ocurriría con el caso de los componentes, el paradigma de orientación o servicios se presentaría como una nueva aproximación de desarrollo y diseño arquitectónico de software sin demasiados mimbres de sustrato tecnológico con base en lenguajes y compiladores de soporte. Las nuevas ideas del paradigma deberían apoyarse más en grandes principios, buenas prácticas, modelos arquitectónicos y patrones de diseño que en nuevos constructos sintácticos y formalizaciones.

Sin embargo, como ya comentamos anteriormente, esta nueva aproximación de desarrollo, encontraría nuevamente en el espacio de los mecanismos su gran aliado en la orientación objetos, la orientación a componentes y el nuevo espacio de la computación distribuida. Sin el ánimo de ser rigurosos ni exhaustivos podemos resumir a continuación aquellas palancas más relevantes que sirvieron de soporte a este paradigma.

  • Orientación a Objetos. Casi por motivo cultural la mayoría de los desarrolladores enfocaban los procesos de construcción y diseño de servicios como un ejercicio de modelado orientado a objetos. A través de una colaboración de entidades se establecía un espacio de responsabilidad y capacidades funcionales que podían ahora ser expuestos en el ámbito de la computación distribuida por medio de un ejercicio de encapsulación que materializaría la lógica en forma de servicios. Dentro de este espacio, los principales caballos de batalla serían la abstracción, la delegación, la herencia, el polimorfismo, la ligadura dinámica y la genericidad.

  • Orientación a Componentes. Desde la orientación a componentes, el desarrollo de servicios se miraba en las ideas de inversión de control y gestión explícita de dependencias y encontraba soporte en los marcos de trabajo tecnológico que se venían proporcionando en este contexto. A la postre, la construcción de un servicio, debía ser interpretada como un esfuerzo de diseño de un componente que sería expuesto, encapsulado y publicado en forma de un servicio.

  • Computación distribuida. Finalmente, dentro de este espacio, los conceptos clásicos de los protocolos de red más convencionales y otros muchos que habrían surgido al calor de nuevas especificaciones RPC serían la base de sustrato para hacer una publicación sencilla en forma de servicios. Sobre la torre de Babel de los lenguajes en uso pronto se desarrollarían marcos de trabajo basados en anotaciones declarativas para automatizar los procesos de despliegue de lógica de negocio en forma de servicios accesibles desde Internet.

Arquitecturas

La creación del paradigma de orientación a servicios no fue para nada algo exento de turbulencias. Desde aquellos primeros días en los que un tímido servicio fuera publicado en Internet para ser consumido por una máquina remota al otro lado del mundo, diversas aproximaciones arquitectónicas fueron defendidas como base de mejora sobre ideas previamente establecidas.

Aunque hoy en día parece haberse alcanzado cierta calma, aún nos llegan ecos de la gran controversia que atravesó la comunidad acerca de cuáles de los modelos arquitectónicos en boga resultaba más prometedores. En lugar de afirmar que el martillo es para los clavos y que para las tuercas la llave inglesa los desarrolladores preferimos embarcarnos en batallas bizantinas que como es común quedaron fuertemente empañadas por intereses de mercado e ignorantes con altavoz. Desde una perspective pretendidamente aséptica trataremos de describir los 4 modelos arquitectónicos dentro de este paradigma.

  • Arquitecturas de Servicios. Las arquitecturas de servicios exponen un modelo de información atacable de manera transaccional en forma de una colección de recursos con endpoints de acceso a los mismos. Este tipo de soluciones pretende exponer las capacidades de una organización en forma de servicios para que otras entidades los consuman de manera automática y programática. Como explicábamos en la introducción, este modelo de arquitectura fue la aproximación clásica y convencional para definir nuevos canales de relación B2B y B2C. Para llevar esto a cabo, es conveniente hacer uso de un API manager que gestiona la definición del producto digital asi definido controlando todos los aspectos relacionados, desde la seguridad, autenticación y control de acceso hasta la monetización, billing, y restricción de uso pasando por aspectos más técnicos de validación, transformación, enrutamiento e incluso orquestación compositiva.

  • Arquitecturas Orientadas a Servicios. Las arquitecturas orientadas a servicios persiguen una transformación global del ecosistema empresarial para modelar cada capacidad del negocio en forma de un servicio. De esta manera, se consigue reducir la impedancia lingüística que de natural se dan entre los equipos de negocio y tecnología. En las arquitecturas orientadas a servicios, toda actividad de construcción se establece a través de un modelo de capas con espacios de responsabilidad bien definido. La capacitación digital de la organización crece en anchura creando nuevos servicios por capa y en profundidad, apoyando la implementación de cada servicio en las capacidades expuestas por los servicios de la capa anterior de acuerdo a un modelo de construcción compositiva ascendente. Dada la volumetría y complejidad de este tipo de contextos, resulta conveniente hacer uso de catálogos de servicios para fomentar los principios de descubrimiento y reusabilidad.

  • Arquitecturas de Microservicios. En las arquitecturas de microservicios el propósito es conseguir un escalado asimétrico de las soluciones asi construidas. En contraposición de lo que ocurre con las aproximaciones monolíticas que requieren estrategias de escalado horizontal o vertical, este tipo de arquitecturas descomponen el espacio de solución en forma de microservicios que mantienen bajo acoplamiento entre ellos mediante el uso de una comunicación desacoplada basada en eventos. Cuando un servicio presenta un alto grado de ataque concurrente, éste puede redimensionar su base de recursos sin afectar al comportamiento del resto del sistema. Las arquitecturas de microservicios son un claro ejemplo de hype malentendido dentro de la comunidad, dado que, rara vez, la volumetría de ataque a los sistemas requiere de un diseño arquitectónico tan complejo de desarrollar y mantener cómo demandan este tipo de soluciones.

  • Arquitecturas Serverless. Finalmente, las arquitecturas serverless, son un modelo de arquitectura promovido por el uso de la computación en la nube. En lugar de crear modelos de servicios corporativos a través de esfuerzos de desarrollo, se invita a los ingenieros de cloud a crear soluciones sobre las consolas de administración de la nube para consumir servicios directamente expuestos por ésta. Para llevar a cabo los procesos de coordinación compositiva, se hace uso de soluciones coreográficas basadas en eventos y funciones reactivas. Cuando se invoca a determinado servicio, éste propaga una notificación ambiental en forma de evento que puede ser recogido por funciones manejadores para promover reacciones de negocio. Este tipo de aproximaciones conduce a soluciones de alto riesgo arquitectónico porque presenta un alto grado de acoplamiento vendor locking y es, hasta cierto punto una involución en muchos de los principios del paradigma. Por ejemplo, la concentración de lógica empresarial en forma de una amalgama de manejadores reactivos no solamente resulta complicado de mantener e interpretar sino que es una solución con baja escalabilidad volumétrica.

Patrones

Dentro del paradigma de orientación a servicios, existen contribuciones relevantes en forma de lenguajes y catálogos de patrones de diseño que ofrecen soluciones correctas y bien formadas para problemas de aparición recurrente para cada uno de los modelos arquitectónicos que acabamos de describir. Lamentablemente, a lo largo de esta sección es imposible hacer una revisión exhaustiva de los mismos. Sin embargo, sí podemos citar algunos referentes dentro de la literatura que merece la pena explorar si se desea adquirir un mayor conocimiento de profundidad en base a patrones.

Dentro del espacio de las arquitecturas orientadas a servicios Thomas Erl es un autor prolífico que tiene mucha literatura en relación a este tipo de modelos arquitectónicos. En particular destaca el libro sobre patrones de diseños que expone las soluciones canónicas que mejor funcionan en el ámbito de ese tipo de soluciones. Para las arquitecturas de microservicios es un referente importante el libro de patrones de diseño de Richardson. A largo de diferentes capas, el autor nos habla de diversas familias de patrones para problemas de despliegue, descubrimiento, comunicación, observabilidad, testing, transaccionalidad, seguridad y un largo etc. Finalmente, para el perímetro de la computación en la nube, resultan de interés recursos en la web que describen diferentes tipos de patrones arquitectónicos. Las páginas de AWS y Azure disponen de una importante base de documentación en este sentido.

Técnicas

Hablar de técnicas de diseño y desarrollo en el marco del paradigma de orientación servicios también exige una clara diferenciación entre los diferentes modelos arquitectónicos en uso. Las técnicas de diseño y desarrollo de soluciones aplicadas para el caso de modelos de APIs de servicio, las arquitecturas orientadas a servicios, las arquitecturas de microservicios o las arquitecturas de servicios en la nube, pueden ser muy diferentes.

En particular, para el caso de las arquitecturas basadas en APIs de servicios, es habitual moverse entre distintos niveles de especificación de recursos. De manera convencional, el diseño consiste en definir recursos fijos por cada entidad del problema con un contrato homogéneo vinculado a los verbos de consumición del protocolo HTTP y asociar dichos recursos a endpoints paramétricos de acceso público. Sin embargo, en otras ocasiones, el diseño de recursos sigue las directrices de una construcción hypermedia. Este tipo de APIs tiene una orientación diferente en la que cada respuesta de un servicio ofrece, adicionalmente, metadatos de siguientes pasos para que el cliente pueda realizar una consumición exploratoria. De esta manera, las arquitecturas intermedias son más tolerantes al cambio evolutivo ya que los clientes basan su interacción en procesos de descubrimiento iterativo en tiempo de ejecución. También son técnicas habituales dentro de este tipo de contextos, el uso de estándares. Por ejemplo, en los formatos de respuesta es común hacer uso de JSON-LD o Open Data o formatos para soporte hypermedia. O en las actividades de documentación formal y computable suele hacerse uso del estándar Open API.

Para el caso de las arquitecturas orientadas a servicios, la práctica más habitual consiste en partir de la definición de un modelo canónico global que represente el espacio de entidades de toda la compañía. A partir de ahí, se crean esquemas de datos para habilitar la comunicación entre servicios. Es habitual hacer uso de un middleware de mensajería que da soporte a toda comunicación aportando capacidades de validación, transformación, filtro y enrutamiento entre los servicios implicados en una colaboración. El uso de este tipo de artefactos centrales puede parecer altamente beneficioso al principio por su alto grado de configuración declarativa. Sin embargo, es frecuente que se convierta rápidamente en centro de polución donde se entrelaza toda la lógica de negocio compositiva lo que complica el mantenimiento y la evolutividad de la arquitectura.

En el caso de las arquitecturas de microservicios, el diseño dirigido por dominio es una práctica habitual para articular este tipo de soluciones. Durante el análisis del problema, se identifican contextos acotados que pueden ser materializados en forma de microservicios potencialmente autónomos e independientes para poder aplicar estrategias de escalado asimétrico. Asimismo, y debido al importante uso de eventos que se hace dentro d este tipo de arquitecturas para dar soporte a una comunicación desacoplada y asíncrona entre microservicios, es frecuente aplicar en las fases de ideación y diseño técnicas de evento storming. Básicamente consiste en sesiones de trabajo que, mediante dinámicas agile, persiguen descubrir la colección de eventos que mueve la ejecución del las arquitectura como un todo sistémico cohesionado.

Finalmente, en el caso de las arquitecturas de nube las técnicas giran en torno a encontrar soluciones para operar con el conjunto de notificaciones ambientales que expresan los servicios durante su ejecución en forma de eventos y que deben ser recogidos por manejadores reactivos. Quizá la técnica más habitual en este sentido pretende dar respuesta al punto de dolor más importante dentro de este tipo de soluciones. Y es que en la definición de reglas de respuesta reactiva es adecuada cuando se pretende expresar un modelo de coordinación basado en coreografía. Sin embargo, en no pocas ocasiones, resulta más conveniente definir esquemas de coordinación basados en orquestación, en los que una entidad coordina la actividad de varios servicios. El uso de sagas de correlación es la técnica más habitual para hacer frente a este problema.

Conclusiones

Durante toda esta serie de artículos hemos hecho una revisión exhaustiva de los diferentes modelos y paradigmas de programación que han surgido a lo largo de la historia. Para recorrer este camino, nos hemos servido de un marco conceptual de referencia que caracteriza los paradigmas de programación en términos de tres ejes dimensionales. Los objetivos describen los propósitos del paradigma, los principios de diseño establecen directrices de actuación general para alcanzar dichos objetivos y los mecanismos hacen referencia a la capacitación que ofrecen los lenguajes como herramientas de soporte a la construcción de soluciones centradas en el paradigma.

A partir de estos ejes surge un espacio de reflexión formado por tres planos de actividad. El corte de los objetivos con los principios define el plano de los modelos arquitectónicos donde diferentes sabores de solución pueden ser articulados respetando las directrices paradigmáticas. El corte entre los principios y los mecanismos nos habla de la colección de catálogos y lenguajes de patrones que articulan soluciones correctas y bien formadas para dar respuesta canónica a problemas de aparición recurrente dentro del paradigma. Y finalmente, El plano de técnicas describe cuáles son las pragmáticas de uso más habituales que los desarrolladores realizan sobre la base de los mecanismos del lenguaje para alcanzar nuevamente los objetivos del paradigma.

Este camino ha pretendido mantener un escrupuloso respeto a la evolución histórica del desarrollo, si bien en algunas ocasiones hemos tenido que tomarnos ciertas licencias en cuanto a las fechas para mantener el relato pedagógico y comprensible. Desde la programación estructurada germinal, hemos pasado a la programación funcional, de ahí a la programación orientada a objetos, de los objetos a la programación orientada a componentes, y finalmente, de los componentes hemos saltado a la programación orientada a servicios que es, en la actualidad, el paradigma de programación más imperante.

Quizá el lector encuentre que alguno de los acontecimientos más relevantes a lo largo de la historia del desarrollo no han sido cubiertos de manera exhaustiva en este recorrido. Por ejemplo, el paradigma de programación orientada aspectos no ha sido presentado como un verdadero paradigma de programación con cuerpo propio. Y es que, pese a lo que el hype y el mercado nos invitara en su dia a pensar en esta dirección, lo cierto es que este caso particular de aproximaciones son tan solo un modelo arquitectónico clásico dentro del stream adaptativo de la orientación a componentes. Con esto quiero decir que, cada marco organiza la realidad de una forma asible característica y esta ha sido la mia. Disculpen la tristeza si echan algo en falta.