Principios para desarrollar aplicaciones modernas de NGINX. Parte 1

Hola amigos En previsión del lanzamiento del curso "Backend PHP Developer" , tradicionalmente compartimos con usted la traducción de material útil.

El software resuelve más y más tareas cotidianas, mientras se vuelve cada vez más difícil. Como Mark Andressen dijo una vez, se traga el mundo.



Como resultado, los enfoques para el desarrollo y la entrega de aplicaciones han cambiado drásticamente en los últimos años. Estos fueron cambios de escala tectónica, que como resultado condujeron al surgimiento de 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, en red y tener una arquitectura orientada al desarrollador . Con base en estos tres principios, puede crear una aplicación confiable y completa que se pueda entregar de manera rápida y segura al usuario final, y que se pueda escalar y expandir fácilmente.



Cada uno de los principios propuestos tiene una serie de aspectos que discutiremos para mostrar cómo cada principio contribuye al logro del objetivo final, que es entregar rápidamente aplicaciones confiables que sean fáciles de mantener y usar. Consideraremos los principios en comparación con sus opuestos para aclarar lo que significa, por ejemplo, "Asegúrate de usar el principio de pequeñez ".

Esperamos que este artículo lo aliente a usar los principios propuestos para crear aplicaciones modernas que proporcionarán un enfoque unificado para el diseño en el contexto de una pila tecnológica cada vez mayor.

Al aplicar estos principios, se encontrará aprovechando las últimas tendencias de desarrollo de software, incluido el enfoque DevOps para desarrollar y entregar aplicaciones, utilizando contenedores (como Docker ) y marcos para la orquestación de contenedores (como Kubernetes ), utilizando microservicios (incluida la arquitectura de microservicios NGINX ) y arquitectura de comunicaciones de red para aplicaciones de microservicio.

¿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 debe dar una definición clara de este concepto.

Una aplicación moderna admite varios clientes, ya sea una interfaz de usuario en la biblioteca JavaScript React, una aplicación móvil para Android o iOS, o una aplicación que se conecta a otra a través de la API. Una aplicación moderna implica la presencia de un número indefinido de clientes para quienes 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 debe estar escrita específicamente para una solicitud específica de ningún cliente en particular. Se puede acceder a la API a través de HTTP (S) y proporciona acceso a toda la funcionalidad que se encuentra en la GUI o CLI.

Los datos deben ser accesibles en un formato generalmente aceptado y compatible, como JSON. La API proporciona objetos y servicios de manera clara y organizada, por ejemplo, la API RESTful o GraphQL proporcionan una interfaz decente.

Las aplicaciones modernas se crean en una pila moderna, y una pila moderna es la pila que admite dichas aplicaciones, respectivamente. Dicha pila permite al desarrollador crear fácilmente una aplicación con una interfaz HTTP y puntos finales 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 Twelve-Factor para microservicios .

Las versiones populares de este tipo de pila se basan en Java , Python , Node , Ruby , PHP y Go . NGINX Microservice Architecture representa un ejemplo de una pila moderna implementada en cada uno de los idiomas mencionados.

Tenga en cuenta que no abogamos exclusivamente por un enfoque de microservicio. Muchos de ustedes trabajan con monolitos que necesitan evolucionar, mientras que otros tratan con aplicaciones SOA que se expanden y evolucionan para convertirse en aplicaciones de microservicio. Aún otros se están moviendo hacia aplicaciones sin servidor, y algunos están introduciendo combinaciones de lo anterior. Los principios establecidos en el artículo son aplicables a cada uno de estos sistemas con solo unos pocos cambios menores.

Principios

Ahora que tenemos una comprensión general de lo que es una aplicación moderna y una pila moderna, es hora de sumergirse en los principios de arquitectura y desarrollo que le servirán para desarrollar, implementar y soportar una aplicación moderna.

Uno de los principios es "crear pequeñas aplicaciones", llamémoslo el principio de pequeñez . Existen aplicaciones increíblemente complejas que consisten en una gran cantidad de componentes móviles. A su vez, la creación de una aplicación a partir de pequeños componentes discretos simplifica su diseño, mantenimiento y trabajo en conjunto. (Tenga en cuenta que dijimos "simplifica", no "lo hace simple").

