Hola, amigos. En la víspera del lanzamiento del curso , tradicionalmente compartimos con ustedes la traducción de un material útil.
El software resuelve cada vez más tareas cotidianas, volviéndose cada vez más complejo. Como dijo una vez Marc Andreessen, está absorbiendo el mundo.

Como resultado, en los últimos años, los enfoques para el desarrollo y la entrega de aplicaciones han cambiado significativamente. Ha habido desplazamientos de escala tectónica que han llevado a la aparición de un conjunto de principios. Estos principios han resultado útiles en la formación de equipos, diseño, desarrollo y entrega de su aplicación a los usuarios finales.
Los principios pueden resumirse de la siguiente manera: la aplicación debe ser pequeña, de red y tener una arquitectura orientada al desarrollador. Basándose en estos tres principios, puede crear una aplicación sólida y completa que pueda ser entregada rápida y seguramente al usuario final, además de ser fácilmente escalable y extensible.

Cada uno de los principios propuestos tiene una serie de aspectos que discutiremos para mostrar cómo cada principio contribuye a alcanzar el objetivo final, que es la entrega rápida de aplicaciones confiables que sean fáciles de mantener y usar. Compararemos los principios con sus opuestos para aclarar qué significa, por ejemplo, «Asegúrese de que está utilizando el principio de pequeña escala».
Esperamos que este artículo lo motive a utilizar los principios propuestos para construir aplicaciones modernas que proporcionen un enfoque unificado de diseño en el contexto de un conjunto de tecnologías en constante crecimiento.
Al aplicar estos principios, descubrirá que está utilizando las últimas tendencias en el desarrollo de software, incluido el enfoque para el desarrollo y entrega de aplicaciones, el uso de contenedores (por ejemplo, ) y marcos para la orquestación de contenedores (por ejemplo, ), el uso de microservicios (incluida la Arquitectura de Microservicios y para aplicaciones de microservicios.
¿Qué es una aplicación moderna?
¿Aplicaciones modernas? ¿Conjunto moderno? ¿Qué significa exactamente «moderno»?
La mayoría de los desarrolladores solo tienen una idea general de qué constituye una aplicación moderna, por lo que es necesario proporcionar 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 con otra a través de API. Una aplicación moderna implica la existencia de un número indefinido de clientes para los cuales 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, en lugar de estar escrita específicamente para una solicitud concreta de un cliente específico. La API está disponible a través de HTTP(S) y proporciona acceso a toda la funcionalidad disponible en la GUI o CLI.
Los datos deben estar disponibles en un formato común y compatible, como JSON. La API proporciona objetos y servicios de manera clara y organizada; por ejemplo, las API RESTful o GraphQL ofrecen una interfaz adecuada.
Las aplicaciones modernas se construyen sobre una pila moderna, que es aquella que admite tales aplicaciones. Esta pila permite al desarrollador crear una aplicación con una interfaz HTTP y puntos finales API bien definidos con facilidad. El enfoque elegido permitirá a su aplicación recibir y enviar datos en formato JSON sin esfuerzo. En otras palabras, la pila moderna se alinea con los elementos de la aplicación de doce factores. .
Las versiones populares de este tipo de pila se basan en , , , , y . La Arquitectura de Microservicios personifica un ejemplo de una pila moderna implementada en cada uno de los idiomas mencionados.
Tenga en cuenta que no estamos promoviendo exclusivamente el enfoque de microservicios. Muchos de ustedes trabajan con monolitos que deben evolucionar, mientras que otros tratan con aplicaciones SOA que se expanden y evolucionan para convertirse en aplicaciones de microservicios. Algunos se dirigen hacia la implementación de aplicaciones sin servidor (serverless), mientras que otros implementan combinaciones de lo anterior. Los principios expuestos en este artículo son aplicables a cada uno de estos sistemas con algunos cambios menores.
Principios
Ahora que hemos alcanzado un entendimiento común sobre qué son las aplicaciones modernas y el stack moderno, es hora de sumergirnos en los principios de arquitectura y desarrollo que te serán de gran ayuda en la creación, implementación y mantenimiento de una aplicación moderna.
Uno de los principios se formula como «crea aplicaciones pequeñas», llamémoslo simplemente el principio de la pequeñez. Existen aplicaciones increíblemente complejas que consisten en una gran cantidad de componentes móviles. A su vez, construir una aplicación a partir de pequeños componentes discretos simplifica su diseño, mantenimiento y funcionamiento en general. (Nota que dijimos «simplifica», y no «hace simple»).
El segundo principio es que podemos aumentar la productividad de los desarrolladores, ayudándoles a concentrarse en las funciones que están desarrollando, liberándolos de preocupaciones sobre la infraestructura y CI/CD durante la implementación. Así que, en pocas palabras, nuestro enfoque está orientado a los desarrolladores.
Finalmente, todo lo que concierne a tu aplicación debe estar conectado a la red. En los últimos 20 años, hemos avanzado enormemente hacia un futuro en red, ya que las redes se han vuelto más rápidas y las aplicaciones más complejas. Como ya hemos determinado, una aplicación moderna debe ser utilizada en red por múltiples clientes diferentes. La aplicación del pensamiento en red en la arquitectura tiene ventajas significativas que se combinan bien con el principio de la pequeñez y el concepto del enfoque, orientado a los desarrolladores.
Si al desarrollar e implementar tu aplicación mantienes estos principios en mente, tendrás una ventaja innegable en el desarrollo y la entrega de tu producto.
Examinemos estos tres principios con más detalle.
Principio de la pequeñez
Es difícil para el cerebro humano procesar una gran cantidad de información a la vez. En psicología, el término carga cognitiva se refiere a la cantidad total de esfuerzo mental necesario para mantener información en la memoria. Reducir la carga cognitiva sobre los desarrolladores es una prioridad, ya que de esta manera pueden concentrarse en resolver problemas, en lugar de mantener en su mente el modelo complejo actual de toda la aplicación y las funciones que se están desarrollando.

Las aplicaciones se descomponen por las siguientes razones:
- Reducir la carga cognitiva sobre los desarrolladores;
- Acelerar y simplificar las pruebas;
- Entregar cambios rápidamente 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.
Así que, tres formas de reducir la carga cognitiva:
- Reducir los plazos que deben considerar al desarrollar una nueva función: cuanto más corto sea el plazo, menor será la carga cognitiva.
- Reducir la cantidad de código en el que se trabaja al mismo tiempo: menos código significa menos carga.
- Simplificar el proceso de realizar cambios incrementales en la aplicación.
Reducción de plazos de desarrollo
Volvamos a los días en que la metodología waterfall era el estándar del proceso de desarrollo, y los plazos de seis meses a dos años para desarrollar o actualizar una aplicación eran la práctica común. Por lo general, los ingenieros leían primero documentos relevantes, como el documento de requisitos del producto (PRD), el documento de referencia del sistema (SRD), el plan de arquitectura y comenzaban a unir todas estas cosas en un solo modelo cognitivo según el cual escribían el código. A medida que cambiaban los requisitos y, en consecuencia, la arquitectura, se requería un esfuerzo considerable para informar a todo el equipo sobre las actualizaciones del modelo cognitivo. Tal enfoque, en el peor de los casos, podía simplemente paralizar el trabajo.
El mayor cambio en el proceso de desarrollo de aplicaciones fue la implementación de la metodología ágil. Una de las características principales de la metodología agile es el desarrollo iterativo. A su vez, esto conduce a una reducción de la carga cognitiva sobre los ingenieros. En lugar de exigir al equipo de desarrolladores la implementación de la aplicación en un largo ciclo, agile el enfoque permite centrarse en pequeños volúmenes de código que pueden probarse y desplegarse rápidamente, al mismo tiempo que se obtiene retroalimentación. La carga cognitiva de la aplicación se ha desplazado de plazos de seis meses a dos años con una gran cantidad de especificaciones a una adición o cambio de función de dos semanas, orientado a una comprensión más difusa de una gran aplicación.
El cambio de enfoque de aplicaciones masivas a funciones pequeñas y específicas que pueden completarse en un sprint de dos semanas, con una mirada hacia adelante que no excede una función del próximo sprint, es un cambio significativo. Esto ha permitido aumentar la productividad del desarrollo mientras se reduce la carga cognitiva, que varía constantemente.
En la metodología agile se asume que la aplicación final será una versión algo modificada del concepto original, por lo que el punto final del desarrollo es necesariamente ambiguo. Solo se pueden considerar claras y precisas las entregas de cada sprint en particular.
Las bases de código pequeñas
El siguiente paso en la reducción de la carga cognitiva es disminuir la base de código. Por lo 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 la organización de los archivos, las conexiones y dependencias entre el código y los archivos pueden ser evidentes o, por el contrario, confusas. Incluso la depuración de la ejecución del código puede presentar problemas, dependiendo de las bibliotecas utilizadas y de qué tan bien las herramientas de depuración separen las bibliotecas/packs/módulos del código del usuario.
Construir un modelo mental funcional del código de la aplicación puede llevar un tiempo considerable y, nuevamente, imponer una gran carga cognitiva al desarrollador. Esto es especialmente cierto para las bases de código monolíticas, donde hay una gran cantidad de código y la interacción entre los componentes funcionales no está claramente definida, y la separación de los objetos de atención a menudo se difumina, ya que no se respetan las fronteras funcionales.
Una de las formas efectivas de reducir la carga cognitiva sobre los ingenieros es pasar a una arquitectura de microservicios. En el enfoque de microservicios, cada servicio se centra en un conjunto de funciones; el significado del servicio generalmente está definido y es claro. Los límites del servicio también son claros; recuerde que la comunicación con el servicio se realiza a través de API, por lo que los datos generados por un servicio pueden ser fácilmente transferidos a otro.
La interacción con otros servicios suele estar limitada a algunos servicios de usuario y a algunos servicios del proveedor, que utilizan llamadas API simples y limpias, por ejemplo, a través de REST. Esto significa que la carga cognitiva para el ingeniero se reduce significativamente. La tarea más complicada sigue siendo entender el modelo de interacción de los servicios y cómo se producen cosas como las transacciones en varios servicios. En definitiva, el uso de microservicios reduce la carga cognitiva, disminuyendo la cantidad de código, delimitando claramente las fronteras del servicio y asegurando una comprensión de las relaciones entre usuarios y proveedores.
Pequeños cambios incrementales
El último elemento del principio pequeñeces – es la gestión de cambios. Una tentación particular para los desarrolladores es mirar el código base (incluso, tal vez, su propio código más antiguo) y afirmar: “Esto es una porquería, necesitamos reescribirlo todo.” A veces esa es la decisión correcta, y a veces no. Impone al equipo de desarrolladores la carga de un cambio global en el modelo, lo que a su vez conduce a una gran carga cognitiva. Es mejor que los ingenieros se concentren en los cambios que pueden realizar durante el sprint, para luego implementar las funcionalidades necesarias a su debido tiempo, aunque sea de manera gradual. El producto final debe parecerse a un plan preestablecido, pero con algunos cambios y pruebas para satisfacer las necesidades del cliente.
Al reescribir grandes partes de código, a veces resulta imposible realizar cambios rápidamente, ya que entran en juego otras dependencias del sistema. Para controlar el flujo de cambios, se puede utilizar la ocultación de funcionalidades (feature hiding). En principio, esto significa que la funcionalidad está en producción, pero no es accesible a través de ajustes de variables de entorno (env-var) o algún otro mecanismo de configuración. Si el código ha pasado por todos los procesos de control de calidad, puede estar en producción en un estado oculto. Sin embargo, esta estrategia solo funciona si la función eventualmente se habilita. De lo contrario, solo saturará el código y añadirá carga cognitiva que el desarrollador deberá manejar para trabajar de manera productiva. La gestión de cambios y los cambios incrementales ayudan a mantener la carga cognitiva de los desarrolladores en un nivel manejable.
Los ingenieros enfrentan muchas dificultades incluso al implementar funcionalidades adicionales simples. Desde la perspectiva de la dirección, es razonable reducir la carga innecesaria sobre el equipo para que puedan concentrarse en los elementos clave de la funcionalidad. Hay tres cosas que puedes hacer para ayudar a tu equipo de desarrolladores:
- Utilizar metodologías
agile, para limitar los plazos en los que el equipo debe centrarse en las funciones clave. - Implementar tu aplicación como varios microservicios. Esto limitará la cantidad de funcionalidades implementadas y reforzará los límites que mantienen la carga cognitiva durante el trabajo.
- Prefiere cambios incrementales en lugar de grandes y pesados, modificando pequeñas secciones de código. Aplica la ocultación de funciones para implementar cambios, incluso si no serán visibles inmediatamente después de ser añadidos.
Si aplicas el principio de simplicidad en tu trabajo, tu equipo será mucho más feliz, se enfocará mejor en la implementación de las funciones necesarias y será más probable que realice cambios de calidad más rápidamente. Sin embargo, esto no significa que el trabajo no pueda complicarse; a veces, por el contrario, la implementación de nuevas funcionalidades requiere modificaciones en varios servicios, y este proceso puede ser más complicado que en una arquitectura monolítica. En cualquier caso, las ventajas de aplicar el enfoque de simplicidad valen la pena.
Fin de la primera parte.
Pronto publicaremos la segunda parte de la traducción, pero por ahora esperamos sus comentarios y los invitamos a , que se llevará a cabo hoy a las 20:00.
Fuente: habr.com
