He disfrutado de la diversidad de la arquitectura durante 20 años y quiero compartir mis pensamientos.





Al principio quería escribir un comentario sobre el artículo " Sufrí arquitecturas terribles en C # durante diez años ... ", pero me di cuenta de dos cosas:



  1. Hay demasiados pensamientos para compartir.
  2. Para tal volumen, el formato de comentario es inconveniente para escribir o para leer.
  3. He estado leyendo Habr durante mucho tiempo, a veces comento, pero nunca he escrito artículos.
  4. No soy bueno en listas numeradas.


Descargo de responsabilidad: no estoy criticando a @ pnovikov ni a su idea en general. El texto es de alta calidad (me siento como un editor experimentado), comparto algunas de mis reflexiones. Hay muchas arquitecturas, pero está bien (sí, suena como el título de una película coreana). 



Sin embargo, vayamos en orden. Primero, mi opinión sobre lo que afecta a la arquitectura, luego sobre los puntos controvertidos del artículo sobre "arreglar arquitecturas". También te diré lo que funciona bien para nosotros; tal vez sea útil para alguien.



Y, por supuesto, todo lo que se dice aquí es una opinión personal basada en mi experiencia y sesgos cognitivos.



Acerca de mi opinion



A menudo tomo decisiones arquitectónicas. Una vez grande, una vez pequeña. De vez en cuando se me ocurre la arquitectura desde cero. Bueno, como desde cero, seguro que todo se inventó antes que nosotros, pero no sabemos nada, así que tenemos que inventarlo. Y no por amor a la construcción de bicicletas (digamos, no solo por amor a ella), sino porque para algunas tareas no había una solución preparada que se adaptara a todos los parámetros.



¿Por qué creo que arquitecturas completamente diferentes tienen derecho a existir? Se podría especular que la programación es un arte, no un oficio, pero yo no lo haré. Mi opinión: una vez un arte, una vez una artesanía. No se trata de eso. Lo principal es que las tareas son diferentes. Y gente. Para aclarar, las tareas son requisitos comerciales.



Si algún día mis tareas se vuelven del mismo tipo, escribiré o pediré a alguien que escriba una red neuronal (o tal vez un script sea suficiente) que me reemplace. Y yo mismo haré algo menos sombrío. Hasta que no haya llegado mi apocalipsis personal y espero que el suyo, pensemos en cómo las tareas y otras condiciones afectan la variedad de arquitecturas. TL&DR; - variado .



Rendimiento versus escalabilidad



Esta es quizás la razón más correcta para cambiar la arquitectura. A menos, por supuesto, que sea más fácil adaptar la arquitectura antigua a los nuevos requisitos. Pero aquí es difícil contar brevemente algo útil.



Sincronización



Digamos que los términos (me aseguré dos veces que escribí con una "o") son muy ajustados. Entonces no tenemos tiempo para elegir, y mucho menos idear arquitectura: tome herramientas familiares y excave. Pero hay un matiz: a veces, los proyectos complejos se pueden realizar a tiempo solo aplicando (y, quizás, inventando) algo fundamentalmente nuevo. Alguien podría decir que invitar a un cliente a una casa de baños es una técnica antigua, pero ahora estoy hablando de arquitectura ...



Cuando el momento es cómodo, a menudo resulta ser una situación paradójica, parece que se puede pensar en algo nuevo, pero ¿por qué? Es cierto que muchos sucumben con éxito a la tentación de emprender otro proyecto más candente y reducir la situación al anterior.



En mi práctica, la sincronización rara vez conduce a revoluciones en la arquitectura, pero sucede. Y eso es genial.



Velocidad y calidad de desarrollo



Sucede que el equipo (o alguien de la gerencia) se da cuenta de que la velocidad de desarrollo se ha ralentizado o que se han producido muchos errores en la iteración. A menudo se culpa a la "arquitectura incorrecta" de esto. A veces, merecidamente. Más a menudo, como el acusado más conveniente (especialmente si el equipo no tiene a su "padre").



En principio, en algunos casos todo se reduce al factor tiempo. Y en otros, a la mantenibilidad, más sobre eso más adelante.



Mantenibilidad



Un tema ambiguo. Porque todo es muy subjetivo y depende mucho de qué. Por ejemplo, del equipo, el lenguaje de programación, los procesos en la empresa, el número de adaptaciones para diferentes clientes. Hablemos del último factor, me parece el más interesante.



Ahora ha realizado un proyecto personalizado. Con éxito, a tiempo y dentro del presupuesto, el cliente queda satisfecho con todo. Yo también tenía esto. Ahora mira lo que usó y piensa, así que aquí está, ¡una mina de oro! Ahora estamos utilizando todos estos desarrollos, crearemos rápidamente un producto B2B y ... Al principio, todo está bien. El producto se hizo, se vendió un par de veces. Contrató a más proveedores y desarrolladores ("se necesita más oro"). Los clientes están satisfechos, pagan por el soporte, se producen nuevas ventas ...



