Desarrollo de microservicios con Python - José Manuel Ortega Candel - E-Book

Desarrollo de microservicios con Python E-Book

José Manuel Ortega Candel

0,0
27,99 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.
Mehr erfahren.
Beschreibung

Domine las herramientas imprescindibles para programar de forma eficaz y desarrolle sus propias aplicaciones con Python En el mundo actual de la tecnología, las aplicaciones basadas en microservicios se han convertido en el estándar para construir aplicaciones escalables y flexibles. El lenguaje más adecuado para llevar a cabo esta tarea es, sin duda, Python. Si desea una guía completa para adentrarse en el desarrollo de microservicios utilizando Python como lenguaje de programación, ha llegado al libro indicado. Desarrollo de microservicios con Python le proporcionará las bases que cualquier desarrollador de Python debe tener para adentrarse en el desarrollo de microservicios. Además, aprenderá a controlar las principales herramientas y frameworks que se pueden utilizar hoy en día para la creación desde cero de aplicaciones que interactúen entre sí y se comuniquen a través de este nuevo paradigma de programación. Gracias a la lectura de este libro: "Conocerá los fundamentos de la arquitectura de microservicios y cómo Python le puede ayudar a desarrollar aplicaciones empleando este paradigma de desarrollo. - Aprenderá los principales frameworks de desarrollo que ofrece el ecosistema de Python a través de la creación de proyectos, donde destacan Django y Flask como principales frameworks de desarrollo. - Aprenderá las mejores prácticas para diseñar microservicios, desde la modularidad hasta la comunicación entre servicios, y obtendrá conocimientos prácticos respaldados por ejemplos concretos. Asimismo, con el objetivo de obtener el máximo provecho del contenido práctico del libro, se proporciona el acceso al repositorio de código fuente con los ejemplos desarrollados a lo largo de los diferentes capítulos. Hágase con su ejemplar y descubra las principales herramientas para desarrollar con éxito sus propias aplicaciones con Python. José Manuel Ortega Candel es ingeniero de software e investigador de seguridad. Ha impartido formación a nivel universitario y ha colaborado con la escuela oficial de ingenieros informáticos. Entre las conferencias que ha impartido a nivel nacional e internacional, destacan las relacionadas con Python, seguridad, Docker y DevOps.

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern

Seitenzahl: 268

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Desarrollo de microservicios con Python

© 2024 José Manuel Ortega Candel

Primera edición, 2024

© 2024 MARCOMBO, S. L.

www.marcombo.com

Ilustración de cubierta: Jotaká

Maquetación: Reverte-Aguilar, S.L.

Corrección: Mónica Muñoz

Directora de producción: M.a Rosa Castillo

Cualquier forma de reproducción, distribución, comunicación pública o transformación de esta obra solo puede ser realizada con la autorización de sus titulares, salvo excepción prevista por la ley. Diríjase a Cedro (Centro Español de Derechos Reprográficos, www.cedro.org) si necesita fotocopiar o escanear algún fragmento de esta obra

ISBN del libro en papel: 978-84-267-3719-9

ISBN del libro electrónico: 978-84-267-3762-5

Producción del ePub: booqlab

Dedicado a los lectores, cuya curiosidad y pasión por el conocimiento hacen que la escritura cobre vida

CONTENIDO

Introducción

CAPÍTULO 1

Patrones y arquitecturas desoftware

1.1. Introducción

1.2. Patrones de arquitectura

1.2.1. Patrón de estructuración

1.2.2. Aplicación monolítica

1.2.3. Capas jerárquicas

1.2.4. Procesamiento batch o secuencial

1.2.5. Tuberías y filtros (Pipes and Filters)

1.2.6. Microkernel

1.2.7. Arquitecturas orientadas a servicios (SOA)

1.2.8. Arquitectura REST

1.2.9. Arquitecturas dirigidas por eventos

1.2.10. Patrón productorconsumidor

1.3. Patrones sobre sistemas distribuidos

1.3.1. Bróker («agente intermediario»)

1.4. Patrones sobre sistemas interactivos

1.4.1. MVC (Modelo Vista Controlador)

1.4.2. MVT (Modelo Vista Template)

1.4.3. MVC (Modelo Vista Controlador) + Observer

1.4.4. Implementación MVC (Modelo Vista Controlador) en Python

1.5. Arquitecturas basadas en microservicios

1.6. Retos de las arquitecturas basadas en microservicios

1.7. Clean Architecture

1.7.1. Principios de diseño

1.8. Conclusiones

CAPÍTULO 2

Python WebFrameworks

2.1. Introducción

2.2. TurboGears

2.3. Pyramid

2.4. CherryPy

2.5. BottlePy

2.6. Starlette

2.7. Responder

2.8. Molten

2.9. Klein

2.10. Quart