El segundo principio es que podemos aumentar la productividad de los desarrolladores al ayudarlos a enfocarse en las funciones que desarrollan, al tiempo que los liberamos de las preocupaciones sobre la infraestructura y el CI / CD durante la implementación. En resumen, nuestro enfoque se centra en los desarrolladores .

Finalmente, todo lo relacionado con su aplicación debe estar conectado a la red. En los últimos 20 años, hemos avanzado mucho hacia un futuro en red, ya que las redes son más rápidas y las aplicaciones son más complejas. Como ya hemos descubierto, muchos clientes diferentes deberían utilizar una aplicación moderna en la red. El uso del pensamiento de red en arquitectura tiene ventajas significativas que van bien con el principio de pequeñez y el concepto de un enfoque orientado al desarrollador .

Si durante el desarrollo y la implementación de la aplicación tendrá en cuenta estos principios, 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 al mismo tiempo una gran cantidad de información. En psicología, el término carga cognitiva significa la cantidad total de esfuerzo mental requerido para almacenar información en la memoria. La reducción de la carga cognitiva en los desarrolladores es una prioridad, porque en este caso pueden centrarse en resolver el problema, en lugar de tener en cuenta el modelo complejo actual de toda la aplicación y las funciones desarrolladas.



Las aplicaciones se descomponen por los siguientes motivos:

  • Disminución de la carga cognitiva en los desarrolladores;
  • Acelerar y simplificar las pruebas;
  • Entrega rápida de cambios en la aplicación.

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

Entonces, hay tres formas de reducir la carga cognitiva:

  1. Reduzca el período de tiempo que deben tener en cuenta al desarrollar una nueva función: cuanto más corto sea el período 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 la aplicación.

Reduce los plazos de desarrollo

Volvamos a los días en que la metodología de waterfall era el estándar para el proceso de desarrollo, y el plazo de seis meses a dos años para desarrollar o actualizar la aplicación era una práctica común. Por lo general, los ingenieros primero leen los documentos relevantes, como los requisitos del producto (PRD), el documento de referencia del sistema (SRD), el plan de arquitectura, y comienzan a combinar todas estas cosas en un solo modelo cognitivo, según el cual escribieron el código. A medida que cambiaron los requisitos y, en consecuencia, la arquitectura, se tuvieron que hacer serios esfuerzos para informar a todo el equipo sobre las actualizaciones del modelo cognitivo. En el peor de los casos, este enfoque podría simplemente paralizar el trabajo.

El mayor cambio en el proceso de desarrollo de aplicaciones ha sido la introducción de la metodología ágil. Una de las principales características de la metodología agile es el desarrollo iterativo. A su vez, esto conduce a una disminución de la carga cognitiva en los ingenieros. En lugar de requerir que el equipo de desarrollo implemente la aplicación en un ciclo largo, el enfoque agile permite concentrarse en pequeñas cantidades de código que pueden probarse e implementarse rápidamente, al tiempo que recibe comentarios. La carga cognitiva de la aplicación ha cambiado del plazo de seis meses a dos años, teniendo en cuenta la gran cantidad de especificaciones para una adición de dos semanas o cambios de características, con el objetivo de una comprensión más vaga de una aplicación grande.

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

La metodología agile supone que la aplicación final será una versión ligeramente modificada del concepto original, por lo que el punto de desarrollo final es necesariamente ambiguo. Solo los resultados de cada sprint en particular pueden ser claros y precisos.

Pequeñas bases de código

El siguiente paso para reducir la carga cognitiva es reducir la base del código. Como regla general, las aplicaciones modernas son masivas: una aplicación empresarial confiable puede constar de miles de archivos y cientos de miles de líneas de código. Dependiendo de la organización de los archivos de comunicación y las dependencias del código y los archivos, pueden ser obvios o viceversa. Incluso la depuración del código en sí puede causar problemas, dependiendo de las bibliotecas utilizadas y qué tan bien las herramientas de depuración distinguen entre bibliotecas / paquetes / módulos y el código de usuario.