Y luego uno de los clientes dice con voz humana: "Hubiera hecho esto de una manera completamente diferente, ¿cuánto puede costar?" Bueno, piénselo: pegue algunos if'chiks con código diferente (por ejemplo, no hubo tiempo para atornillar DI), ¿qué puede pasar?



Y la primera vez, realmente no pasará nada malo. Ni siquiera aconsejaría en tal situación que vallara algo especial. La complicación prematura de la arquitectura es similar a la optimización prematura. Pero cuando sucede la segunda y tercera vez, esta es una razón para recordar cosas como DI, el patrón de "estrategia", Feature Toggle y otros similares. Y, por un tiempo, ayudará.



Y luego llega el día en que miras la configuración del proyecto (solo unos pocos cientos de opciones) para un banco de pruebas específico ... Recuerda cómo contar el número de combinaciones y piensa: ¿cómo, tu madre, se puede probar esto? Está claro que en un mundo ideal esto es simple: después de todo, cada característica está diseñada e implementada de tal manera que no afecta a la otra de ninguna manera, y si lo hace, entonces todo esto está previsto y, en general, nuestros desarrolladores nunca se han equivocado.



Por supuesto, espesé los colores: puedes resaltar algunos conjuntos de características que utilizan los clientes reales, escribir más pruebas (cómo y cuáles son un tema para otra conversación) y simplificar un poco la tarea. Pero piénselo: cada versión importante debe probarse para todos los clientes. Permítame recordarle que esto no es B2C, donde puede decir "implementar una función para el 5% de los usuarios y recopilar comentarios"; para B2B, puede comenzar a recopilar comentarios de los tribunales ...



¿Soluciones? Por ejemplo, divida el producto en módulos con un ciclo de vida separado (sin olvidar probar su interacción). Esto reducirá la complejidad del mantenimiento, aunque complicará el desarrollo. Y ahora no estoy hablando del tema fértil de los holivares “monolito vs. microservicios "- en un monolito, también puede organizar uno similar (aunque más complicado, en mi opinión).



Y, fíjate, desde un punto de vista pragmático, en cada etapa, tuvimos una buena arquitectura.



¿Y para qué sirve todo esto?



No quiero cansarlos a ustedes (ni a mí) enumerando otras razones para los cambios en la arquitectura. Acordemos ahora que las arquitecturas tienden a cambiar con el tiempo, dependiendo de muchos factores. Es decir: la arquitectura ideal que resuelve "bueno, todos los problemas" no existe.



Si aún no te he convencido de esto, mira la variedad de lenguajes de programación y marcos (pero no en la interfaz, no necesitas abrir este tema). Si alguien dice que esto es malo, sugiero que realice un experimento mental: imagine un mundo en el que haya un lenguaje de programación específico. Con una condición importante: no te gusta. Por ejemplo, porque nunca lo usó y nunca tuvo la intención de hacerlo.



Y, lo admito, hay otra buena razón: idear algo nuevo, optimizar algunos parámetros, jugar con compromisos, es muy divertido. Ahora que todos (¿verdad?) Estamos de acuerdo en que la diversidad en la arquitectura está bien ...



Discusión del artículo sobre "arreglar arquitecturas"



¿Qué pasa con IoC?



Acerca de IoC Estoy de acuerdo en que las calzas tienen un lugar en el ejército y los módulos son un bien universal. Pero aquí está el resto ...



Si, por supuesto, escuchas a algunos apologistas del "código limpio", entonces puedes codificar una montaña de servicios, cada uno de los cuales tendrá un promedio de un método y medio, y en el método, dos líneas y media. ¿Pero por qué? Honestamente, definitivamente desea seguir los principios que lo ayudarán a lidiar con problemas poco probables en un futuro lejano, pero ¿difuminar incluso la lógica simple en docenas de archivos? ¿O es suficiente que escriba un código que funcione decentemente ahora? 



Por cierto, ahora estoy trabajando en un módulo que definitivamente se usará en diferentes productos y, muy probablemente, se "sintonizará" activamente. Así que trato de no "superficializar". No vale la pena. Aunque en él uso la única implementación de interfaces con más frecuencia de lo habitual.



Entonces, si tenemos módulos y no somos "mezquinos", ¿de dónde vienen los problemas de rendimiento de IoC o las "tapices de configuraciones de IoC" sin soporte? No me he encontrado. 



Sin embargo, aclararé nuestras condiciones laborales:



  • Nuestros módulos no son los que "son proporcionados por casi cualquier marco de IoC", sino "módulos directos", que se comunican entre sí de forma remota a través de la API (a veces, por razones de rendimiento, puede ponerlos en un proceso, pero el esquema de trabajo no cambiará).

  • IoC se usa de la manera más simple posible y tan simple como sea posible: las dependencias están atrapadas en los parámetros del constructor.

  • Sí, ahora tenemos una arquitectura de microservicio, pero aquí intentamos no ser demasiado pequeños. 