2.11. BlackSheep

2.12. FastAPI

2.12.1. Tratamiento de rutas con FastAPI

2.12.2. Tratamiento de excepciones con FastAPI

2.12.3. Tratamiento con SQLite

2.12.4. Estructura de un proyecto

2.13. Emmet

2.14. PY4WEB

2.15. Falcon Framework

2.16. Pynecone

2.17. Ejecutar Python en el navegador

CAPÍTULO 3

DjangoFramework

3.1. Introducción

3.2. Patrón Modelo-Vista-Template en Django

3.3. Ventajas de Django

3.4. Proyectos web que usan Django

3.5. Instalación de Django con Virtualenv

3.6. Crear un proyecto Django

3.6.1. Cómo procesa una petición Django

3.7. Crear una aplicación en Django

3.7.1. Vistas en Django

3.7.2. Plantillas en Django

3.7.3. Modelos en Django

3.7.4. Panel de administración en Django

3.8. Django-environ

3.9. Django REST Framework

3.9.1. Componentes de Django REST Framework

3.9.2. Serializadores con Django REST Framework

3.9.3. Probando la API con Django REST Framework

3.9.4. Creando un serializador personalizado

3.10. Django REST Swagger

3.11. Django Ninja

3.12. Autenticación y autorización en Django

3.13. Django AdminApp

3.14. Django TodoApp

3.15. Wagtail como sistema gestor de contenidos

3.16. Fly.io para desplegar aplicaciones Django

CAPÍTULO 4

FlaskFramework

4.1. Introducción

4.2. Gestión de paquetes en Python con Pipenv y Poetry

4.3. Estructura de un proyecto en Flask

4.3.1. Añadir un template HTML

4.3.2. Métodos de enrutamiento

4.3.3. Trabajando con peticiones HTTP

4.3.4. Plantillas en Flask

4.3.5. Subir ficheros a un servidor en Flask

4.4. Extensiones de Flask

4.5. Desarrollo de API con APIFlask

4.6. Aplicaciones modulares con Flask

4.7. Flask-Injector

4.8. Flask-Socket.IO

4.9. Flask asíncrono

4.10. Flask-Login

4.11. Flask CRUD

4.12. Uso de Flask con JWT

4.12.1. PyJWT

4.13. Mejores prácticas en Flask

4.14. Flask vs. Django

CAPÍTULO 5

Ejecución de microservicios en Python

5.1. Creación de microservicios con PyMS

5.2. Web Server Gateway Interface (WSGI)

5.3. Llamadas asíncronas

5.4. Greenlet

5.5. Gevent

5.6. Twisted

5.7. Tornado

5.8. Peticiones asíncronas con AIOHTTP y asyncio

5.8.1. El módulo AIOHTTP

5.8.2. El módulo asyncio

5.8.3. Caso de uso asyncio junto con Socket.IO

5.9. Sanic

5.10. Colas de mensajes

5.11. RabbitMQ

5.11.1. Protocolo MQTT (Message Queuing Telemetry Transport)

5.11.2. Comunicación con el bróker

5.11.3. Nameko

5.11.4. Protocolo de comunicaciones con Nameko

5.11.5. Interacción con Python mediante los módulos Pika y Puka

5.11.6. Administración de RabbitMQ

5.11.7. Interacción con Python mediante AMQPStorm

5.11.8. Conclusiones RabbitMQ

5.12. Apache Kafka

5.13. Celery

5.13.1. Uso de Django con Celery

5.14. Aplicaciones distribuidas y asíncronas con PyZMQ

CAPÍTULO 6

Desarrollo de microservicios con arquitecturas Serverless

6.1. Introducción

6.2. AWS Lambda

6.2.1. Funciones Lambda con Python

6.3. Serverless en las aplicaciones Python WSGI

6.4. Frameworks Serverless

6.5. Slam

6.6. Zappa

6.7. Chalice

6.8. FaaS (Function as a Service) vs. Microservicios

Glosario

INTRODUCCIÓN

El objetivo de este libro es dar una visión global de las técnicas y herramientas de las que disponemos en Python para diseñar y desarrollar aplicaciones basadas en microservicios que faciliten el mantenimiento de las aplicaciones. El diseño de microservicios hace posible aislar características y funcionalidades relacionadas con el desarrollo de microservicios mantenidos de forma independiente.

Para el uso de nuevos tipos de arquitecturas, también sería importante comprender los patrones, frameworks y herramientas que hacen que los microservicios basados en Python sean fáciles de desarrollar y mantener. Entre los principales puntos que trata el libro, podemos destacar:

•    Patrones y arquitecturas de software, donde se realiza un estudio de los principales patrones de implementación de componentes débilmente acoplados. También se efectúa un análisis de los principales patrones que se suelen utilizar por los principales frameworks para el desarrollo de aplicaciones web.

