c# - quitar - ¿Por qué las referencias circulares en Visual Studio son una mala práctica?
referencia circular json c# (8)
Además de los problemas de construcción, las referencias circulares siempre indican un defecto de diseño. En .NET, una relación circular hace que dos ensamblajes sean efectivamente un ensamblaje. Si ninguno puede vivir solo sin el otro, construirlos por separado es solo un ejercicio; no cambia el hecho de que en conjunto representan una asamblea monolítica.
Me he dado cuenta de esto mucho con los ensambles de utilidades. Debe ser un antipatrón.
¿Por qué las referencias circulares en Visual Studio son una mala práctica?
Primero, describiré un ejemplo de cómo puede suceder esto usando C # en Visual Studio, ya que VS generalmente le informará si tiene una referencia circular y la evitará.
En primer lugar, se crea una clase de Utilities basándose únicamente en el código que le otorgan Visual Studio y .Net. Luego, se crea una clase de correo electrónico que depende de las Utilidades . En lugar de agregar ambos proyectos a una única solución, se crea una nueva solución y se agrega una referencia a Utilities.dll . Luego, un tiempo después, alguien decide que quiere que la clase Utilidades envíe un correo electrónico y agrega una referencia a Email.dll . Visual Studio está feliz de poder hacer esto, pero ahora la fuente no se compilará tal cual sin uno de los binarios.
En mi lugar de trabajo, es un procedimiento estándar copiar y pegar binarios al hacer el desarrollo y luego construir solo los proyectos en los que está trabajando. Esto ha llevado a al menos una referencia circular en la base de código que ha pasado desapercibida durante más de 3 años.
Esto me parece una práctica muy mala porque no hay forma de construir ningún proyecto desde el origen sin tener primero los archivos DLL. Ese argumento es un poco plano para las personas "prácticas" con las que trabajo, ya que parece muy improbable que perdamos todas las copias de nuestros binarios simultáneamente. Los binarios no se almacenan en el control de versiones en ningún punto, lo que solo me preocupa más.
Esto parece una situación que debe evitarse, pero no una situación que represente una amenaza apreciable. ¿Las referencias circulares entre proyectos son realmente un gran problema o lo estoy desproporcionando?
Este es uno de los síntomas de la sobremodulación.
Una vez trabajé en una empresa con aproximadamente veinte desarrolladores y más de sesenta proyectos activos diferentes en el repositorio de SVN. Cada proyecto tenía su propio script de compilación y producía un archivo JAR que era una dependencia de al menos media docena de otros proyectos. Administrar todas esas dependencias era tan complicado que perdimos un montón de tiempo intentando (sin éxito, podría agregar) establecer proyectos maven para buscar automáticamente todas las bibliotecas correctas (y las versiones correctas) para todos esos pequeños microproyectos.
Lo gracioso (para mí) fue que realmente era solo un proyecto, y ni siquiera era algo que distribuimos al mundo exterior. Era una aplicación alojada, con un front-end web, ejecutándose en un único clúster de servidores.
Sheesh.
Otro efecto secundario de la arquitectura fue que los mismos tipos de funcionalidad se duplicaron una y otra vez (no siempre con los mismos algoritmos, o resultados, para el caso) en varios proyectos diferentes. Creo que parte del motivo se debe a que las personas no querían introducir una nueva dependencia en un subproyecto completo solo para acceder a algunas de sus clases. Pero creo que otra razón es que las personas simplemente no sabían qué código existía y, en lugar de tomarse la molestia de encontrar el código que querían volver a utilizar, lo reescribían en su propio proyecto.
Por supuesto, la modularidad generalmente es algo bueno.
Pero como todas las cosas buenas, se puede llevar a extremos ridículos.
Mi consejo es encontrar esas dependencias circulares y fusionar los proyectos en trozos más grandes, ya que el desglose del proyecto actual probablemente represente una modularidad falsa. Es mejor dividir su gran proyecto en unos pocos módulos bien separados que tener un billón de pseudo-módulos creando límites artificiales entre las clases lógicamente acopladas.
Hm, creo que en términos de la pregunta OP, sobre la construcción de proyectos desde cero, se trata de malas prácticas, debido a:
- Incapacidad para construir desde la fuente / cero - ¿Qué ocurre si mantengo varias versiones de código? Entre cada versión, se han realizado algunos cambios en cada una de las libs. La única manera en que puedo mantener estas versiones simultáneas de forma segura es almacenar ahora los binarios compilados en mi control de versiones. Esto también significa que las comparaciones entre cada versión de la biblioteca es mucho más difícil. (Necesito averiguar qué versión se está usando, luego mirar el código fuente real de la lib, en lugar de solo una diferencia directa en la fuente misma.
- Posiblemente sea más difícil enviar parches a los clientes que tienen versiones parcheadas incrementalmente. ¿Dónde y qué parchear?
La pregunta que plantearía a tus compañeros de trabajo es:
De acuerdo, es muy poco probable que perdamos todos nuestros binarios al mismo tiempo. Pero dime, ¿cuál es el beneficio de este enfoque?
Si vienen con algo diferente a "Siempre lo hemos hecho de esta manera", me gustaría escucharlo. Y, como todos saben "siempre lo hemos hecho de esta manera" NO es una buena razón y no deberían defenderla.
Sí, es una mala práctica precisamente por la razón que ha indicado, no puede reconstruir desde la fuente.
las dependencias circulares son malas porque:
- Proyecto Un proyecto de referencias B
- cuando el proyecto B cambia, el proyecto A necesita ser reconstruido
- ahora si el proyecto B también hace referencia al proyecto A
- luego, cuando uno de ellos cambia, el otro necesita ser reconstruido
- que hace que el otro necesite ser reconstruido
- que hace que el otro necesite ser reconstruido
- etc.
esto es potencialmente un bucle infinito en el proceso de construcción
Sí, es un gran problema, porque conduce a composiciones de componentes inmanejables, y muy probablemente a algún tipo de errores de compilación y muy probablemente a algunos errores de implementación, en algún momento del ciclo de vida del proyecto.
Visual Studio 2008 evita explícitamente referencias circulares entre proyectos (no binarios) en soluciones. Como ha indicado, ese no es el caso de los binarios. Creo que es porque VS2008 espera que las referencias binarias se administren de forma independiente y espera que usted construya esos proyectos de forma independiente. En términos generales, eso significa que todas las referencias binarias deben verse como componentes de terceros que representan una relación única de ida (entre su código y el binario).
Además, MSBuild le permite usar el archivo SLN para compilar todo, si todos sus proyectos usan VB o C #. Esto permite la creación de un archivo de súper solución, que es ideal para un proceso de compilación automatizado. El problema es que para que un archivo de solución maestra funcione, todos los proyectos en el SLN deben utilizar referencias de proyectos. Por lo tanto, para aprovechar esto, Microsoft, por definición, espera que no emplee referencias circulares, ya que están explícitamente prohibidas por el IDE de Visual Studio (para referencias de proyectos).
Scott Hanselman hace referencia a un archivo de solución universal en la siguiente publicación:
Hack: Parallel MSBuilds desde el Visual Studio IDE
http://www.hanselman.com/blog/CategoryView.aspx?category=MSBuild
Si tiene problemas para convencer a sus colegas "pragmáticos" de que esta es una mala práctica, ofrezca una solución pragmática: elimine estas referencias circulares y los tiempos de construcción disminuirán ya que se evitarán muchas reconstrucciones innecesarias.