Estou pensando em arquitetar uma nova solução que seja muito modular por natureza e gostaria de criar uma estrutura que suporte esse design para permitir fácil expansão futura, separação clara de preocupações, licenciamento por módulo, etc. encontrados na web sobre aplicativos modulares ou compostos são centrados na interface do usuário, focados no Silverlight, WPF etc. No meu caso, estou desenvolvendo um aplicativo de serviço WCF que será consumido por outros desenvolvedores que trabalham em vários projetos de interface do usuário.
fundo
O objetivo do meu projeto é criar uma fonte centralizada de lógica de negócios / domínio para dar suporte a vários aplicativos de negócios que atualmente duplicam processos, regras etc. E embora nem todos os benefícios da modularidade sejam alcançados, eu gostaria de aproveitar o oportunidade de estabelecer uma estrutura que aproveite essas partes das quais podemos tirar proveito.
Comecei o design observando a API exposta pelo aplicativo de serviço. É claro que os serviços podem ser segregados ao longo das linhas modulares que eu estava considerando. Por exemplo, terei serviços FinanceService, InventoryService, PersonnelService etc. que agrupam minhas operações de serviço para fornecer alta coesão na API enquanto mantêm o acoplamento baixo, para que os clientes tenham apenas que consumir os serviços pertinentes ao seu aplicativo.
Faz sentido para mim que eu possa ter módulos separados para cada um desses serviços, como MyApp.Finance, MyApp.Inventory, My.Personnel e assim por diante. Preocupações transversais e tipos compartilhados estariam no assembly compartilhado MyApp. A partir daqui, fico um pouco amarrado.
(Ah, devo mencionar que usarei um contêiner de IoC para injeção de dependência para manter o aplicativo fracamente acoplado. Não vou mencionar qual, porque não quero abrir a caixa de Pandora!)
No MyApp.ServiceHost, vou criar um arquivo host de serviço (.svc) correspondente a cada módulo, FinanceService.svc, por exemplo. O host de serviço precisa do nome do serviço que corresponda às informações no arquivo de configuração que contém a interface que define o contrato de serviço. A configuração de IoC é usada para mapear a implementação concreta da interface a ser usada.
1. A camada de serviço deve implementar a API e delegar nos módulos ou os módulos devem ser independentes (na medida em que contêm tudo relacionado a esse módulo, incluindo a implementação do serviço)?
Uma maneira de abordar o problema é ter um "módulo" MyApp.Services que contém a implementação dos contratos de serviço. Cada classe de serviço simplesmente delega para outra classe no módulo apropriado que contém a lógica do domínio para a operação. Por exemplo, a classe FinanceService WCF no MyApp.Services delega para outra interface que é implementada no módulo Finanças para executar a operação. Isso me permitiria manter uma fachada de serviço fina e 'plug-in' a implementação para a implementação do serviço e eliminar a necessidade de os módulos se preocuparem com o WCF, por exemplo.
Por outro lado, talvez seja preferível ter cada módulo independente, pois ele possui a interface e a implementação. O host de serviço refere-se à interface do contrato de serviço encontrada no módulo e o IoC está configurado para usar também a implementação apropriada do módulo. Isso significa que a adição de um novo módulo pode ser feita sem alterações na camada de serviço, exceto a adição de um novo arquivo .svc e informações de configuração da IoC.
Estou pensando no impacto se eu mudar do WCF padrão para uma interface de serviço RESTful ou se for para serviços RIA ou algo assim. Se cada módulo contiver a implementação do contrato de serviço, tenho que fazer alterações em todos os módulos se alterar a tecnologia ou a abordagem do serviço. Mas, se a fachada é seu próprio módulo, então só tenho que trocar essa parte para fazer uma alteração. Os módulos teriam que implementar um conjunto diferente de contratos (interfaces), possivelmente definido no assembly compartilhado ???
2. Qual é a melhor maneira de lidar com o compartilhamento de recursos entre módulos e / ou dependências entre módulos?
Tome, por exemplo, uma operação de recebimento. À primeira vista, faz sentido que isso entre no módulo Inventário, pois receber mercadorias é uma função de inventário. No entanto, há também um aspecto financeiro, pois precisamos gerar um recibo e autorizar o pagamento.
Por um lado, eu esperaria usar algum tipo de eventos / mensagens do domínio para comunicar a operação. O módulo Inventário gera um GoodsReceivedEvent que é tratado pelo módulo Financeiro para gerar o Recebimento e iniciar o processo de pagamento. No entanto, isso significa que o módulo Financeiro precisa saber sobre os itens de estoque que foram recebidos. Posso simplesmente consultá-los por ID, mas e se eu precisar de informações adicionais para o Recibo, como nome e / ou descrição, custo unitário etc.? Faz sentido que cada módulo tenha sua própria versão de um item de inventário projetado para atender às necessidades desse módulo? Nesse caso, o módulo Financeiro precisaria executar sua própria pesquisa nos itens de estoque ao manipular o GoodsReceivedEvent.
...
Usei esse exemplo de propósito, porque trabalhei muito com vários sistemas ERP e sei que eles são projetados com esse tipo de modularidade - simplesmente não sei como. Também não o mencionei explicitamente acima, mas prefiro seguir os princípios de Design Orientado a Domínio na arquitetura da solução e acredito que esse tipo de modularidade se encaixa nessa área.
Qualquer ajuda para envolver minha cabeça nisso é muito apreciada.