•    Python web frameworks, donde se dan a conocer los principales frameworks para crear microservicios y aplicaciones web con Python.

•    FrameWork Django, donde se realiza un estudio con más detalle de lo que ofrece Django para el desarrollo de aplicaciones web.

•    Utilizar el framework Flask para la creación de microservicios. Además, se analizan los principales gestores de dependencias, como Pipenv y Poetry, para el mantenimiento de los módulos y dependencias de un proyecto en Python.

•    Ejecución de microservicios en Python, donde se realiza un estudio de aquellos módulos de Python que nos pueden ayudar en la implementación de microservicios y su ejecución, tanto de forma síncrona como de forma asíncrona.

•    Arquitecturas Serverless: tiene como objetivo dar a conocer las principales herramientas que tenemos para implementar y desplegar microservicios en plataformas Cloud.

En el libro, se trata de seguir un enfoque teórico-práctico con el objetivo de afianzar los conocimientos mediante la creación y ejecución de scripts desde la consola de Python. Además, se provee de un repositorio, donde se pueden encontrar los ejemplos que se analizan a lo largo del libro, para facilitar al lector las pruebas y asimilación de los contenidos teóricos.

A lo largo del libro, el lector encontrará ejemplos de código fuente en el lenguaje de programación Python. Se puede acceder al GitHub donde están alojados los scripts y proyectos implementados, organizados por capítulos, desde http://marcombo.info/ con el código PYTHON24. Adjunto a cada ejemplo de código, podrá ver la ruta donde se encuentra dentro del capítulo correspondiente.

Se recomienda al lector seguir los ejemplos prácticos del libro junto con el código fuente que podemos encontrar en el repositorio de GitHub, con el objetivo de que se puedan practicar los conceptos que se analizan de forma teórica. Todos los scripts se pueden probar con versiones recientes de Python. En este punto, se recomienda al lector probar los scripts con una versión de python >= 3.8. En la página https://www.python.org/downloads, se puede descargar diferentes versiones, incluida la última.

CAPÍTULO 1PATRONES Y ARQUITECTURAS DE SOFTWARE

1.1. Introducción

Una arquitectura incluye a las decisiones que definen cuáles son los componentes que forman parte de una solución y el modo en el que estos se relacionan para interactuar en un ecosistema que dará soporte a la solución que representa. De esta forma, se establece la estructura de una aplicación actual, su futuro estado, habilitando el cumplimiento de la estrategia definida, así como los estados intermedios que aseguran la continuidad de la entrega de valor.

El proceso de creación o evolución de una arquitectura es el conjunto de actividades que deben sucederse para definir el estado futuro que soportará los requerimientos técnicos y funcionales identificados, y habilitará a que sean cubiertos mediante la creación de soluciones de software adecuadas cuando esta no exista, o la modificación cuidadosa y precisa de soluciones existentes en aquellos casos donde no se comience desde cero.

El objetivo de los patrones de software es el de mostrar una solución, aceptada y probada por la industria, a un problema de diseño recurrente en una manera estandarizada que permita ser comunicada y reutilizada fácilmente. Los estilos arquitectónicos son un tipo de patrón de software para diseñar la arquitectura.

Una arquitectura es el conjunto de decisiones significativas sobre la organización de un sistema de software que define los principios que guían el desarrollo, los componentes principales del sistema, sus responsabilidades y la manera en que se interrelacionan. En definitiva, una arquitectura debe servir para dar forma a un sistema en sus inicios, asegurando que se cumplan los requerimientos en el momento de su concepción, pero, al mismo tiempo, soporte su evolución.

El trabajo de arquitectura comienza en las etapas tempranas de un proyecto de creación de soluciones de software, buscando obtener todo el conocimiento necesario sobre la situación actual desde donde se parte, ya que esta podrá habilitar o restringir la solución futura. Como se establece en TOGAF (The Open Group Architecture Framework), estas etapas de definición de la arquitectura tienen como objetivo obtener detalles:

•    Aquellos principios que la organización define como «reglas que cumplir» en la ejecución de sus actividades.

•    El alcance del proyecto en cuestión y del trabajo de arquitectura relacionado, estableciendo claramente qué queda dentro del scope y qué aspectos serán vistos en etapas posteriores.

•    Los recursos técnicos y skills de los miembros de los equipos técnico y funcional.

•    Otras restricciones, como pueden ser el tiempo, los costes o las regulaciones de la industria.

En resumen, es la etapa donde se identifican las influencias y restricciones principales del trabajo de arquitectura, y se da forma a su alcance. Con respecto a las personas involucradas, podemos identificar los siguientes roles:

•    Stakeholders, o las personas influyentes en el trabajo de arquitectura, siendo estos, por ejemplo, los product owners en metodologías ágiles, o los responsables funcionales y del negocio en una visión más general. No debemos olvidar que, en última instancia, la arquitectura da soporte a la entrega de valor al negocio.

