¿Cuál es la forma más efectiva de compartir código entre aplicaciones .NET?

15

En nuestro trabajo, tenemos varias aplicaciones .net diferentes que comparten muchas funciones básicas. Creamos estas aplicaciones utilizando una arquitectura limpia de n niveles, pero llegamos a ese momento en el que nos damos cuenta de que hemos vuelto a implementar las mismas funciones varias veces. Obviamente, esto viola DRY, y nos gustaría corregir eso. Ya estamos usando Nuget con cierto éxito para el código de pegamento común (cableado de IoC, registro, configuración), pero también nos gustaría compartir nuestros datos y capas comerciales entre todas nuestras aplicaciones. La idea es que la interfaz de usuario solo se ocupe de las partes de la capa empresarial que realmente necesita.

Esto parece un problema directo al principio, pero el desarrollo continuo podría proporcionar algunas dificultades y no estamos seguros de cómo proceder. Supongamos que creamos nuestra capa empresarial única para gobernarlos a todos. Por brevedad, lo llamaré "Fundación". Portamos nuestras aplicaciones para usar la Fundación, y todo funciona muy bien. La Fundación se distribuye a capas de interfaz de usuario ligeras a través de nuget, y nos vemos bien. Pero luego comenzamos a agregar funciones a nuestras aplicaciones y nos encontramos con problemas.

Digamos que estamos trabajando en el Proyecto A y agregamos una nueva característica que requiere cambios en Foundation. Realizamos los cambios en la base (Foundation-A) y los enviamos al feed nuget como un paquete inestable. El Proyecto A obtiene el último paquete Nuget, y todo está bien. Mientras tanto, otro desarrollador está trabajando en el Proyecto B. Obtiene la última Fundación del control de código fuente, pero la toma de una rama estable, para que no tenga cambios en el Proyecto A. Él hace cambios y creó la Fundación B. Y todo esta bien. Pero luego descubrimos que la funcionalidad de implementación de Foundation-A y Foundation-B podría compartir código, por lo que las combinamos. Mientras tanto, Foundation-C está flotando por ahí con sus propios cambios. Finalmente, Foundation-B está lista para la producción, por lo que la sacamos. Pero luego necesitamos actualizar la producción A, B,

Parece que podría funcionar, pero nos preocupa trabajar con diferentes esquemas de bases de datos y mantener todo sincronizado entre las diversas ramas del repositorio de Foundation y los repositorios del Proyecto A, B y C. Parece que probablemente tomará mucho trabajo manual, lo que abre la posibilidad de errores. Me gustaría que esto sea lo más automatizado posible.

Aquí está la pila que estamos usando: C #, TFS con integración continua, Nuget. Nuestras aplicaciones son todos los diversos tipos de aplicaciones ASP.NET. Estamos dispuestos a ver diferentes SCM si eso facilitará las cosas.

Estoy buscando formas de mantener a Nuget cuerdo con nuestras diferentes ramas de código fuente. No queremos introducir accidentalmente el código de desarrollo en producción porque hacemos referencia al paquete Nuget incorrecto.

Josh
fuente
Además, si este no es un buen foro para una discusión como esta, ¿alguien puede sugerir uno mejor?
Josh

Respuestas:

9

Realizamos los cambios en la base (Foundation-A) y los enviamos al feed nuget como un paquete inestable.

Aquí es donde comienza tu problema ... No hagas eso.

Cualquier cambio en Foundation v1.0 debería ser inherentemente valioso para todos los consumidores de Foundation, de lo contrario no pertenece a Foundation. Entonces, al crear el paquete nuget, hágalo como una versión oficial y estable de Foundation (es decir, v1.1), o no lo haga en absoluto.

El Proyecto B debería construir sus mejoras de la Fundación como lo haría normalmente, pero (en una buena gestión de la fuente) debería fusionarse en los cambios troncales (v1.1) antes de empujar una Fundación estable (v1.2) para nuget.

