2012-02-07 11 views
23

He recibido el visto bueno para comenzar a sentar las bases de una nueva arquitectura para nuestra base de códigos en mi empresa. El ímpetu para esta iniciativa es el hecho de que:¿Cómo separar capas en una arquitectura de capas estrictas y promover la modularidad sin causar redundancia innecesaria?

  • Nuestra base de código tiene más de diez años y finalmente se rompe en las costuras cuando tratamos de escalar.
  • Las "capas" superiores, si quieres llamarlas así, son un desastre de clásico ASP y .NET.
  • Nuestra base de datos está llena de un montón de procesos almacenados impíos que contienen miles de líneas de lógica de negocio y validación.
  • Los desarrolladores anteriores crearon soluciones "inteligentes" que son no extensibles, no reutilizables, y exhiben anti-patrones muy obvios; estos deben estar en desuso en poco tiempo.

he estado haciendo referencia a la MS Patterns and Practices Architecture Guide muy fuertemente, ya que trabajo hacia un diseño inicial, pero todavía tengo algunas preguntas pendientes antes de comprometerse a nada. Antes de entrar en las preguntas, esto es lo que tengo hasta ahora para la arquitectura:

(de alto nivel)

High-level

(capas de negocio y datos de profundidad)

Business and Data layers in depth

Los diagramas muestran básicamente cómo pretendo dividir cada capa en múltiples conjuntos. Por lo tanto, en esta arquitectura candidata, tendríamos once ensamblajes, sin incluir las capas superiores.

Aquí está el desglose, con una descripción de cada conjunto:

  • Company.Project.Common.OperationalManagement: Contiene componentes que implementan políticas de gestión de excepciones, la tala, los contadores de rendimiento, configuración y localización.
  • Company.Project.Common.Security: contiene componentes que realizan autenticación, autorización y validación.
  • Company.Project.Common.Communication: contiene componentes que se pueden usar para comunicarse con otros servicios y aplicaciones (básicamente un grupo de clientes WCF reutilizables).
  • Company.Project.Business.Interfaces: Contiene las interfaces y las clases abstractas que se usan para interactuar con la capa empresarial desde capas de alto nivel.
  • Company.Project.Business.Workflows: Contiene componentes y lógica relacionada con la creación y el mantenimiento de flujos de trabajo de negocios.
  • Company.Project.Business.Components: Contiene componentes que encapsulan las reglas comerciales y la validación.
  • Company.Project.Business.Entities: Contiene objetos de datos que son representativos de entidades comerciales de alto nivel. Algunos de estos pueden ser únicos, algunos pueden ser compuestos formados a partir de entidades de datos más granulares de la capa de datos.
  • Company.Project.Data.Interfaces: Contiene las interfaces y clases abstractas que se utilizan para interactuar con la capa de acceso a datos en un estilo de repositorio.
  • Company.Project.Data.ServiceGateways: Contiene clientes de servicio y componentes que se utilizan para llamar y recuperar datos de sistemas externos.
  • Company.Project.Data.Components: Contiene los componentes que se utilizan para comunicarse con una base de datos.
  • Company.Project.Data.Entities: Contiene entidades mucho más granulares que representan datos comerciales a un nivel bajo, adecuado para persistir en una base de datos u otra fuente de datos de forma transaccional.

Mi intención es que este sea un diseño de capas estrictas (una capa solo puede comunicarse con la capa directamente debajo) y la rotura modular de las capas debe promover una alta cohesión y un acoplamiento flexible. Pero todavía tengo algunas preocupaciones. Aquí están mis preguntas, que creo que son lo suficientemente objetivo de que sean adecuados aquí en SO ...

  1. son mis convenciones de nomenclatura para cada módulo y su respectiva asamblea siguientes convenciones estándar, o hay una manera diferente que debe estar yendo sobre esto?
  2. ¿Es beneficioso separar las capas comerciales y de datos en múltiples conjuntos?
  3. ¿Es beneficioso tener las interfaces y clases abstractas para cada capa en sus propios ensamblajes?
  4. MÁS IMPORTANTE - ¿Es beneficioso contar con un ensamblaje de "Entidades" tanto para el negocio como para las capas de datos? Mi preocupación aquí es que si incluye las clases que generará LINQ to SQL dentro de los componentes de acceso a datos, entonces una entidad determinada se representará en tres lugares diferentes en la base de código. Obviamente, herramientas como AutoMapper pueden ayudar, pero todavía no estoy al 100%. La razón por la que los he separado así es A - Aplicar una arquitectura de capas estrictas y B - Promover un acoplamiento más flexible entre capas y minimizar la rotura cuando ocurren cambios en el dominio comercial detrás de cada entidad. Sin embargo, me gustaría obtener orientación de personas que están mucho más experimentadas en arquitectura que yo.

Si pudiera responder a mis preguntas o señalarme en la dirección correcta estaría muy agradecido. Gracias.