•    Arquitecto de software. Es importante que tenga experiencia definiendo arquitecturas de software.

•    Equipo técnico, donde encontramos a analistas y desarrolladores, principalmente.

En lo que se refiere a restricciones, podemos tener como ejemplos:

•    Costes. Este aspecto puede guiarnos en limitar las alternativas hacia soluciones open source, o reutilizando componentes técnicos o skills existentes.

•    Tiempos. Aquí es importante definir el tiempo en que debe ser lanzada la nueva solución a producción. En este punto, resulta importante identificar qué es lo que realmente se requiere para tener un Minimum Viable Product (MVP) y cuáles aspectos pueden entregarse posteriormente de manera iterativa.

•    Regulación. Muchas industrias se encuentran ampliamente reguladas. Conocer las regulaciones que impactan en la problemática alcanzada por el trabajo de arquitectura es vital para guiar la toma de decisiones.

•    Recursos. Relacionados con los skills existentes en los equipos técnicos de la organización, y de qué otros recursos se disponen para la toma de decisiones.

A la hora de diseñar arquitecturas de sistemas empresariales, no existe un solo enfoque que resuelva todas las situaciones. Es, con base en esto, que existen patrones, o formas probadas de resolver un problema en virtud de prácticas usadas en problemas similares.

Pensar en arquitecturas es una tarea compleja, que requiere de un correcto balance entre diferentes aspectos, teniendo en cuenta qué se quiere cubrir (requerimientos funcionales), cómo se debe comportar el sistema (los atributos de calidad) y las diferentes restricciones que puedan existir.

A la hora de pensar en una arquitectura, podemos aplicar el principio de «divide y vencerás». Es imposible pensar un sistema complejo viéndolo a nivel general, ya que nos perderemos sus diversas aristas, corriendo el riesgo de tomar decisiones con un sesgo de conocimiento que nos impide detectar problemas en otros ámbitos. Por eso pensamos en los sistemas como módulos o subsistemas, los cuales agrupan componentes arquitecturales relacionados, ya sea desde el punto de vista de negocio, organizacional o tecnológico.

Podemos, entonces, entender a los componentes como bloques de funcionalidad únicos del sistema con interfaces definidas que deben seguir determinados principios de diseño para interactuar entre ellos, asegurando su funcionalidad de la forma esperada.

No hay una regla única para todos los casos, pero una buena aproximación consiste en comprender todas las aristas que me permitan tomar decisiones sin sesgos de información. Si hay alguna duda que no comprendamos del todo sobre cómo abordarlo, entonces, lo mejor es dividir el problema nuevamente en partes. Si bien existen diferentes aspectos que tener en cuenta a la hora de diseñar arquitecturas, entre los principales criterios, podemos destacar:

•    Modularización. La modularidad es la propiedad de un sistema de ser dividido en partes más pequeñas (llamadas «módulos») independientes lo más posible entre sí, pero conectadas para colaborar de manera coordinada en la concreción del objetivo del sistema. Aplicar modularización en un sistema tiene varias ventajas, entre las que podemos destacar:

○    Minimización de impacto ya que, mientras se respeten los criterios de conectividad entre módulos (parámetros de entrada y salida y protocolos), podemos hacer un cambio en un módulo sin impactar en el resto.

○    Evolución independiente. Cada componente puede evolucionar de manera independiente del resto.

○    Elasticidad de capacidad de trabajo. Podemos tener a equipos dedicados a cada módulo, lo que permite paralelizar la tarea de creación o evolución de un sistema.

•    Abstracción. La capacidad de abstracción hace pensar en cada módulo de un sistema como una caja negra. Desde el exterior, como consumidor de un módulo, nos interesa cuáles son las acciones que este puede realizar, pero no de qué manera las realiza. Provee de límites conceptuales entre cada uno de los módulos, lo que habilita las bondades de la modularización. La abstracción, al depender de la definición de interfaces o puntos de conexión claros entre los módulos, agrega niveles de abstracción que pueden llegar a penalizar la performance, aunque esto solo debe tenerse en cuenta en casos extremos, donde los requerimientos son muy exigentes.

•    Encapsulamiento. El «encapsulamiento» separa las características principales de un módulo de las que no lo son, evitando módulos complejos que sean difíciles de modificar u operar. Oculta la complejidad de la gestión de estados interna de un módulo, lo que permite solo operar con estos mediante operaciones claramente definidas, aplicando abstracción.

