2009-03-13 12 views
5

Una complejidad muy común para los arquitectos técnicos es dividir la aplicación en ensamblados y espacios de nombres.Sugerencias de estrategia para particionar ensamblados y espacios de nombres

  • Los ensamblajes se pueden dividir según los límites de despliegue, rendimiento y seguridad.
  • Los espacios de nombres se pueden dividir según los límites lógicos de la aplicación.

También: los espacios de nombres pueden abarcar varios ensamblajes.

Tuve una mala experiencia en un proyecto una vez donde dividimos los ensamblajes según las unidades lógicas de la aplicación. ¡Esta decisión terminó con archivos de solución con 30 o 40 proyectos! El tiempo de carga del archivo de solución maestra fue de aprox. ¡¡¡5 minutos!!! Esto terminó en una gran pérdida de tiempo, pff ...

El escenario opuesto era mantener todo el código en 1 ensamblaje y partición cuando realmente se necesita.

¿Tiene más consejos o mejores prácticas sobre este tema?

Respuesta

1

Divido el código en ensamblajes separados solo cuando necesito reutilizarlo para dos aplicaciones diferentes (prácticamente). Así que empiezo con todo en un proyecto, y cuando la necesidad de reutilizar el código se vuelve obvia, creo un nuevo ensamblaje y muevo el código (a veces es obvio desde el principio, por ejemplo, cuando necesitas una aplicación web y formas de ganar haciendo lo mismo) cosa).

Re. Espacios de nombres, prefiero tenerlo bastante bien particionado dentro de un ensamblaje, por lo que está claro a dónde pertenece cada clase y para qué se debe usar.

+0

Este es también mi actual forma de trabajar. A menudo veo a los desarrolladores dividir la aplicación en 3 ensamblajes porque la mayoría de ellos piensa que una 3 capas en 3 ensamblajes es algo bueno que hacer; pero esto también se puede lograr mediante capas de espacios de nombres y mantener todo el conjunto en 1. Solo cuando la seguridad y el rendimiento son actores clave, comience a investigar cómo particionar físicamente su aplicación. –

0

Puede particionar las clases con espacios de nombres y usar carpetas si desea agrupar archivos fuente juntos para facilitar el mantenimiento. Si tiene requisitos de seguridad y ciertos ensamblajes necesitan pasar por un proceso especial como la Ofuscación, por ejemplo, puede que necesite separarlos en un proyecto separado.

La reutilización también es un factor que debe tener en cuenta al pensar si una unidad lógica necesita obtener su propio proyecto, ya que también puede necesitar este proyecto en otra solución.

0

Lo que funcionó bien para mí es la agrupación de gran nivel por tipo de código, pero más nivel macro que las unidades lógicas por las que se estaba dividiendo. Por ejemplo,

  • Motor - cualquier cosa no visual. Clases de soporte, código de infraestructura base. Todo se refiere a esto.
  • EngineUI - Se basa en Engine, y obviamente se usa para la interfaz de usuario, pero no es específico de ninguna aplicación.
  • EngineServer - Se basa en el motor, utilizado por la creación del servidor (normalmente web).
  • AppCore - Funcionalidad básica específica de la aplicación, sin interfaz de usuario.
  • AppUI - Interfaz de usuario específica de la aplicación
  • AppClient - Utiliza AppUI, AppCore, EngineUI, Engine. La aplicación del cliente real.
  • AppServer - Utiliza AppServer, EngineServer, Engine. La aplicación de servidor.

Cada proyecto tiene una jerarquía de espacios de nombres y de vez en cuando encuentro su utilidad que desembolsar una gran cantidad de código en otro conjunto, pero por lo general éstos mantener las cosas razonablemente organizado y manejable, incluso cuando hay muchos cientos de archivos involucrados. Demasiados proyectos definitivamente es algo que trato de evitar. Una ventaja de mantener estos proyectos al mínimo es que hace que sea mucho más fácil reutilizar estas bibliotecas en proyectos posteriores (como compilaciones de pruebas automatizadas).

No me preocupo demasiado por el código no utilizado que se implementa desde estas bibliotecas porque puedo usar un utility que elimina las funciones no utilizadas para la compilación final, manteniendo el tamaño del archivo al mínimo.

0

Me resulta útil organizar espacios de nombres en una jerarquía y hacer que los nombres de los ensamblajes coincidan con el espacio de subnombres al que contribuyen. Por ejemplo, un proyecto llamado Womble tendría un espacio de nombres de primer nivel Womble, y entonces no podría ser ensamblados llaman:

Womble.ClientLibrary.dll 
Womble.Controls.dll 
Womble.Util.dll 
Womble.Interop.dll 

Aquí, el espacio de nombres externo Womble abarca varios ensamblados, pero cada conjunto tiene un subespaciodenombres única que sólo puede contribuir, que se encuentra al eliminar .dll del final. Hace que sea mucho más fácil recordar lo que necesita para hacer referencia y para encontrar cosas.

En cuanto a un gran número de conjuntos, en última instancia, no es necesario que los guarde todos en una sola solución. En el desarrollo a gran escala, ayuda a dividir un gran producto en subsistemas, que a su vez pueden consistir en múltiples ensamblajes, y cada subsistema puede terminar siendo mantenido por equipos separados, y puede tener sus propios archivos de solución. Los diversos equipos "lanzan" nuevas versiones entre sí a través del control de código fuente, tratándose entre ellos como bibliotecas de terceros.

No creo que haya una manera difícil y rápida de decidir cómo dividir el software en partes iguales. Aquí hay un principio general: las cosas que cambian por diferentes razones deben separarse.

Los proyectos muy grandes pueden beneficiarse del hecho de que al colocar elementos en ensamblajes separados, puede parcharlos por separado. Puede generar una revisión para un problema en Womble.Interop.dll, y luego producir por separado un hotfix para un problema en Womble.Controls.dll, y dar ambos al mismo cliente, de modo que, en teoría, esos dos ensamblajes podrían ser completamente mantenido y respaldado por equipos separados, sin tener que coordinar sus actividades directamente.

Los ensamblajes separados también crean claridad en las dependencias entre códigos. Puede ver a un nivel muy alto (solo mirando la lista de referencias) cómo un trozo de código depende de otro y cómo puede ser reutilizado. Si pones todo en un solo conjunto, podría ser un gran desastre enredado sin un patrón sensible.

0

motivación

La razón por la que estoy publicando esta respuesta tardía es que todas las respuestas anteriores son más recomendaciones mejores prácticas en lugar consistentes.

Desde hace muchos años estoy trabajando en un proyecto .NET muy grande y solo la mejor práctica consistente que está estratégicamente bien motivada técnicamente es la propuesta por el equipo de NDepend.

En pocas palabras

recomendaciones NDepend son por lo general en línea con su experiencia de no estructurar conjuntos de acuerdo con la arquitectura.También contiene consideraciones sobre cuándo tener montajes separados y por qué. La regla de oro es la estructuración mediante el uso de conjuntos por razones físicas, use espacios de nombres por razones lógicas.

NDepend resumen las mejores prácticas:

Para montajes y proyectos

  • reducir drásticamente el número de conjuntos de su base de código.
  • Cree un ensamblaje nuevo solo cuando esté justificado por un requisito específico de separación física.
  • En un proyecto de Visual Studio, use 'referencia por ensamblado' en lugar de 'referencia por proyecto de Visual Studio'.
  • Nunca use la opción de referencia de Visual Studio 'Copy Local = True'.
  • Coloque todas las soluciones VS y los archivos Build Build .bat en un directorio $ rootDir $.
  • Compila todos los ensamblados en los directorios: $ rootDir $ \ bin \ Debug y $ rootDir $ \ bin \ Release
  • Usa el directorio $ rootDir $ \ bin para alojar conjuntos de pruebas.

Para espacios de nombres

  • utilizar el concepto de espacio de nombres para definir los límites de los componentes.
  • Un espacio de nombre contiene típicamente de una a dos docenas de tipos, y tiene un tamaño razonable que cabe en el rango de LoC de 500 a 2.000.
  • Tómese el tiempo para nivelar sus componentes de código base, sin duda es una tarea más barata de lo esperado, por lo que el retorno de la inversión será alto.
  • Comprueba continuamente que el gráfico de dependencia de los componentes dentro de un conjunto sea acíclico.
  • Si un componente es demasiado grande (> 2.000 LoC), utilice espacios de nombres para dividirlo en un conjunto más pequeño de componentes relacionados.
  • En cualquier escala, clasifique componentes entre mediadores de alto nivel, características independientes de nivel medio, base/dominios de bajo nivel.
  • Tener un conjunto "nivelado" de componentes elimina la necesidad de la mayoría de las decisiones de diseño.

lectura detallada

Partitioning code base through .NET assemblies and Visual Studio projects

Defining .NET Components with Namespaces

Cuestiones relacionadas