Principios para desarrollar aplicaciones modernas desde NGINX. Parte 1

Hola amigos. En previsión del lanzamiento del curso. Desarrollador back-end de PHP, tradicionalmente comparte con ustedes la traducción de material útil.

El software resuelve cada vez más tareas cotidianas, mientras se vuelve cada vez más complejo. Como dijo una vez Marc Andressen, consume el mundo.

Principios para desarrollar aplicaciones modernas desde NGINX. Parte 1

Como resultado, la forma en que se desarrollan y entregan las aplicaciones ha cambiado drásticamente en los últimos años. Estos fueron cambios de escala tectónica que dieron como resultado un conjunto de principios. Estos principios han demostrado ser útiles en la creación de equipos, el diseño, el desarrollo y la entrega de su aplicación a los usuarios finales.

Los principios se pueden resumir de la siguiente manera: la aplicación debe ser pequeña, basada en la web y tener una arquitectura centrada en el desarrollador. Con estos tres principios en mente, puede crear una aplicación robusta de extremo a extremo que se pueda entregar de manera rápida y segura al usuario final, y que sea fácilmente escalable y extensible.

Principios para desarrollar aplicaciones modernas desde NGINX. Parte 1

Cada uno de los principios propuestos tiene una serie de aspectos que discutiremos para mostrar cómo cada principio contribuye al objetivo final, que es la entrega rápida de aplicaciones confiables que son fáciles de mantener y usar. Veremos los principios en relación con sus opuestos para aclarar lo que significa, decir: "Asegúrate de usar principio de pequeñez".

Esperamos que este artículo lo anime a utilizar los principios propuestos para crear aplicaciones modernas, lo que proporcionará un enfoque unificado para el diseño en el contexto de una pila de tecnología en constante crecimiento.