•    Separación de responsabilidades. La separación de responsabilidades es un principio de diseño que dicta la separación de un sistema en partes o módulos, cada uno de los cuales posee un conjunto único de responsabilidades asociadas, las cuales solo dicho módulo cumple dentro del sistema. Esta separación se logra aplicando encapsulamiento y abstracción, lo que asegura que, dentro de un sistema, no existan dos módulos que realicen la misma tarea o tengan la misma responsabilidad. La aplicación de este principio asegura un mayor grado de libertad en todo el ciclo de vida de una aplicación.

•    Acoplamiento. El «acoplamiento» define el nivel de interdependencia entre módulos de un sistema. Cuanto más alto el acoplamiento, más complejo será un sistema, su mantenimiento y operación. El acoplamiento se debe definir no por la cantidad de dependencias entre los módulos sino, principalmente, por la calidad de su dependencia. De esta forma, podemos definir los siguientes niveles de acoplamiento:

○    Acoplamiento entre datos. Se produce por la gestión por parte de dos módulos de la misma información o conjunto de datos.

○    Acoplamiento por lógica. Se produce cuando el acoplamiento se plasma por reutilización de código o lógica de negocio entre módulos.

○    Acoplamiento por interfaz. Representa el modo de acoplamiento más deseable, donde cada módulo aplica claramente el principio de separación de responsabilidades y presenta interfaces claras para interactuar con sus datos y lógica.

•    Cohesión. Frecuentemente, el acoplamiento va de la mano del concepto de «cohesión»; concepto por el que se dicta que, cuanto más alta la cohesión, más relacionadas las funciones internas de un módulo entre sí, lo que hace posible un bajo acoplamiento. Por el contrario, cuando un módulo es poco cohesivo, implica una baja relación funcional entre sus funciones internas, aumentando el nivel de interdependencia entre módulos, lo que lleva a un alto acoplamiento.

•    No duplicación. El principio de no duplicación implica que cada porción de la lógica de un sistema debe tener un único componente que la soporte. La aplicación de este principio habilita la modularidad, el bajo acoplamiento, mientras que es habilitado por una correcta aplicación del principio de separación de responsabilidades.

•    Parametrización y configurabilidad. Si existen datos o porciones de información que modifican el entorno en el cual la lógica de un módulo se ejecuta, estos datos no deben formar parte de la lógica, sino que deben ser externalizados vía parametrización o configuración; por ejemplo, un módulo puede requerir consumir una application programming interface (API) de un sistema externo, cuya URL depende del entorno en el que se esté ejecutando. Estos casos se pueden resolver de una manera más elegante y escalable mediante la externalización de dichos atributos mediante variables de entorno o archivos de configuración.

1.2. Patrones de arquitectura

Como hemos comentado, el objetivo de los patrones de software es el de mostrar una solución, aceptada y probada por la industria, a un problema de diseño recurrente en una manera estandarizada que permita ser comunicada y reutilizada fácilmente.

Los patrones de arquitectura expresan un esquema organizativo fundamental sobre la estructura de un sistema de software y proporcionan un conjunto de subsistemas predefinidos, especifican sus responsabilidades e incluyen reglas y recomendaciones para organizar las relaciones entre los subsistemas. Un patrón de arquitectura define:

•    Qué forma tienen los componentes.

•    Qué forma tiene la comunicación entre esos componentes.

•    Qué restricciones se ponen a esa comunicación.

La selección de un patrón de arquitectura es una decisión de diseño fundamental cuando se desarrolla un software, ya que afectará a la mayor parte del sistema y sus componentes. Suelen elegirse en una etapa temprana del diseño, ya que cambiarlos posteriormente podría introducir costes adicionales. A continuación, vamos a analizar con más detalle los principales patrones de arquitectura de software.

1.2.1. Patrón de estructuración

Este patrón se basa en la separación de responsabilidades, definiendo al sistema como un conjunto de componentes con interfaces claramente definidas, que interactúan entre sí para darle forma.

Todos los procesos están divididos en diferentes componentes de tal modo que toda la información y funciones dentro de cada uno de ellos esté semánticamente relacionada, buscando modularidad y cohesión. Luego, un sistema estará formado por la coordinación de estos componentes, de la manera menos acoplada posible.

Se trata de un patrón muy utilizado en la actualidad, ya que es el núcleo de conceptos asociados a la programación orientada a objetos y lenguajes de programación como Java o NET, entre otros. Este patrón arquitectónico es de utilidad cuando:

•    Se desea dividir el esfuerzo de desarrollo entre diferentes equipos.

•    Se busca maximizar la reutilización.

•    La latencia dada por la comunicación entre módulos no es un impacto para la performance requerida.

•    Se busca escalabilidad de cada componente por separado.

1.2.2. Aplicación monolítica

En este patrón arquitectónico, la arquitectura se describe como una única capa o componente, donde todas las problemáticas asociadas a él (front-end, business logic o data access) están combinadas en un único punto. El principal problema de este patrón radica en que no aplica modularidad y, en general, son ejecuciones procedurales que dan inicio y fin a un grupo de funciones.

