Estoy pensando en diseñar una nueva solución que sea muy modular por naturaleza y me gustaría crear una estructura que soporte ese diseño para permitir una fácil expansión futura, una clara separación de preocupaciones, licencias por módulo, etc. que se encuentran en la web sobre aplicaciones modulares o compuestas están centradas en UI, enfocadas en Silverlight, WPF, etc. En mi caso, estoy desarrollando una aplicación de servicio WCF que será consumida por otros desarrolladores que trabajan en varios proyectos de UI.
Antecedentes
El objetivo de mi proyecto es crear una fuente centralizada de lógica comercial / de dominio para admitir varias de nuestras aplicaciones comerciales que actualmente duplican procesos, reglas, etc. Y aunque no se lograrán todos los beneficios de la modularidad, me gustaría aprovechar oportunidad de establecer un marco que aproveche las partes que podemos aprovechar.
Comencé el diseño mirando la API expuesta por la aplicación de servicio. Está claro que los servicios se pueden segregar a lo largo de las líneas modulares que estaba considerando. Por ejemplo, tendré servicios de FinanceService, InventoryService, PersonnelService, etc. que agrupan mis operaciones de servicio para proporcionar una alta cohesión en la API y mantener el acoplamiento bajo para que los clientes solo tengan que consumir los servicios que sean pertinentes para su aplicación.
Para mí tiene sentido que luego pueda tener módulos separados para cada uno de estos servicios, como MyApp.Finance, MyApp.Inventory, My.Personnel, etc. Las preocupaciones transversales y los tipos compartidos estarían en el ensamblado compartido MyApp. Desde aquí me ato un poco.
(Oh, debo mencionar que usaré un contenedor IoC para la inyección de dependencia para mantener la aplicación acoplada libremente. ¡No mencionaré cuál porque no quiero abrir la caja de Pandora!)
En MyApp.ServiceHost, crearé un archivo de host de servicio (.svc) correspondiente a cada módulo, por ejemplo, FinanceService.svc. El host del servicio necesita el nombre del servicio que corresponde a la información en el archivo de configuración que contiene la interfaz que define el contrato de servicio. La configuración de IoC se usa para mapear la implementación concreta de la interfaz a usar.
1. ¿Debería la capa de servicio implementar la API y delegar en los módulos o deberían ser autónomos (en el sentido de que contienen todo lo relacionado con ese módulo, incluida la implementación del servicio)?
Una forma de abordar el problema es tener un "módulo" MyApp.Services que contenga la implementación de los contratos de servicio. Cada clase de servicio simplemente delega a otra clase en el módulo apropiado que contiene la lógica de dominio para la operación. Por ejemplo, la clase WCF FinanceService en MyApp.Services delega a otra interfaz que se implementa en el módulo de Finanzas para llevar a cabo la operación. Esto me permitiría mantener una fachada de servicio delgada y 'conectar' la implementación a la implementación del servicio y eliminar la necesidad de que los módulos se preocupen por WCF, por ejemplo.
Por otro lado, tal vez sea preferible que cada módulo sea autónomo ya que tiene la interfaz y la implementación. El host del servicio se refiere a la interfaz del contrato de servicio que se encuentra en el módulo y el IoC también está configurado para usar la implementación adecuada del módulo. Esto significa que se puede agregar un nuevo módulo sin cambios en la capa de servicio que no sea agregar un nuevo archivo .svc e información de configuración de IoC.
Estoy pensando en el impacto si cambio de WCF estándar a una interfaz de servicio RESTful o tal vez vaya a servicios RIA o algo así. Si cada módulo contiene la implementación del contrato de servicio, entonces tengo que hacer cambios en cada módulo si cambio la tecnología o el enfoque del servicio. Pero, si la fachada es su propio módulo, entonces solo tengo que cambiar esa parte para hacer un cambio. ¿Los módulos tendrían que implementar un conjunto diferente de contratos (interfaces), posiblemente definidos en el ensamblado compartido?
2. ¿Cuál es la mejor manera de manejar el intercambio de recursos entre módulos y / o dependencias entre módulos?
Tomemos, por ejemplo, una operación de recepción. A primera vista, tiene sentido que esto entre en el módulo de Inventario, ya que recibir mercancías es una función de inventario. Sin embargo, también hay un aspecto financiero en el que necesitamos generar un Recibo y autorizar el pago.
Por un lado, esperaría usar algún tipo de eventos / mensajes de dominio para comunicar la operación. El módulo de Inventario genera un Evento de Bienes Recibidos que es manejado por el módulo Financiero para generar el Recibo e iniciar el proceso de pago. Sin embargo, esto significa que el módulo Financiero necesita saber acerca de los artículos de inventario que se recibieron. Simplemente puedo referirme a ellos por ID, pero ¿qué sucede si necesito información adicional para el Recibo, como el nombre y / o la descripción, el costo unitario, etc.? ¿Tiene sentido que cada módulo tenga su propia versión de un artículo de inventario diseñado para satisfacer las necesidades de ese módulo? En ese caso, el módulo Financiero tendría que realizar su propia búsqueda de los artículos de inventario cuando maneje el Evento GoodsReceived.
...
Utilicé este ejemplo a propósito porque he trabajado mucho con varios sistemas ERP y sé que están diseñados con este tipo de modularidad. Simplemente no sé cómo. Tampoco lo menciono explícitamente anteriormente, pero prefiero seguir los principios del diseño impulsado por dominio en la arquitectura de la solución y creo que este tipo de modularidad encaja perfectamente en esa área.
Cualquier ayuda para entender esto es muy apreciada.