Sugerencia: las interfaces se pueden guardar en el mismo archivo que la clase; es conveniente (si, por supuesto, usa un IDE normal y no un bloc de notas). Hago excepciones cuando las interfaces (o comentarios sobre ellas) crecen. Pero esto es todo gusto, por supuesto.



¿Qué pasa con ORM y por qué el acceso directo a la base de datos? 



Sí, yo mismo diré lo que está mal: muchos de ellos están demasiado lejos de SQL. Pero no todos. Por lo tanto, en lugar de “aguantar mientras O / RM elimina 3000 objetos” o proponer otro, encuentra uno que se adapte a ti.



Consejo: pruebe LINQ to DB . Está bien equilibrado, existen métodos de actualización / eliminación para varias líneas. Solo ten cuidado, adictivo. Sí, no hay funciones de EF y un concepto ligeramente diferente, pero me gustó mucho más EF.



Por cierto, es bueno que este sea un desarrollo de nuestros compatriotas. Igor Tkachev - respeto (no lo encontré en Habré).



UPD: RouRseñaló en los comentarios que hay una extensión para EF Core que permite operaciones masivas. No renunciaré a LINQ to DB de todos modos, porque es bueno .



¿Qué pasa con las pruebas de la base de datos?



Sí, serán más lentos que los datos en la memoria. ¿Es fatal? No claro que no. ¿Cómo resolver este problema? Aquí hay dos recetas que se usan mejor al mismo tiempo.



Receta número 1. Toma un desarrollador genial al que le encanta hacer todo tipo de cosas interesantes y discute con él cómo resolver este problema maravillosamente. Tengo suerte porquefuerzaresolvió el problema más rápido de lo que parecía (ni siquiera recuerdo si lo discutimos o no). ¿Cómo? Hizo (en un día, parece) una fábrica de pruebas para ORM, que reemplaza el subconjunto principal de operaciones con matrices de acceso.



Perfecto para pruebas unitarias simples. Una opción alternativa es usar SQLite o algo similar en lugar de bases de datos "grandes".

Comentario de fuerza: . -, , ORM, , SQL . -, , , , , .. . .



Receta número 2. Prefiero probar escenarios comerciales en bases de datos reales. Y si el proyecto declara la capacidad de soportar múltiples DBMS, se realizan pruebas para varios DBMS. ¿Por qué? Es simple. En la declaración "No quiero probar el servidor de la base de datos", lamentablemente, hay una sustitución de conceptos. Ya sabes, no estoy probando si unirme funciona u ordenar por.



Estoy probando mi código trabajando con DB. Y sabiendo que incluso diferentes versiones del mismo DBMS pueden producir resultados diferentes en las mismas consultas ( prueba ), quiero verificar los scripts principales en esas bases de datos con las que funcionará este código.



Por lo general, tales pruebas para mí se ven así:



  • Para un grupo de pruebas (Fixture), se genera desde cero utilizando los metadatos de la base de datos. Si es necesario, se completan los libros de referencia necesarios.

  • Cada guión agrega los datos necesarios durante el pasaje (los usuarios también lo hacen). No es así en las pruebas de rendimiento, pero esa es una historia completamente diferente ...

  • Después de cada prueba, se eliminan los datos sobrantes (excepto los libros de referencia).



Consejo: si estas pruebas se realizan objetivamente durante mucho tiempo (y no porque sea el momento de optimizar las consultas a la base de datos), cree una compilación que las ejecute con menos frecuencia (categorías de prueba o un proyecto separado para ayudar). De lo contrario, los desarrolladores no querrán ejecutar el resto por sí mismos: pruebas rápidas.



Transacción y correo electrónico



Solo agregaré a la historia "la transacción en la base de datos por alguna razón cayó y el correo electrónico desapareció". Y qué divertido será cuando la transacción espere por un servidor de correo inaccesible, avivando todo el sistema por alguna notificación que luego el usuario envía a la canasta sin leer ...



Es cierto, siempre creí que solo June en la naturaleza envía cartas en una transacción en ausencia de una revisión. En nuestro equipo para tal candelabro batieron (hasta ahora virtual).



Salir



En general, si @ pnovikov no tiene planes de conquistar el mundo con la ayuda de la única ideología verdadera de la arquitectura, no encontró ninguna otra diferencia que valga la pena mencionar. Para algunas tareas, por supuesto, los principios que expresó son adecuados. Estaré encantado de leer los siguientes artículos y comentarios, tal vez encuentre algunas ideas útiles para mí.



Difícilmente utilizaré el marco propuesto. La razón es simple: ya tenemos una arquitectura ideal ...



PD: Si desea discutir algo en los comentarios, estaré encantado de participar.



All Articles