Eficiencia

Los programadores experimentados pueden distinguir fácilmente una buena arquitectura de una mala, pero si se les pide que la describan en pocas palabras, es poco probable que puedan hacerlo. No existe un criterio único para una buena arquitectura ni una definición única.

Sin embargo, si lo piensa, puede escribir una serie de criterios que debe satisfacer una buena arquitectura. Una buena arquitectura es, ante todo, una arquitectura lógica que hace que el proceso de desarrollo y mantenimiento de un programa sea más simple y eficiente.

Cuando un programa tiene una buena arquitectura, siempre es bastante fácil entender cómo funciona y dónde escribir el código. Un programa bien diseñado es más fácil de cambiar, probar, depurar y desarrollar. Las personas inteligentes han formulado los siguientes criterios para una buena arquitectura:

  • Eficiencia;
  • Flexibilidad;
  • Expansibilidad;
  • escalabilidad;
  • comprobabilidad;
  • Mantenibilidad del código.

Eficiencia del sistema. El programa, por supuesto, debe resolver las tareas asignadas y realizar bien sus funciones, y en diversas condiciones. Parece que cualquier programa hace lo que debe hacer (si está escrito), pero a menudo no es así en absoluto.

Constantemente te encontrarás con programas que no hacen lo que dicen hacer.

  • Libre Office es un reemplazo completo de Microsoft Office (no realmente);
  • El navegador Edge es compatible con todos los estándares web (no realmente);
  • El banco se preocupa por la seguridad de los datos personales de sus usuarios (en realidad no).

Y aún no hemos tocado el rendimiento, la confiabilidad, las correcciones de errores oportunas o la publicación de información sobre vulnerabilidades conocidas.

Está claro que nadie es perfecto, pero el programa debe resolver sus tareas principales. Por lo tanto, sin eficiencia, en ninguna parte.

Flexibilidad

En mi opinión, lo único más importante que la eficiencia es la flexibilidad. Cualquier aplicación tiene que cambiar con el tiempo, a medida que cambian los requisitos, se agregan nuevos. Cuanto más rápido y conveniente sea realizar cambios en la funcionalidad existente, menos problemas y errores causará, más flexible será la arquitectura del sistema.

Muy a menudo, los programadores/arquitectos novatos piensan que necesitan una arquitectura ideal para las tareas actuales. No. Necesita una arquitectura ideal para las tareas que se le anunciarán dentro de un año. Usted, que ya no sabe las tareas futuras, debe saber cuáles serán.

No tiene sentido tratar de predecirlos, porque siempre habrá algo inesperado. Pero debe tener en cuenta que tales tareas aparecerán. Por lo tanto, en el proceso de desarrollo, intente evaluar lo que se está obteniendo en términos de cómo será necesario cambiarlo.

Pregúntese: "¿Qué sucede si la decisión arquitectónica actual resulta ser incorrecta?", "¿Cuánto código se cambiará?". Cambiar un fragmento del sistema no debería afectar a sus otros fragmentos.

Siempre que sea posible, las decisiones arquitectónicas no deben quedar grabadas en piedra, y las consecuencias de los errores arquitectónicos deben limitarse razonablemente. "La buena arquitectura te permite RETRASAR decisiones clave" (Bob Martin) y minimiza el "costo" de los errores.

Uno de estos enfoques es dividir la aplicación en microservicios: es fácil dividir la lógica ya existente en partes separadas. Pero el mayor problema es realizar cambios futuros en una docena de servicios a la vez para implementar una pequeña característica.

Escalabilidad

La escalabilidad es la capacidad de reducir el tiempo de desarrollo al agregar nuevas personas al proyecto. La arquitectura debe permitir que el proceso de desarrollo sea paralelo para que muchas personas puedan trabajar en el programa al mismo tiempo.

Parece que esta regla se cumple por sí sola, pero en la práctica todo es exactamente lo contrario. Incluso hay un libro súper popular, The Mythical Man-Month , que explica por qué cuando se agregan nuevas personas a un proyecto, el tiempo de desarrollo aumenta.

Expansibilidad

La extensibilidad es la capacidad de agregar nuevas características y entidades a un sistema sin romper su estructura central. En la etapa inicial, tiene sentido poner solo la funcionalidad básica y más necesaria en el sistema.

Este es el llamado principio YAGNI: no lo necesitarás , "no lo necesitarás". Al mismo tiempo, la arquitectura debería permitirle aumentar fácilmente la funcionalidad adicional según sea necesario. Y para que la introducción de los cambios más probables requiriera el menor esfuerzo.