Construir un modelo mental funcional del código de la aplicación puede llevar una cantidad impresionante de tiempo y, nuevamente, colocar una gran carga cognitiva en el desarrollador. Esto es especialmente cierto para las bases de código monolítico, 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 en los ingenieros es la transición a una arquitectura de microservicio. En el enfoque de microservicio, cada servicio se enfoca en un conjunto de funciones; El significado del servicio es usualmente definido y entendible. Los límites del servicio también son claros: recuerde que la comunicación con el servicio se lleva a cabo utilizando la 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 varios servicios de usuario y varios servicios de proveedor que usan llamadas API simples y limpias, por ejemplo, usando REST. Esto significa que la carga cognitiva en el ingeniero se reduce seriamente. La tarea más difícil es comprender el modelo de interacción entre servicios y cómo ocurren cosas como las transacciones en varios servicios. Como resultado, el uso de microservicios reduce la carga cognitiva, reduce la cantidad de código, indica límites claros del servicio y proporciona una comprensión de la relación entre usuarios y proveedores.

Pequeños cambios incrementales

El último elemento del principio de pequeñez es la gestión del cambio. Es una tentación especial para los desarrolladores mirar la base del código (incluso, tal vez, en su propio código más antiguo) y decir: "Esto es una mierda, necesitamos reescribirlo todo". Algunas veces esta es la decisión correcta, y otras no. Coloca 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 luego implementar la funcionalidad necesaria de manera oportuna, aunque gradualmente. El producto final debe recordar a uno previamente planificado, pero con algunas modificaciones y pruebas para satisfacer las necesidades del cliente.

Al reescribir grandes partes del código, a veces es imposible entregar cambios rápidamente, ya que otras dependencias del sistema entran en juego aquí. Para controlar el flujo de cambios, puede usar la función de ocultación. En principio, esto significa que la funcionalidad está en producción, pero no está disponible utilizando la configuración de las 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 estar en producción en un estado oculto. Sin embargo, esta estrategia solo funciona si la función está finalmente habilitada. De lo contrario, solo ensuciará el código y agregará una carga cognitiva, que el desarrollador tendrá que enfrentar para un trabajo productivo. La gestión del cambio y los cambios incrementales en sí mismos ayudan a mantener la carga cognitiva de los desarrolladores a un nivel asequible.

Los ingenieros tienen que superar muchas dificultades incluso con la implementación simple de funcionalidad adicional. Por parte de la administración, sería razonable reducir la carga adicional en el equipo para que pueda enfocarse en los elementos clave de lo funcional. Hay tres cosas que puede hacer para ayudar a su equipo de desarrollo:

  1. Use una metodología agile para limitar el marco de tiempo dentro del cual un equipo debe centrarse en las funciones clave.
  2. Implemente su aplicación como múltiples microservicios. Esto limitará la cantidad de características que se implementarán y fortalecerá los límites que sostienen la carga cognitiva durante el trabajo.
  3. Prefiere cambios incrementales a grandes y voluminosos, cambia pequeños trozos de código. Use la función de ocultación para implementar cambios, incluso si no son visibles inmediatamente después de agregarlos.

Si aplica el principio de pequeñez en su trabajo, su equipo se volverá mucho más feliz, se centrará mejor en la implementación de las funciones necesarias y será más probable que desarrolle cambios cualitativos más rápido. Pero esto no significa que el trabajo no pueda ser complicado, a veces, por el contrario, la introducción de una nueva funcionalidad requiere la modificación de varios servicios y este proceso puede ser más complicado que uno similar en una arquitectura monolítica. En cualquier caso, los beneficios de un enfoque pequeño valen la pena.

El final de la primera parte.

Pronto publicaremos la segunda parte de la traducción, y ahora estamos esperando sus comentarios y los invitamos a la jornada de puertas abiertas , que se realizará hoy a las 20.00.

Source: https://habr.com/ru/post/452748/


All Articles