Sto cercando di progettare una nuova soluzione che è molto modulare per natura e vorrei creare una struttura che supporti tale progetto per consentire una facile espansione futura, una chiara separazione delle preoccupazioni, licenze per modulo, ecc. La maggior parte di ciò che ho trovato sul web su applicazioni modulari o composite sono incentrati sull'interfaccia utente, focalizzato su Silverlight, WPF, ecc. Nel mio caso, sto sviluppando un'applicazione di servizio WCF che verrà utilizzata da altri sviluppatori che lavorano su vari progetti di interfaccia utente.
sfondo
L'obiettivo del mio progetto è quello di creare una fonte centralizzata di logica aziendale / di dominio per supportare molte delle nostre applicazioni aziendali che attualmente duplicano processi, regole, ecc. E mentre non tutti i vantaggi della modularità saranno raggiunti, vorrei cogliere il opportunità di stabilire un quadro che sfrutterà quelle parti di cui possiamo trarre vantaggio.
Ho iniziato la progettazione guardando l'API esposta dall'applicazione di servizio. È chiaro che i servizi possono essere separati secondo le linee modulari che stavo prendendo in considerazione. Ad esempio, avrò servizi FinanceService, InventoryService, PersonnelService, ecc. Che raggruppano le mie operazioni di servizio per fornire un'elevata coesione nell'API mantenendo basso l'accoppiamento, in modo che i clienti debbano solo consumare i servizi pertinenti alla loro applicazione.
È logico per me poter disporre di moduli separati per ciascuno di questi servizi, come MyApp.Finance, MyApp.Inventory, My.Personnel e così via. Preoccupazioni trasversali e tipi condivisi sarebbero nell'assemblea condivisa MyApp. Da qui mi lego un po '.
(Oh, dovrei menzionare che userò un contenitore IoC per Dependency Injection per mantenere l'applicazione liberamente accoppiata. Non menzionerò quale perché non voglio aprire la confezione di Pandora!)
In MyApp.ServiceHost, creerò un file host di servizio (.svc) corrispondente a ciascun modulo, ad esempio FinanceService.svc. L'host del servizio richiede il nome del servizio che corrisponde alle informazioni nel file di configurazione che contiene l'interfaccia che definisce il contratto di servizio. La configurazione IoC viene quindi utilizzata per mappare l'implementazione concreta dell'interfaccia da utilizzare.
1. Il livello di servizio dovrebbe implementare l'API e delegare i moduli o i moduli dovrebbero essere autonomi (in quanto contengono tutto ciò che è relativo a quel modulo, inclusa l'implementazione del servizio)?
Un modo per affrontare il problema è disporre di un "modulo" MyApp.Services che contenga l'implementazione dei contratti di servizio. Ogni classe di servizio semplicemente delegare a un'altra classe nel modulo appropriato che contiene la logica di dominio per l'operazione. Ad esempio, la classe WCF FinanceService in MyApp.Services viene delegata a un'altra interfaccia implementata nel modulo Finance per eseguire l'operazione. Ciò mi consentirebbe di mantenere una facciata di servizio sottile e di "plug-in" l'implementazione per l'implementazione del servizio, eliminando ad esempio la necessità che i moduli si preoccupino della WCF.
D'altra parte, forse è preferibile avere ogni modulo autonomo in quanto ha l'interfaccia e l'implementazione. L'host del servizio fa riferimento all'interfaccia del contratto di servizio presente nel modulo e l'IoC è configurato per utilizzare l'implementazione appropriata anche dal modulo. Ciò significa che l'aggiunta di un nuovo modulo può essere eseguita senza modifiche al livello di servizio oltre all'aggiunta di un nuovo file .svc e informazioni sulla configurazione IoC.
Sto pensando all'impatto se passo da WCF standard a un'interfaccia di servizio RESTful o forse vado ai servizi RIA o qualcosa del genere. Se ogni modulo contiene l'implementazione del contratto di servizio, allora devo modificare ogni modulo se cambio la tecnologia o l'approccio del servizio. Ma se la facciata è il suo modulo, devo solo cambiare quella parte per fare un cambiamento. I moduli dovrebbero quindi implementare una diversa serie di contratti (interfacce), eventualmente definiti nell'assembly condiviso ???
2. Qual è il modo migliore per gestire la condivisione delle risorse tra i moduli e / o le dipendenze tra i moduli?
Prendi, ad esempio, un'operazione di ricezione. A prima vista ha senso che questo entri nel modulo Inventario poiché ricevere merci è una funzione di inventario. Tuttavia, c'è anche un aspetto finanziario in quanto dobbiamo generare una ricevuta e autorizzare il pagamento.
Da un lato, mi aspetterei di utilizzare un tipo di eventi di dominio / messaggistica per comunicare l'operazione. Il modulo Inventory genera un GoodsReceivedEvent che viene gestito dal modulo finanziario per generare la ricevuta e avviare il processo di pagamento. Tuttavia, ciò significa che il modulo finanziario deve conoscere gli articoli di inventario che sono stati ricevuti. Posso semplicemente fare riferimento a loro tramite ID, ma cosa succede se ho bisogno di ulteriori informazioni per la ricevuta, come il nome e / o la descrizione, il costo unitario, ecc.? Ha senso per ogni modulo avere la propria versione di un articolo di inventario progettato per soddisfare le esigenze di quel modulo? In tal caso, il modulo finanziario dovrebbe eseguire la propria ricerca degli articoli di inventario durante la gestione di GoodsReceivedEvent.
...
Ho usato questo esempio apposta perché ho lavorato molto con vari sistemi ERP e so che sono progettati con questo tipo di modularità - non so proprio come. Inoltre, non lo menziono esplicitamente sopra, ma preferisco seguire i principi di Domain Driven Design nell'architettura della soluzione e credo che questo tipo di modularità si adatti perfettamente a quell'area.
Qualsiasi aiuto per farmi avvolgere la testa è molto apprezzato.