El requisito de que la arquitectura del sistema sea flexible y extensible (es decir, capaz de cambiar y evolucionar) es tan importante que incluso se formula como un principio separado: el "Principio abierto/cerrado " . El Principio Abierto-Cerrado es el segundo de los cinco principios SOLID: las entidades de software (clases, módulos, funciones) deben estar abiertas para la extensión, pero cerradas para la modificación .

En otras palabras: debería ser posible cambiar y extender el comportamiento del sistema sin reescribir partes existentes del sistema .

Esto significa que la aplicación debe diseñarse de tal manera que se pueda cambiar su comportamiento y agregar nuevas funciones escribiendo código nuevo (extensiones), sin tener que cambiar el código existente.

En este caso, la aparición de nuevos requisitos no supondrá una modificación de la lógica existente, sino que puede implementarse principalmente a través de su expansión. Este principio es la base de la "arquitectura de complemento" (Plugin Architecture). Las técnicas mediante las cuales se puede lograr esto se discutirán más adelante.

¿Recuerdas los servlets y los filtros? ¿Por qué se necesitaban filtros, e incluso con interfaces separadas, si, de hecho, toda la misma lógica podría implementarse utilizando servlets?

Fue la invención del concepto de filtros (servlets de servicio) lo que hizo posible mover varias funciones de servicio a una capa separada. Y en el futuro, al cambiar el comportamiento de los filtros, no fue necesario cambiar los servlets.

Antes de la invención de los filtros, toda la lógica del servicio responsable de redirigir las solicitudes se encontraba en los propios servlets. Y, a menudo, un pequeño cambio en la lógica llevaría a la necesidad de revisar todos los servlets y realizar varios cambios en todos.

Testabilidad

Si es un desarrollador backend de Java, sus aplicaciones de servidor a menudo exponen un conjunto de métodos como una API REST. Y para verificar que todos sus métodos funcionen según lo previsto, deben cubrirse con pruebas.

En general, la cobertura de prueba API es un buen estilo. Le permite asegurarse de que su API realmente haga lo que se pretendía que hiciera. Y también, lo que es más importante, puede realizar cambios en la lógica del servidor y verificar fácilmente que no haya roto nada accidentalmente .

Tan pronto como comience a escribir pruebas, se dará cuenta de que la mayoría del código no se puede probar en absoluto: métodos privados, acoplamiento fuerte, clases estáticas y variables.

“¿Por qué necesitamos pruebas si el código funciona?”, preguntará el principiante.

“¿Por qué necesitamos un código que funcione si no se puede probar?”, se preguntará el profesional.

El código que es fácil de probar contendrá menos errores y será más confiable. Pero las pruebas no solo mejoran la calidad del código. Casi todos los desarrolladores finalmente llegan a la conclusión de que el requisito de "buena capacidad de prueba" también es una fuerza guía que conduce automáticamente a un buen diseño.

Aquí hay una cita del libro Arquitectura ideal: "Use el principio de "probabilidad" de una clase como una "prueba de fuego" de un buen diseño de clase. Incluso si no escribe una sola línea de código de prueba, responda esta pregunta en 90 % de los casos ayudará a entender cómo todo bien" o "mal" con su diseño".

Existe toda una metodología para el desarrollo de programas basados ​​en pruebas, que se denomina Test-Driven Development (TDD). Este es, por supuesto, el otro extremo: escribir código antes de escribir código.

Mantenibilidad del código

Como regla general, mucha gente trabaja en el programa: algunos se van, vienen otros nuevos. El tiempo medio de trabajo de un programador en una empresa de TI es de un año y medio. Entonces, si llegó a un proyecto que tiene 5 años, solo el 20% de sus colegas trabajaron en él desde el principio.

Mantener y desarrollar un programa que otros han escrito es muy difícil. Incluso si el programa ya está escrito, a menudo es necesario continuar manteniéndolo: corregir errores y hacer correcciones menores. Y a menudo esto lo tienen que hacer personas que no participaron en su redacción.

Por lo tanto, una buena arquitectura debería hacer que sea relativamente fácil y rápido para las personas nuevas entender el sistema . El proyecto debe ser:

  • Bien estructurado.
  • No contenga duplicación.
  • Tener un código bien formateado.
  • Es conveniente incluir documentación.
  • Es necesario aplicar soluciones estándar y familiares para programadores.

Puede calificar fácilmente el proyecto en el que está trabajando en un sistema de 5 puntos . Solo cuenta dos puntos por cada uno de estos requisitos . Y si obtienes 5 o más, estás de suerte.

Los programadores incluso tienen un principio de menor sorpresa : cuanto más exótico es el sistema, más difícil es para que otros lo entiendan. Por lo general, se usa en relación con la interfaz de usuario, pero también se aplica a la escritura de código.