Otros proyectos que pueden usar las mejoras de Foundation pueden actualizar sus referencias nuget cuando sea apropiado, o seguir con las versiones anteriores si es necesario.

Estoy de acuerdo con @Giedrius ; Esto me parece más un problema de control de origen / ramificación en el sentido de que si la ramificación / fusión de Foundation se maneja correctamente, los problemas de gestión de paquetes se vuelven discutibles.

Eric King
fuente
Sí, esto tiene sentido. El problema está en la aplicación práctica. A medida que realiza actualizaciones para Foundation for v1.1, desea utilizar esos cambios en el Proyecto B a medida que se desarrolla. Si la forma en que ha estado compartiendo ese código es a través de nuget, entonces sus opciones son: 1) Publicar un nuevo paquete nuget, o 2) Copiar dll manualmente. Ninguno de estos parece buenas opciones.
Josh
Algo de esto puede mitigarse al tener un conjunto de pruebas efectivo, pero todavía habrá que ir y venir a medida que agregue funciones.
Josh
@ Josh Sí, las actualizaciones de Foundation deben ser completas y verificables independientemente de cómo las vaya a usar el Proyecto B (ya que van a una biblioteca compartida), por lo que 'publicar un nuevo paquete Nuget' es la forma natural de hacerlo. No importe y use Foundation v.Next en el Proyecto B hasta que sea un paquete estable en nuget. Se necesita un poco de disciplina, pero es mucho mejor que el lío de hacerlo de otra manera.
Eric King
1
Entiendo totalmente lo que estás diciendo, pero no creo que sea muy realista. A medida que desarrolle una función, incluso si ha probado completamente toda la lógica de negocios y la capa de acceso a datos, habrá modificaciones antes de que se ponga en producción. Tal vez se dé cuenta de que necesita agregar otra propiedad a la lógica de negocios, o el propietario del producto regresa con cambios o aclaraciones. Tal vez algunos de sus supuestos simplificadores estaban equivocados. Estas son cosas que suceden todo el tiempo. Si está limitado a bloquear la liberación de su lógica base, parece muy limitada.
Josh
2
Como hemos estado haciendo esto durante unos meses, esto es básicamente lo que decidimos. Creo que estaba demasiado preocupado por tener un proceso formal. Una vez que comenzamos a trabajar en ello, las cosas terminaron realmente bien. Gracias por tu contribución.
Josh
4

Refactorice su código duplicado en funciones que sean aplicables de una manera más abstracta y colóquelas en sus propias bibliotecas o marcos. Hágalos sin apretar y sin arquitectura, y nunca debería tener ningún problema. Si necesita inspiración, estudie cómo el marco .NET abstrae conceptos usando cosas como interfaces, genéricos y patrones de software como Dispose().

Además, recuerde que no todo el código duplicado está realmente duplicado; parte de esto es código de pegamento o código que de otro modo es necesario para mantener la arquitectura, así que no te obsesiones con estar demasiado SECO.

Robert Harvey
fuente
Tal vez no estaba tan claro como podría estar en mi pregunta. Esto es sobre lo que viene después. Has hecho todo eso y ahora necesitas compartir tu código de manera efectiva entre tus diferentes proyectos. Alguien dice "solo usa nuget para eso" y suena genial hasta que entres en detalles y tengas problemas, como cómo sincronizar diferentes cambios de diferentes ramas y aplicaciones.
Josh
Bueno, estoy de acuerdo con Eric King. El código de base debe ser empujado como una versión estable, no inestable. La clave es mantener una API estable: si sabe que las firmas de sus métodos de Foundation no van a cambiar, puede enviar los métodos a Foundation de manera segura y refactorizarlos más tarde sin romper nada.
Robert Harvey
4

Reutilización de código