Si bien es un patrón arquitectónico en desuso por las complejidades asociadas a la falta de modularidad, aún puede verse en algunas herramientas orientadas a aplicaciones mainframe o de finanzas, donde se requiere gestionar los datos como parte de la aplicación por cuestiones de seguridad.

Los problemas que presentan las aplicaciones monolíticas donde toda la lógica está en una aplicación en un servidor son:

•    Son grandes y difíciles de modificar.

•    Realizan múltiples funcionalidades.

•    Hay un único punto de fallo: un error puede afectar al sistema entero.

•    Requieren escalar el monolito entero, lo que es poco eficiente.

•    Hacen muy difícil emplear la tecnología más adecuada para cada problema de la aplicación o adoptar nuevas.

•    Los despliegues de nuevas versiones pueden ser problemáticos por el tamaño de la aplicación.

1.2.3. Capas jerárquicas

Se trata de un patrón arquitectónico que permite dividir en capas un sistema con el objetivo de dividir sus responsabilidades. En este patrón, cada capa:

•    Provee de servicios a la capa superior, a través de interfaces claras.

•    Es cliente de la capa inferior, minimizando las dependencias entre ellas.

•    Puede pensarse como un todo coherente, sin conocer demasiado sobre las otras. Es posible, por ejemplo, conocer cómo funciona FTP sin saber demasiado sobre el protocolo de control de transmisión (TCP, la capa sobre la que se apoya).

Es un patrón muy utilizado, tanto para diseñar sistemas de software como para definir protocolos de comunicación, como los modelos OSI y TCP/IP, donde los sistemas basan su diseño en distintos niveles de abstracción.

Diferentes implementaciones de una misma capa pueden ser usadas e intercambiadas de ser necesario. Esto permite definir estándares para las interfaces y, luego, poder utilizar cualquiera de las implementaciones de una capa.

Un sistema en capas está organizado jerárquicamente, donde cada capa provee de servicios a la capa superior y consume los que brinda la capa inferior.

Existen distintas variantes de esta organización, dependiendo de si una capa puede consumir y brindar servicios solo a las capas adyacentes, o a todas las superiores/inferiores.

La mayor dificultad de este patrón está en encontrar las abstracciones adecuadas, sin romper las reglas de intercomunicación entre capas. Cuando este patrón no es correctamente implementado, se transforma en un problema complejo, sobre todo cuando hay que realizar modificaciones. Cuando es correctamente ejecutado y sus reglas cumplidas, ofrece las siguientes ventajas:

•    Cuando los cambios para realizar atacan solo una capa, resultan simples de hacer y replicar.

•    Habilita a la estandarización sobre cómo abordar las diferentes responsabilidades en cada capa.

Y, aun cuando es bien utilizado, presenta algunas desventajas, entre las que podemos destacar:

•    En general, los cambios en una capa afectan al resto. Esto genera una cadena de cambios en cascada que impactan en todo el sistema; por ejemplo, en un sistema en tres capas, si quiero añadir un dato nuevo, esto implica modificar las tres capas.

•    Si la performance es un aspecto importante que tener en cuenta, añadir más capas puede jugar en contra de la performance.

Entre las organizaciones típicas en sistemas software destacamos el modelo de dos capas cliente-servidor.

Figura 1.1. Modelo cliente-servidorFuente:https://commons.wikimedia.org/wiki/File:Modelo_Cliente-Servidor.png

Actualmente, gran parte de los sistemas que usamos todos los días utilizan este patrón arquitectónico que describe al sistema como la cooperación entre cliente y servidor. El servidor es responsable de proveer de una función o servicio a uno o varios clientes. Estos últimos realizan solicitudes al servidor para acceder a dichos servicios.

En el esquema de tres capas, la capa de datos almacena la información y permite su consulta y modificación. La capa de presentación presenta las vistas de los datos a los usuarios y la interacción con ellos. En la capa de negocio, se determina la lógica y reglas directamente relacionadas con el dominio de la aplicación. Hoy día, las aplicaciones en tres capas son las más comunes y expresan al sistema como las siguientes responsabilidades:

•    Capa de presentación: provee de servicios y presentación de la información al usuario.

•    Capa de negocio: contiene la ejecución de la lógica de negocio.

•    Capa de acceso a datos: da acceso a la información ofrecida por diferentes repositorios y bases de datos. No hay que suponer que siempre estará constituida por una base de datos, ya que puede ser un sistema externo el que cumpla dicha función.

En los últimos años, se ha comenzado a utilizar una capa intermedia entre la capa de negocio y la capa de presentación denominada «capa de servicios». La principal motivación es proveer de una interfaz simple para el acceso a la capa de negocio desde distintas formas de presentación.

1.2.4. Procesamiento batch o secuencial