EDIT: quería incluir algunos detalles adicionales que parecen ser más pertinente después de leer la respuesta de babuino. Las tablas de la base de datos también son un desastre profano y son cuasi relacionales, en el mejor de los casos. Sin embargo, no estoy autorizado a realizar una nueva arquitectura de la base de datos y a hacer una limpieza de datos: lo más profundo que puedo llegar es crear nuevos procs almacenados y comenzar a desaprobar los antiguos. Es por eso que me inclino por tener entidades definidas explícitamente en la capa de datos, para tratar de usar las clases generadas por LINQ a SQL (o cualquier otro ORM) ya que las entidades de datos simplemente no parecen factibles.

+1

Actualización a partir del 2012-03-05: decidimos ir con una arquitectura de capas estrictas, como estaba previsto. Sin embargo, al final llegué a la conclusión de que tener las interfaces y las clases abstractas en su propio ensamblado era una complejidad añadida sin ningún beneficio real. Todavía estoy yendo con el enfoque de tener entidades comerciales separadas, que son distintas de las entidades en la capa de datos. Esto ha demostrado ser invaluable, ya que evita que los detalles abominables del esquema DB se filtren más allá de la capa empresarial. En otras palabras, ayuda dibujar una línea en la arena y se agrega protección. –

Respuesta

8

De hecho, me acaba de comenzar la misma cosa, así que espero que esto ayudará o al menos generar más comentarios e incluso ayuda para mí :)

1. Son mis convenciones de nomenclatura para cada módulo y su respectivo ensamblaje ¿siguiendo las convenciones estándar, o hay una manera diferente en que debería hacerlo?

De acuerdo con MSDN Names of Namespaces, esto parece estar bien.Ponen a cabo como:

<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
For example, Microsoft.WindowsMobile.DirectX.

2.Is que es beneficioso para romper las capas de negocio y de datos en múltiples montajes?

Definitivamente creo que es beneficioso separar las capas de negocio y de datos en múltiples conjuntos. Sin embargo, en mi solución, he creado solo dos conjuntos (DataLayer y BusinessLayer). Los otros detalles como Interfaces, Workflows, etc. Crearía directorios para debajo de cada ensamblaje. No creo que deba dividirlos en ese nivel.

3. ¿Es beneficioso tener las interfaces y clases abstractas para cada capa en sus propios ensamblajes?

El tipo de junto con los comentarios anteriores.

4. ¿Es beneficioso contar con un conjunto de "Entidades" tanto para el negocio como para las capas de datos?

Sí. Diría que sus entidades de datos podrían no corresponder directamente con cuál será su modelo de negocio. Al almacenar los datos en una base de datos u otro medio, es posible que deba cambiar las cosas para que funcione bien. Las entidades que expone a su capa de servicio deberían ser utilizables para la UI. Las entidades que utiliza para usted Capa de acceso a datos deben ser utilizables para su medio de almacenamiento. AutoMapper es definitivamente su amigo y puede ayudarlo con el mapeo como lo mencionó. Así que esta es la forma en que se perfila:

Service Layer Details http://i.msdn.microsoft.com/dynimg/IC350997.png

+0

Te doy la marca porque tu respuesta para el # 4 fue exactamente la confirmación que estaba buscando. Creo que vale la pena tener la redundancia en mi caso particular porque las entidades que generará el ORM reflejarán el horror del esquema de la base de datos, que preferiría dejar encapsulado dentro de los componentes concretos de acceso a los datos. Esto significa que sería necesario un conjunto adicional de entidades de datos para dar cierta cordura a la capa de acceso a los datos. ¿Estás de acuerdo? Por cierto, todavía no estoy contigo en el n. ° 3: nuestras pruebas unitarias y las implementaciones WCF mostrarán su valor IMO. –

+2

@RepoMan - Sí, estoy de acuerdo. Para el n. ° 3, no creo que separarlos en asambleas te vaya a comprar nada. Es de suponer que están relacionados ya que pertenecen a Company.Project, por lo que son específicos del proyecto y no lo suficientemente genéricos como para ser reutilizados en otros proyectos. Id mantenerlos en el mismo conjunto y utilizar su Company.Project.X.Test para la prueba unitaria. – SwDevMan81

+0

Resulta que tenía razón sobre el # 3 después de todo. Mira el comentario que agregué a mi publicación original. –

14

estoy de acuerdo con esta arquitectura en capas estándar a favor de una onion architecture.

enter image description here

De acuerdo con esto, puedo darle una oportunidad a sus preguntas:

1. Son mis convenciones de nomenclatura para cada módulo y su respectiva asamblea siguientes convenciones estándar, o hay una diferente forma I debería estar pasando esto?

Sí, yo estaría de acuerdo en que no es una mala convención, y más o menos estándar.

2. ¿Es beneficioso dividir las capas comerciales y de datos en múltiples conjuntos?

Sí, pero prefiero tener un ensamblado llamado Dominio (normalmente Núcleo Central) y otro llamado Datos (Núcleo.Datos). El ensamblado del dominio contiene todas las entidades (según el diseño impulsado por el dominio) junto con las interfaces del repositorio, los servicios, las fábricas, etc. El ensamblaje de datos hace referencia al Dominio e implementa repositorios concretos con un ORM.