Ha habido varios enfoques para la reutilización de código que han encontrado favor a lo largo de los años. Cada enfoque tiene su lugar y, lo que es más importante, sus problemas , pero las formas viables de reutilizar el código en .NET son:

  1. Biblioteca Común. El código que se necesita en más de un lugar se coloca en una biblioteca común, y todas las demás partes de la base del código tienen una sola referencia a este código. La desventaja principal es que terminas con la mayoría de tu proyecto dependiendo de esta biblioteca que contiene muchas funciones no relacionadas. Esta es una mala idea desde un aspecto de garantía de calidad.

  2. Código fuente común. El código que se necesita en más de un lugar se escribe una vez y se coloca en un archivo fuente en una estructura de directorio común. Todos los proyectos que necesitan este código incluyen este archivo como uno de sus archivos fuente. Esto proporciona la reutilización del código, y las ventajas de escribir una vez, usan muchas. Sin embargo. Su desventaja es que es posible tener diferentes partes del proyecto compiladas con diferentes versiones de este código, lo que puede introducir algunos defectos sutiles que pueden ser muy difíciles de detectar e identificar mediante el aseguramiento de la calidad.

  3. Servicio. El código común se implementa como un servicio al que pueden acceder otros aspectos. Esto tiene la ventaja de que habrá un único servicio en una implementación y evita las dependencias. Sin embargo, introducirá latencia y fallas. Este tipo de enfoque funciona bien en productos distribuidos grandes donde la alta disponibilidad y la tolerancia a fallas ya se comprenden y administran.

Administrar NuGET

Aquí tienes un problema mucho más interesante. Gestión de múltiples configuraciones. Mi consejo aquí es no administrar una base de clientes diversa con diferentes versiones de código, sino con archivos de configuración. Hay al menos 3 capas de datos de configuración para administrar. Configuración básica (interna) del producto que el cliente nunca ve. Las opciones de configuración predeterminadas que su cliente puede cambiar y la capa final de opciones de configuración que su cliente ha cambiado. Al separar estas diferentes capas, podrá implementar actualizaciones sin destruir las configuraciones de sus clientes.

Michael Shaw
fuente
1

Creo que el problema no está en nuget / control de origen / ramificación, sino en lo que se desliza en el código de pegado.

Robert tiene una buena respuesta, solo para ver la imagen completa, recomiendo pensar en las dependencias que estas utilidades comunes traerán a cada proyecto:

http://ayende.com/blog/3986/let-us-burn-all-those-pesky-util-common-libraries http://blog.jordanterrell.com/post/CommonUtility-Libraries-Dead.aspx

La mejor manera de evitar el infierno que tienes es abrir el código de pegamento. De tal manera que comenzará a preocuparse, que ninguna lógica de negocios se haga pública, por lo que ninguna dependencia concreta del proyecto se deslizará en el código de pegamento, que sería lo suficientemente abstracto como para ser reutilizado por cualquier persona, incluso fuera de su empresa, y si eso pega el código será lo suficientemente bueno, también obtendrá información de la comunidad

Giedrius
fuente
No estoy hablando de administrar el código de pegamento. Ya tenemos una solución para eso y funciona bien. Estoy hablando de compartir la lógica de negocios. Por ejemplo, nuestras aplicaciones tratan con la administración de organizaciones y personas. Entonces, necesitamos crear una persona, y hay un montón de reglas de negocios asociadas con cómo se debe crear una persona. En lugar de crearlo varias veces, queremos tener un paquete que maneje todo, desde la construcción del objeto hasta la persistencia que compartimos entre los diferentes proyectos. que necesitan crear personas.
Josh
0

La solución es simple: cree un proyecto separado para él y adminístrelo como algo separado: sus propios requisitos, pruebas, convenciones, documentación, planificación, personas, etc. De esta manera, se asegura de que la calidad siga siendo alta y que se produzcan posibles cambios importantes. evaluado primero antes de que creen un problema.

O incluso mejor: hágalo "código abierto" dentro de su organización. Por lo tanto, cualquiera puede cambiar el código, pero solo unas pocas personas seleccionadas tendrán derechos de confirmación completos. Y esas personas serán responsables de garantizar la calidad y las características correctas.

Eufórico
fuente