En este patrón arquitectónico, el sistema se describe como una cadena de componentes entrelazados, donde la información producida por un eslabón es la entrada del siguiente punto, y cada componente puede iniciar su procesamiento solo cuando el anterior en la cadena ha terminado su tarea.

Este patrón deviene útil para flujos de datos secuenciales y considera una tarea compleja que puede ser subdividida en subtareas más pequeñas, donde cada subtarea se termina en su completitud y se envía el conjunto total de los datos procesados a la siguiente.

Cada uno de los pasos de procesamiento son programas independientes, y los datos entre ellos se transmiten como un todo. Requiere de un componente de control externo a los procesos que gobierne la ejecución y esté al tanto de la completitud de un paso para dar inicio al siguiente en la cadena. En el diagrama de la figura 1.2, se muestra cómo funciona este patrón.

Figura 1.2. Modelo secuencial o batch

Este patrón arquitectónico puede ser de utilidad cuando nos interesa trabajar con grupos de datos de manera secuencial donde la información debe pasar por diferentes fases y cada fase requiere que la información esté previamente procesada de manera completa en la fase anterior.

1.2.5. Tuberías y filtros (Pipes and Filters)

Este patrón se enfoca en la transformación incremental de la información a través de componentes sucesivos. El flujo de la información es derivado por los datos, y el sistema completo está formado por componentes denominados data sources («fuentes de los datos»), filters, pipes y data sinks («salidas de los datos»). Sus principales componentes son:

•    Los filtros transforman los datos sin retener información del estado.

•    Los pipes mueven los datos entre los filtros y permiten la flexibilidad en las conexiones.

Figura 1.3. Modelo de tuberías y filtros

A diferencia del patrón anterior, en este caso no es necesario que cada tarea se termine completamente, y un filtro puede estar tomando los datos del filtro anterior a medida que se generan. Este patrón hace hincapié en la transformación incremental de datos mediante componentes colocados sucesivamente. Las principales ventajas de este estilo son:

•    Asegura la escalabilidad, ya que cada conjunto de datos puede procesarse en componentes independientes.

•    Bajo acoplamiento, lo que habilita a la modificabilidad simple de cada componente.

•    Flexibilidad, debido al soporte en funcionamiento secuencial o en paralelo.

1.2.6. Microkernel

El patrón microkernel se aplica a sistemas de software susceptibles a cambios en el tiempo. Separan la mínima funcionalidad principal (el core) de la funcionalidad extendida y las partes específicas del cliente.

Durante el diseño de un sistema aplicando el patrón microkernel, resulta fundamental encontrar las funcionalidades esenciales que necesitarán la gran mayoría de las extensiones. Estas funcionalidades formarán parte del microkernel y brindarán servicios básicos hacia el resto de los componentes, buscando un equilibrio en el número de funcionalidades.

En la figura 1.4, podemos ver el diagrama de componentes de este tipo de arquitectura.

Figura 1.4. Modelo de componentes para arquitectura microkernel

El microkernel provee de dos tipos de componentes «servidores»:

•    Unos internos, que extienden la funcionalidad que provee al microkernel

•    Unos externos, que proveen de interfaces de programación a los clientes

Los servidores internos son utilizados por los externos a través del microkernel como una extensión de este. Los externos resuelven a través del microkernel la funcionalidad invocada por los clientes. De esta forma, el cliente no interactúa directamente sobre los servidores externos, sino que lo hace a través de adaptadores.

Al aplicar este patrón, es importante saber que el tamaño del microkernel no tiene que ser muy grande y, a la vez, debe cubrir todas las necesidades básicas de las extensiones.

1.2.7. Arquitecturas orientadas a servicios (SOA)

En este patrón arquitectónico, el sistema es visto como una serie de servicios estándar publicados por un componente, para que otros puedan hacer uso de él a través de un protocolo de comunicación sobre una red.

Un servicio SOA es una unidad de funcionalidad discreta a la que se puede acceder de manera remota y actuar de modo independiente de cualquier otro servicio. Si bien no es obligatorio, mediante la especificación de los estándares WS-* y SOAP (Simple Object Access Protocol), se busca que sea independiente de productos y tecnología. Un servicio tiene cuatro propiedades, de acuerdo con la definición de SOA:

•    Un servicio representa una actividad de negocio, con un resultado específico. Así, por ejemplo, podríamos tener el servicio get-customers, que devuelve todos los clientes, o el servicio update-order, que modifica un pedido.

•    Un servicio es autocontenido, lo que quiere decir que no depende de otro servicio para ejecutarse, sino solo de los parámetros con los que es invocado.

•    Un servicio es una caja negra para sus consumidores, ocultando la complejidad de su implementación, siendo el contrato y los datos que se intercambian las únicas partes visibles a los clientes.