3. ¿Es beneficioso tener las interfaces y clases abstractas para cada capa en sus propios ensamblajes?

Dependiendo de varios motivos. En la respuesta a la pregunta anterior, mencioné la separación de interfaces para repositorios en el Dominio y repositorios concretos en el ensamblado de Datos. Esto le proporciona un dominio limpio sin ninguna "contaminación" de ningún dato específico ni de ninguna otra tecnología. En general, baso mi código pensando en un nivel orientado a TDD, extrayendo todas las dependencias de las clases haciéndolas más utilizables, siguiendo el principio de SRP y pensando qué puede salir mal cuando otras personas en el equipo usan la arquitectura :) Por ejemplo, Una gran ventaja de la separación en ensambles es que usted controla sus referencias y declara claramente "¡sin código de acceso a datos en el dominio!".

4. ¿Es beneficioso contar con un conjunto de "Entidades" tanto para el negocio como para las capas de datos?

No estoy de acuerdo, y digo que no. Debe tener sus entidades centrales y asignarlas a la base de datos a través de un ORM. Si tiene una lógica de presentación compleja, puede tener algo así como objetos ViewModel, que son básicamente entidades simplificadas solo con datos adecuados para la representación en la interfaz de usuario. Si tiene algo así como una red intermedia, también puede tener objetos DTO especiales para minimizar las llamadas de red. Pero, creo que tener datos y entidades comerciales separadas simplemente complica el asunto.

Una cosa más que añadir aquí, si está comenzando una nueva arquitectura, y está hablando de una aplicación que ya existe desde hace 10 años, debería considerar mejores herramientas ORM de LINQ-a-SQL, ya sea Entity Framework o NHibernate (en mi opinión, opto por NHibernate).

También agregaría que responder a tantas preguntas como las hay en la arquitectura de una aplicación es difícil, así que intente publicar sus preguntas por separado y más específicamente. Para cada una de las partes de la arquitectura (interfaz de usuario, capas de servicio, dominio, seguridad y otras cuestiones cruzadas), podría tener discusiones de varias páginas. Además, recuerde no sobre-arquitecturar sus soluciones, ¡y con eso complicar las cosas aún más de las necesarias!

+0

No estoy seguro de que esté demasiado interesado en la arquitectura de cebolla, pero +1 para sus otras respuestas. –

+0

En mi opinión, lo mejor de la arquitectura de cebolla es tener su regla de dominio, y hasta ahora he encontrado que es la mejor decisión de arquitectura. Las preocupaciones sobre datos y datos solo deberían ser un problema lateral para una aplicación. –

+4

+1 para la arquitectura de cebolla. –

2

1) La denominación es absolutamente buena, tal como lo indica SwDevMan81.

2) Absolutamente, si WCF se desactualiza en unos años, solo tendrá que cambiar su DAL.

3) La regla de oro es hacerse esta simple pregunta: "¿Puedo pensar en un caso en el que haga un uso inteligente de esto?".
Al hablar sobre sus contratos de WCF, sí, definitivamente colóquelos en un ensamble por separado: es la clave para un buen diseño de WCF (entraré en más detalles).
Cuando hablamos de una interfaz definida en AssemblyA, y se implementa en AssemblyB, las propiedades/métodos descritos en esas interfaces se usan en AssemblyC, está bien siempre que cada clase definida en AssemblyB se use en C a través de una interfaz. De lo contrario, tendrás que hacer referencia tanto a A, como a B: pierdes.

4) La única razón por la que se me ocurre mover 3 veces el mismo objeto, es un mal diseño: las relaciones con la base de datos estaban mal elaboradas, y por eso hay que ajustar los objetos que tienen algo que puede trabajar con.
Si vuelve a hacer la arquitectura, puede tener otro ensamblaje, utilizado en casi todos los proyectos, llamado "Entidades" que contiene los objetos de datos. Por cada proyecto quise decir WCF también.

En una nota lateral, agregaría que el servicio WCF se debe dividir en 3 ensamblajes: los ServiceContracts, el Servicio mismo y las Entidades de las que hablamos. Tuve un buen video sobre este último punto, pero está en el trabajo, lo vincularé mañana!

HTH,

bab.

EDITAR:here es el video.

+0

"La única razón por la que se me ocurre mover tres veces el mismo objeto, es un diseño incorrecto: las relaciones con la base de datos estaban mal elaboradas, y por eso hay que ajustar los objetos que salen para tener algo con lo que se puede trabajar. " - ¡BINGO! Voy a editar mi pregunta para reflejar esto porque probablemente debería haberlo dicho desde el principio. –

+0

Para el punto n. ° 3, dado que mis implementaciones concretas se encuentran en el conjunto B, tengo que hacer referencia a ambos ensamblados de todos modos ¿no? En cuanto a su nota lateral, ¿está diciendo que debería tomar las interfaces de la capa empresarial, decorarlas como [ServiceContract] y usarlas directamente en mis servicios de WCF? –

+1

Tal vez debería haber elaborado para el punto 3, pero si usa una Inyección de Dependencia como MEF, los contratos son suficientes. ¿Necesitas tanta abstracción? –

Cuestiones relacionadas