Al aplicar estos principios, se encontrará aprovechando las últimas tendencias en desarrollo de software, incluida la DevOps al desarrollo y entrega de aplicaciones, el uso de contenedores (por ejemplo, Docker) y marcos de orquestación de contenedores (por ejemplo, Kubernetes), el uso de microservicios (incluida la arquitectura de microservicios Nginx и arquitectura de comunicación de red para aplicaciones de microservicios.

¿Qué es una aplicación moderna?

¿Aplicaciones modernas? pila moderna? ¿Qué significa exactamente "moderno"?

La mayoría de los desarrolladores solo tienen una idea general de en qué consiste una aplicación moderna, por lo que es necesario definir claramente este concepto.

Una aplicación moderna admite varios clientes, ya sea una interfaz de usuario de la biblioteca React JavaScript, una aplicación móvil Android o iOS, o una aplicación que se conecta a otra API. Una aplicación moderna implica un número indefinido de clientes a los que proporciona datos o servicios.

Una aplicación moderna proporciona una API para acceder a los datos y servicios solicitados. La API debe ser inmutable y constante, y no estar escrita específicamente para una solicitud específica de un cliente específico. La API está disponible a través de HTTP(S) y brinda acceso a todas las funciones disponibles en la GUI o la CLI.

Los datos deben estar disponibles en un formato interoperable comúnmente aceptado, como JSON. Una API expone objetos y servicios de una manera limpia y organizada, como RESTful API o GraphQL, que proporcionan una interfaz decente.

Las aplicaciones modernas se basan en la pila moderna, y la pila moderna es la pila que admite dichas aplicaciones, respectivamente. Esta pila permite a un desarrollador crear fácilmente una aplicación con una interfaz HTTP y puntos finales de API claros. El enfoque elegido permitirá que su aplicación reciba y envíe datos fácilmente en formato JSON. En otras palabras, la pila moderna corresponde a los elementos de la Aplicación de Doce Factores para microservicios.

Las versiones populares de este tipo de pila se basan en Java, Python, Nodo, Rubí, PHP и Go. Arquitectura de microservicios Nginx representa un ejemplo de una pila moderna implementada en cada uno de los lenguajes mencionados.

Tenga en cuenta que no estamos defendiendo un enfoque exclusivamente de microservicio. Muchos de ustedes están trabajando con monolitos que necesitan evolucionar, mientras que otros están lidiando con aplicaciones SOA que se están expandiendo y evolucionando para convertirse en aplicaciones de microservicios. Otros se están moviendo hacia aplicaciones sin servidor y algunos están implementando combinaciones de lo anterior. Los principios descritos en el artículo se aplican a cada uno de estos sistemas con solo algunas modificaciones menores.

Principios

Ahora que tenemos un entendimiento común de lo que son una aplicación moderna y una pila moderna, es hora de profundizar en la arquitectura y los principios de desarrollo que le serán útiles para desarrollar, implementar y mantener una aplicación moderna.

Uno de los principios suena como "hacer pequeñas aplicaciones", llamémoslo principio de pequeñez. Hay aplicaciones increíblemente complejas que se componen de muchas partes móviles. A su vez, la creación de una aplicación a partir de componentes pequeños y discretos facilita el diseño, el mantenimiento y el trabajo con ella como un todo. (Tenga en cuenta que dijimos "simplifica" no "hace simple").

El segundo principio es que podemos aumentar la productividad de los desarrolladores ayudándolos a concentrarse en las características que están desarrollando, mientras los liberamos de las preocupaciones de infraestructura y CI/CD durante la implementación. Entonces, en pocas palabras, nuestro enfoque enfocado en desarrolladores.

Finalmente, todo lo relacionado con su aplicación debe estar conectado a la red. Durante los últimos 20 años, hemos dado grandes pasos hacia un futuro en red a medida que las redes se vuelven más rápidas y las aplicaciones más complejas. Como hemos visto, una aplicación moderna debe ser utilizada en una red por muchos clientes diferentes. Aplicar el pensamiento de red a la arquitectura tiene beneficios significativos que van bien con principio de pequeñez y el concepto del enfoque, orientado al desarrollador.

Si tiene en cuenta estos principios al diseñar e implementar una aplicación, tendrá una ventaja innegable en el desarrollo y la entrega de su producto.

Veamos estos tres principios con más detalle.

Principio de pequeñez

Es difícil para el cerebro humano percibir una gran cantidad de información al mismo tiempo. En psicología, el término carga cognitiva se refiere a la cantidad total de esfuerzo mental requerido para retener información en la memoria. Reducir la carga cognitiva de los desarrolladores es una prioridad porque les permite concentrarse en resolver el problema en lugar de mantener en su mente el modelo complejo actual de toda la aplicación y las características que se están desarrollando.

Principios para desarrollar aplicaciones modernas desde NGINX. Parte 1

Las aplicaciones se descomponen por las siguientes razones:

  • Carga cognitiva reducida en los desarrolladores;
  • Aceleración y simplificación de las pruebas;
  • Entrega rápida de cambios en la aplicación.


Hay varias formas de reducir la carga cognitiva de los desarrolladores, y aquí es donde entra en juego el principio de la pequeñez.

Así que aquí hay tres formas de reducir la carga cognitiva:

  1. Reduzca el marco de tiempo que tienen que considerar al desarrollar una nueva función: cuanto más corto sea el marco de tiempo, menor será la carga cognitiva.
  2. Reduzca la cantidad de código en el que se realiza el trabajo de una sola vez: menos código, menos carga.
  3. Simplifique el proceso de realizar cambios incrementales en una aplicación.

Reducir el marco de tiempo de desarrollo

Volvamos a los días en que la metodología waterfall era el estándar para el proceso de desarrollo, y los plazos de seis meses a dos años para desarrollar o actualizar una aplicación eran una práctica común. Por lo general, los ingenieros primero leían documentos relevantes, como los requisitos del producto (PRD), el documento de referencia del sistema (SRD), el plano de la arquitectura, y comenzaban a combinar todas estas cosas en un modelo cognitivo, según el cual codificaron. A medida que cambiaban los requisitos y, en consecuencia, la arquitectura, se tuvo que hacer un gran esfuerzo para informar a todo el equipo sobre las actualizaciones del modelo cognitivo. Tal enfoque, en el peor de los casos, podría simplemente paralizar el trabajo.

El mayor cambio en el proceso de desarrollo de aplicaciones fue la introducción de la metodología ágil. Una de las principales características de la metodología agile es un desarrollo iterativo. A su vez, esto conduce a una reducción de la carga cognitiva de los ingenieros. En lugar de requerir que el equipo de desarrollo implemente la aplicación en un ciclo largo, agile El enfoque le permite concentrarse en pequeñas cantidades de código que se pueden probar e implementar rápidamente, al mismo tiempo que recibe comentarios. La carga cognitiva de la aplicación ha pasado de un período de tiempo de seis meses a dos años con una gran cantidad de especificaciones para agregar o cambiar funciones en dos semanas, lo que apunta a una comprensión más borrosa de una aplicación grande.

Cambiar el enfoque de una aplicación masiva a funciones pequeñas específicas que se pueden completar en un sprint de dos semanas, con no más de una función en mente antes del próximo sprint, es un cambio significativo. Esto nos permitió aumentar la productividad del desarrollo al mismo tiempo que reducíamos la carga cognitiva, que fluctuaba constantemente.

en metodologia agile Se espera que la aplicación final sea una versión ligeramente modificada del concepto original, por lo que el punto final del desarrollo es necesariamente ambiguo. Solo los resultados de cada sprint específico pueden ser claros y precisos.

Bases de código pequeñas

El siguiente paso para reducir la carga cognitiva es reducir la base de código. Como regla general, las aplicaciones modernas son masivas: una aplicación empresarial robusta puede constar de miles de archivos y cientos de miles de líneas de código. Dependiendo de cómo estén organizados los archivos, los vínculos y las dependencias entre el código y los archivos pueden ser obvios, o viceversa. Incluso la ejecución del código de depuración en sí puede ser problemática, según las bibliotecas utilizadas y qué tan bien las herramientas de depuración distinguen entre bibliotecas/paquetes/módulos y código personalizado.

La creación de un modelo mental funcional del código de una aplicación puede llevar una cantidad de tiempo impresionante y, una vez más, supone una gran carga cognitiva para el desarrollador. Esto es especialmente cierto para las bases de código monolíticas, donde hay una gran cantidad de código, cuya interacción entre los componentes funcionales no está claramente definida, y la separación de los objetos de atención a menudo es borrosa porque no se respetan los límites funcionales.

Una de las formas efectivas de reducir la carga cognitiva de los ingenieros es pasar a una arquitectura de microservicios. En un enfoque de microservicio, cada servicio se centra en un conjunto de características; mientras que el significado del servicio suele ser definido y comprensible. Los límites de un servicio también son claros: recuerde que la comunicación con un servicio se realiza a través de una API, por lo que los datos generados por un servicio pueden transferirse fácilmente a otro.

La interacción con otros servicios generalmente se limita a unos pocos servicios de usuario y unos pocos servicios de proveedor que usan llamadas API simples y limpias, como usar REST. Esto significa que la carga cognitiva del ingeniero se reduce considerablemente. El mayor desafío sigue siendo comprender el modelo de interacción del servicio y cómo suceden cosas como las transacciones en múltiples servicios. Como resultado, el uso de microservicios reduce la carga cognitiva al reducir la cantidad de código, definir límites claros del servicio y brindar una comprensión de la relación entre usuarios y proveedores.

Pequeños cambios incrementales

El último elemento del principio. pequeñez es la gestión del cambio. Es una tentación particular para los desarrolladores mirar el código base (incluso quizás su propio código más antiguo) y decir: "Esto es una mierda, necesitamos reescribirlo todo". A veces esta es la decisión correcta, ya veces no. Pone la carga del cambio de modelo global en el equipo de desarrollo, lo que a su vez conduce a una carga cognitiva masiva. Es mejor que los ingenieros se concentren en los cambios que pueden hacer durante el sprint, para que puedan implementar la funcionalidad necesaria de manera oportuna, aunque sea gradualmente. El producto final debe parecerse al planificado previamente, pero con algunas modificaciones y pruebas para adaptarse a las necesidades del cliente.

Cuando se reescriben grandes porciones de código, a veces no es posible entregar el cambio rápidamente porque entran en juego otras dependencias del sistema. Para controlar el flujo de cambios, puede ocultar funciones. En principio, esto significa que la funcionalidad está en producción, pero no está disponible mediante la configuración de variables de entorno (env-var) o algún otro mecanismo de configuración. Si el código ha pasado todos los procesos de control de calidad, entonces puede terminar en producción en estado latente. Sin embargo, esta estrategia solo funciona si la función finalmente se habilita. De lo contrario, solo desordenará el código y agregará una carga cognitiva con la que el desarrollador tendrá que lidiar para ser productivo. La gestión de cambios y los cambios incrementales en sí mismos ayudan a mantener manejable la carga de trabajo cognitiva de los desarrolladores.

Los ingenieros tienen que superar muchas dificultades incluso con la simple introducción de funciones adicionales. Por parte de la gerencia, sería prudente reducir la carga innecesaria del equipo para que pueda concentrarse en los elementos funcionales clave. Hay tres cosas que puede hacer para ayudar a su equipo de desarrollo:

  1. Metodología de uso agilepara limitar el marco de tiempo en el que el equipo debe centrarse en las funciones clave.
  2. Implemente su aplicación como múltiples microservicios. Esto limitará la cantidad de funciones que se pueden implementar y reforzará los límites que mantienen la carga cognitiva en funcionamiento.
  3. Prefiera los cambios incrementales a los grandes y difíciles de manejar, cambie pequeños fragmentos de código. Utilice la ocultación de características para implementar cambios, incluso si no serán visibles inmediatamente después de agregarlos.

Si aplica el principio de pequeñez en su trabajo, su equipo estará mucho más contento, mejor enfocado en implementar las características necesarias y más propensos a implementar cambios cualitativos más rápido. Pero esto no significa que el trabajo no pueda complicarse más, a veces, por el contrario, la introducción de nuevas funcionalidades requiere la modificación de varios servicios, y este proceso puede ser más difícil que similar en una arquitectura monolítica. En cualquier caso, los beneficios de adoptar el enfoque de la pequeñez valen la pena.

El final de la primera parte.

Próximamente publicaremos la segunda parte de la traducción, y ahora esperamos sus comentarios y los invitamos a Dia abierto, que tendrá lugar hoy a las 20.00 horas.

Fuente: habr.com

Añadir un comentario