Este patrón arquitectónico tuvo gran auge hace unos años y aún sigue siendo utilizado en algunas empresas, aunque ha caído en desuso debido a la complejidad de su implementación y lo pesado de su protocolo, y ha sido reemplazado en la práctica por REST. Cualquier arquitectura distribuida moderna debería hacer uso del patrón arquitectónico REST para realizar integraciones si lo que busca es asegurar performance, confiabilidad y escalabilidad.

1.2.8. Arquitectura REST

Representational State Transfer (REST) es un patrón arquitectónico que establece una serie de restricciones, basadas en el estándar HTTP, para la creación de interfaces entre sistemas. A diferencia de la orientación a servicios, este estilo busca exponer las capacidades de un sistema como modificaciones a recursos web o sus entidades, ocultando la complejidad de su implementación, basándose en los métodos estándar HTTP.

HTTP define varios tipos de operaciones o verbos, que pueden ser GET, PUT, POST, DELETE o PATCH, entre otros. Es importante saber para qué están pensados cada verbo, de modo que sean utilizados correctamente por los clientes:

•    GET: se utiliza para consultar, leer y, en definitiva, acceder a un recurso.

•    POST: envía datos para crear un recurso. Como en cualquier petición POST, los datos deben ir incluidos en el cuerpo de la petición.

•    PUT: se usa para editar un recurso. Al igual que el POST, los datos han de ir en el cuerpo de la petición.

•    DELETE: es la opción para eliminar un recurso.

•    PATCH: se utiliza para modificar parcialmente un recurso, aunque se emplea en muy pocas ocasiones. Normalmente, se usa simplemente PUT.

Un sistema RESTful está guiado por seis restricciones que condicionan la forma en que un servidor (quién expone la funcionalidad o los datos) y un cliente (quién hace uso de la funcionalidad o accede a los datos) intercambian información. Estas restricciones son:

•    Arquitectura cliente/servidor. Este es el patrón arquitectónico utilizado para separar los aspectos de interfaz de la implementación o los datos, mejorando la portabilidad de los servicios entre diferentes plataformas, además de mejorar la escalabilidad por la simplificación de los componentes del servidor. El principio detrás de esta restricción es la separación de responsabilidades. Separar el componente dueño de la lógica de sus interfaces asegura la escalabilidad y reutilización de la lógica en diferentes momentos y situaciones, lo que permite que cada componente evolucione de manera independiente.

•    No existe estado en el servidor. El componente servidor no almacena ningún componente de estado de sus clientes, haciendo que cada interacción sea independiente de otra. Todas las interacciones entre el cliente y el servidor tienen la información necesaria para entender la petición, sin tener que depender de la información almacenada en el servidor.

•    Caché. Las respuestas pueden estar implícita o explícitamente marcadas como cacheables o no cacheables. Implementando una caché, se salva en parte las debilidades tenidas por la arquitectura de comunicación stateless. Si una respuesta es cacheable, entonces el cliente puede usar los datos de esa respuesta en el futuro, sin hacer una nueva petición. Al eliminarse en forma potencial muchas interacciones, se mejora la eficiencia, la escalabilidad y la performance percibidas por el cliente.

•    Diseño en capas. Un cliente no puede a ciencia cierta conocer si está conectado al servidor final de la funcionalidad o dato que almacena, o a un intermediario. Si existe un proxy o balanceador entre el cliente y el servidor, este no puede afectar a la comunicación ni requerir cambios en el cliente. Ejemplos de este principio es la existencia de API Gateways.

La característica principal que caracteriza a REST es el énfasis en una interfaz uniforme entre los componentes. Aplicando el principio de generalidad a la interfaz de los componentes, la arquitectura se simplifica y se mejora la visibilidad e interacción. Mediante la aplicación del principio de generalidad a la interfaz, se simplifica la arquitectura completa y se mejora la visibilidad de las interacciones.

Para poder lograr interfaces uniformes, se añaden múltiples restricciones a la arquitectura, entre las que podemos destacar:

•    Identificación de recursos en las peticiones: los recursos individuales que forman parte de las interfaces REST definidas se identifican en las peticiones. En un sistema REST, cada recurso es direccionable únicamente a través de su Uniform Resource Identifier (URI).

•    Manipulación de recursos a través de representaciones: la manipulación de los recursos se realiza a través de sus representaciones, utilizando los métodos HTTP de manera explícita (GET —consultar un recurso—, POST —crear un recurso—, PUT —modificar un recurso— y DELETE —eliminar un recurso—), y basándose en la información obtenida de la representación de los recursos. Cuando un cliente cuenta con la representación de un recurso, dispone de la suficiente información como para modificar o eliminar el recurso y su estado.

•    Mensajes autodescriptivos: cada mensaje debe incluir suficiente información como para procesarlo.

•    Uso correcto de HTTP: