Cómo compartir arquitectura e implementación sin disputas

La creación de un nuevo sistema es un proceso de múltiples etapas: elaboración del concepto y diseño, diseño de arquitectura, implementación, prueba, lanzamiento. El diseño y la implementación de la arquitectura son las etapas que más preocupan a los desarrolladores.


A la mayoría de los desarrolladores les gusta participar en la arquitectura, pensar en cómo se organizará el sistema o parte de él desde cero. Si alguien que ha pensado en la arquitectura del sistema y lo implementará, no hay problemas con la motivación: el programador recibirá satisfacción por la realización de sus ideas. Pero si uno pensaba en la arquitectura, y otro se dedicaría a la implementación, entonces este último puede tener una indignación natural: pensaron todo por mí, pero ¿puedo hacer lo que está escrito?



En este artículo se discutirá cómo evitar tales situaciones, por qué la implementación puede ser no menos interesante que la elaboración de la arquitectura y, a veces, más.


Introduccion


Se puede usar una arquitectura bien pensada como base para las tareas de desglose : la implementación de cada componente suficientemente separado se convierte en una subtarea separada.


Por ejemplo, si hay una tubería para procesar solicitudes, concebida arquitectónicamente en el estilo de tuberías y filtros , entonces las subtareas serán la implementación de pasos de procesamiento individuales (cada paso tiene su propia subtarea) y otra subtarea para conectar todos los pasos juntos.


Si bien una arquitectura bien pensada y el desglose en subtareas dan una idea general de cómo crear un sistema y le permiten evaluar los costos laborales, no son suficientes para implementar el plan. La descripción de la subtarea indicará qué debe hacer el componente, puede contener requisitos de velocidad y consumo de memoria, pero no proporcionará instrucciones completas sobre cómo hacerlo.


El hecho es que hay muchas opciones para hacer un componente que cumpla con los requisitos especificados. Mucho depende de cómo se implementará: flexibilidad de código, su extensibilidad, facilidad de soporte, etc. Nos acercamos al concepto de diseño de código .


Concepto de diseño de código


A veces, el diseño del código se llama arquitectura u organización del código, a veces incluso solo arquitectura. Me apego al término diseño de código porque lo contrasta con la arquitectura del sistema y dibuja una línea clara entre ellos. Para ser más específico, considere un ejemplo.


Digamos que estamos desarrollando el backend de un sitio que está ganando popularidad. El número de servidores ya ha excedido varias decenas, la audiencia está creciendo y decidimos que queremos recopilar análisis sobre el comportamiento del usuario en el sitio: popularidad de las páginas de visita, frecuencia de uso de las funciones según el perfil del usuario, etc.


Surgen una serie de problemas arquitectónicos y tecnológicos: dónde almacenar las métricas, cómo transferirlas a través de la red, qué hacer si la tienda de métricas no está disponible, cómo el servicio de back-end registrará las métricas, etc. La arquitectura solo necesita responder estas preguntas, determinar los componentes de la solución y establecer los requisitos para ellos.


Supongamos que hemos desarrollado una arquitectura: usaremos InfluxDB como almacenamiento, transferiremos métricas a través de la red usando UDP para telegrafiar , y para evitar la falta de disponibilidad del almacenamiento, almacenaremos las métricas en Kafka replicadas en varios servidores. Todas las métricas seguirán el camino del servicio de backend -> telegraf -> Kafka -> InfluxDB. Para escribir las métricas, el backend decidió escribir un módulo que implemente la función de transferencia de métricas en telegraf usando UDP.


El módulo para registrar métricas es un componente separado del sistema, su escritura es una subtarea separada que puede confiarse al desarrollador. Esta subtarea tiene muchas soluciones y preguntas que deben responderse: las métricas se enviarán de forma sincrónica o asincrónica; cómo se sincronizará el acceso simultáneo de varios hilos de back-end, cuáles serán las principales clases / funciones.


Estas preguntas están más allá de la descripción de la arquitectura de la solución, pero las respuestas a ellas tienen consecuencias de largo alcance. Por ejemplo, si durante el funcionamiento de una solución queda claro que la pila de tecnología no es óptima y necesita reemplazar telegraf con una solución alternativa, entonces la división incorrecta del módulo en clases no lo permitirá sin reescribir todo el módulo. Las respuestas a estas preguntas son el dominio del diseño de código .


El desarrollo del diseño del código es una etapa de diseño separada , que se encuentra entre el desarrollo de la arquitectura del sistema y la codificación. Dibujar una línea entre la arquitectura y el diseño del código le permite diseñar un sistema sin tener en cuenta todos los detalles y evaluar los costos laborales en un tiempo limitado. Por otro lado, resaltar el desarrollo del diseño de código como una etapa de implementación separada le permite aumentar la calidad de la implementación del sistema, reducir el costo de mejoras adicionales y aumentar la facilidad de soporte.


La necesidad de reflexionar sobre el diseño del código en la etapa de implementación antes de la codificación hace que la implementación sea interesante : las tareas de diseño de un diseño de código pueden ser no menos interesantes que diseñar un sistema completo a nivel de arquitectura. Esta idea fue expresada por Brooks en el mítico hombre-mes .


Por supuesto, dibujar una línea entre la arquitectura y el diseño del código puede no ser tan fácil, echemos un vistazo más de cerca a este problema.


El límite entre la arquitectura y el diseño del código.


Ideológicamente, la arquitectura y el diseño del código están en diferentes niveles de diseño: la arquitectura se piensa en la etapa inicial, cuando hay poca certeza, y pensar en el diseño del código agrega detalles. En consecuencia, se ejecutan en diferentes momentos: la arquitectura está más cerca del principio y el diseño del código durante la implementación de las subtareas.


Dibujar un límite entre estas dos etapas de diseño depende de una serie de factores, estos son los principales:


  • El grado en que el componente afecta el sistema. A veces, el dispositivo de todo el sistema puede depender significativamente del dispositivo de su componente individual. En este caso, debe diseñar el componente en la etapa de desarrollo arquitectónico y no en la etapa de implementación.
  • La presencia de una interfaz clara para el componente. Es posible aislar el diseño de un componente como una subtarea solo si está claramente definido qué debe hacer este componente y cómo interactuará con el resto del sistema.
  • Estimaciones realistas del esfuerzo para completar la subtarea. La tarea puede ser demasiado grande para poder evaluar los costos laborales con suficiente precisión. En este caso, es mejor diseñar la tarea con más detalle y dividirla en sus propias subtareas para dar una evaluación más adecuada de los costos laborales.

Hay varios casos especiales en los que puede trazar una buena línea entre el diseño arquitectónico y el diseño de código.


El componente tiene una API estricta.
Por ejemplo, en mi práctica había una tarea: implementar encima de una API de socket UNIX para capturar / liberar recursos del sistema operativo utilizados por un demonio existente. Esta tarea surgió en el marco de la arquitectura elegida para la nueva característica épica . Dentro del marco de la arquitectura, era bastante de alto nivel describir la API, y el diseño detallado se realizó más tarde, durante la implementación.


Módulo / clase con una interfaz dada
La forma más fácil de delegar el diseño de una parte de un sistema monolítico es resaltar un módulo o clase, describir su interfaz y tareas. Un módulo asignado como una subtarea separada no debe ser demasiado grande. Por ejemplo, la biblioteca del cliente para acceder a la base de datos de fragmentos es, sin duda, un módulo separado, pero la tarea de implementar esta biblioteca será difícil de evaluar por los costos laborales sin un diseño más detallado. Por otro lado, la tarea de implementar una clase demasiado pequeña será trivial. Por ejemplo, si surge la subtarea "para implementar una función que verifica la existencia de una carpeta determinada por una ruta determinada", entonces la arquitectura está claramente pensada con demasiado detalle.


Pequeño componente con requisitos fijos.
Si el componente es lo suficientemente pequeño y el problema que resuelve está estrictamente definido, entonces los costos de mano de obra para la implementación se pueden estimar con suficiente precisión, y la implementación del componente en sí dejará espacio para el diseño. Ejemplo: un proceso que se ejecuta en una corona y elimina recursivamente archivos y directorios antiguos en una ruta determinada.


Antipatrones


Hay escenarios en los que la distribución entre pensar sobre la arquitectura y la implementación no es correcta, algunos de ellos se analizan a continuación.


Todo está diseñado hasta el más mínimo detalle.
Se crearon diagramas UML detallados, se especificó la firma de cada método de cada clase, se describieron los algoritmos para implementar métodos individuales ... De acuerdo con una descripción tan detallada, puede implementar el sistema lo más rápido, realmente, porque todo está planeado para tales detalles que no hay espacio para la creatividad, tomar y hacer escrito Si el objetivo es que el desarrollador codifique lo que le dicen lo más rápido posible, entonces sí, puede hacerlo.


Sin embargo, si profundiza un poco más, quedará claro una serie de deficiencias en la organización del trabajo en este sentido. En primer lugar, para diseñar todo con esos detalles, tendrá que dedicar mucho tiempo al diseño en sí. En lo que el desarrollador generalmente piensa antes de la implementación, el arquitecto lo considerará en este esquema: todo el diseño se desplaza más cerca del comienzo del proyecto, lo que puede aumentar su duración. Después de todo, si no divide el trabajo de diseño en partes, entonces no podrá paralelizarlo. En segundo lugar, la falta de trabajo de diseño durante la implementación reducirá en gran medida la motivación de los desarrolladores: hacer exactamente lo que dicen puede ser útil para los principiantes, pero los desarrolladores experimentados se aburrirán. En tercer lugar, este enfoque generalmente puede reducir la calidad del resultado: el sistema, que no está dividido en componentes suficientemente independientes, será más difícil de mantener y expandir.


La arquitectura siempre está diseñada por un desarrollador, el resto fumar a un lado solo darse cuenta
En primer lugar, deben tenerse en cuenta varios casos en los que esto puede ser útil. En primer lugar, es un equipo en el que hay muchos principiantes y solo un programador experimentado. En este caso, los principiantes no tienen suficiente experiencia para diseñar la arquitectura para hacer el trabajo con suficiente calidad, mientras que al mismo tiempo, la implementación de una arquitectura bien pensada les ayudará a elevar su nivel. En segundo lugar, se trata de grandes proyectos en los que participan varios equipos. Luego, el diseño de la arquitectura del proyecto se divide en dos niveles: el arquitecto lo analiza en su conjunto y cada equipo: la arquitectura de los componentes dentro de su área de responsabilidad.


Pero considere un equipo formado por especialistas suficientemente experimentados. Si las tareas arquitectónicas siempre se asignarán a uno solo, por ejemplo, el desarrollador más experimentado, entonces otros desarrolladores no podrán revelar completamente sus capacidades. La arquitectura del sistema será unilateral, porque todos tienen un conjunto de técnicas que él aplica. Si diferentes desarrolladores pensaran en la arquitectura de diferentes componentes / subsistemas, esto facilitaría el intercambio de experiencias y el desarrollo de los miembros del equipo. Incluso los miembros del equipo no muy experimentados a veces deben recibir tareas arquitectónicas: esto elevará su nivel y aumentará su participación en el proyecto.


Conclusión


La presencia de la etapa de diseño en la implementación es el factor principal que hace que las tareas de implementación sean interesantes. Por supuesto, hay otros: el uso de nuevas tecnologías, tareas de investigación, pero, como regla, son mucho menos comunes. Si las tareas de implementación no requieren diseño y consisten en una codificación simple, esto afectará en gran medida la motivación de los desarrolladores y no permitirá el uso de sus habilidades.


Diseñar un diseño de código en la etapa de implementación le permite hacer rápidamente estimaciones adecuadas de los costos laborales, paralelizar el trabajo de manera más eficiente y, en general, mejorar la calidad del sistema.
La necesidad de diseñar un diseño de código durante la implementación es exactamente lo que hace que la implementación funcione interesante a los ojos de los desarrolladores.


No vale la pena cometer errores, excluyendo el trabajo de diseño de la implementación de subtareas, así como no siempre debe confiar las tareas arquitectónicas solo al desarrollador más experimentado.

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


All Articles