Je cherche à concevoir une nouvelle solution très modulaire par nature et je voudrais créer une structure qui prend en charge cette conception pour permettre une expansion future facile, une séparation claire des préoccupations, l'octroi de licences par module, etc. La plupart de ce que j'ai que l'on trouve sur le Web à propos des applications modulaires ou composites sont centrées sur l'interface utilisateur, centrées sur Silverlight, WPF, etc. Dans mon cas, je développe une application de service WCF qui sera utilisée par d'autres développeurs travaillant sur divers projets d'interface utilisateur.
Contexte
Le but de mon projet est de créer une source centralisée de logique métier / domaine pour prendre en charge plusieurs de nos applications métier qui dupliquent actuellement les processus, les règles, etc. Et bien que tous les avantages de la modularité ne soient pas atteints, je voudrais saisir la possibilité d'établir un cadre qui tirera parti des éléments dont nous pouvons tirer parti.
J'ai commencé la conception en regardant l'API exposée par l'application de service. Il est clair que les services peuvent être séparés selon les lignes modulaires que j'envisageais. Par exemple, j'aurai des services FinanceService, InventoryService, PersonnelService, etc. qui regroupent mes opérations de service pour fournir une haute cohésion dans l'API tout en gardant le couplage bas afin que les clients n'aient qu'à consommer les services qui sont pertinents pour leur application.
Il est logique pour moi que je puisse alors avoir des modules séparés pour chacun de ces services, tels que MyApp.Finance, MyApp.Inventory, My.Personnel et ainsi de suite. Les préoccupations transversales et les types partagés se trouveraient dans l'assembly partagé MyApp. De là, je suis un peu ligoté.
(Oh, je dois mentionner que j'utiliserai un conteneur IoC pour l'injection de dépendances pour garder l'application faiblement couplée. Je ne mentionnerai pas lequel parce que je ne veux pas ouvrir la boîte de Pandore!)
Dans MyApp.ServiceHost, je vais créer un fichier hôte de service (.svc) correspondant à chaque module, FinanceService.svc par exemple. L'hôte de service a besoin du nom du service qui correspond aux informations du fichier de configuration qui contient l'interface définissant le contrat de service. La configuration IoC est ensuite utilisée pour cartographier l'implémentation concrète de l'interface à utiliser.
1. La couche de service doit-elle implémenter l'API et déléguer aux modules ou les modules doivent-ils être autonomes (en ce qu'ils contiennent tout ce qui concerne ce module, y compris l'implémentation de service)?
Une façon d'aborder le problème est d'avoir un "module" MyApp.Services qui contient l'implémentation des contrats de service. Chaque classe de service délègue simplement à une autre classe dans le module approprié qui contient la logique du domaine pour l'opération. Par exemple, la classe WCS FinanceService dans MyApp.Services délègue à une autre interface qui est implémentée dans le module Finance pour effectuer l'opération. Cela me permettrait de maintenir une façade de service mince et de «brancher» l'implémentation à l'implémentation de service et d'éliminer le besoin pour les modules de se soucier de WCF, par exemple.
D'un autre côté, il est peut-être préférable que chaque module soit autonome en ce qu'il ait l'interface et l'implémentation. L'hôte de service fait référence à l'interface de contrat de service trouvée dans le module et l'IoC est configuré pour utiliser également l'implémentation appropriée à partir du module. Cela signifie que l'ajout d'un nouveau module peut être effectué sans modification de la couche de service autre que l'ajout d'un nouveau fichier .svc et des informations de configuration IoC.
Je pense à l'impact si je passe du WCF standard à une interface de service RESTful ou si je vais aux services RIA ou quelque chose du genre. Si chaque module contient la mise en œuvre du contrat de service, je dois apporter des modifications à chaque module si je change de technologie ou d'approche de service. Mais, si la façade est son propre module, je n'ai qu'à changer cette partie pour faire un changement. Les modules devraient alors implémenter un ensemble de contrats (interfaces) différent, éventuellement défini dans l'assembly partagé ???
2. Quelle est la meilleure façon de gérer le partage des ressources entre les modules et / ou les dépendances entre les modules?
Prenez, par exemple, une opération de réception. À première vue, il est logique que cela entre dans le module Inventaire car la réception des marchandises est une fonction d'inventaire. Cependant, il y a aussi un aspect financier dans la mesure où nous devons générer un reçu et autoriser le paiement.
D'une part, je m'attendrais à utiliser un certain type d'événements / messagerie de domaine pour communiquer l'opération. Le module d'inventaire déclenche un GoodsReceivedEvent qui est géré par le module financier pour générer le reçu et lancer le processus de paiement. Cependant, cela signifie que le module financier doit connaître les articles en stock qui ont été reçus. Je peux simplement y faire référence par ID, mais que se passe-t-il si j'ai besoin d'informations supplémentaires pour le reçu, telles que le nom et / ou la description, le coût unitaire, etc.? Est-il judicieux que chaque module ait sa propre version d'un élément d'inventaire conçu pour répondre aux besoins de ce module? Dans ce cas, le module financier devrait effectuer sa propre recherche des articles en stock lors de la gestion de l'événement GoodsReceivedEvent.
...
J'ai utilisé cet exemple exprès car j'ai beaucoup travaillé avec divers systèmes ERP et je sais qu'ils sont conçus avec ce type de modularité - je ne sais tout simplement pas comment. Je ne le mentionne pas non plus explicitement ci-dessus, mais je préfère suivre les principes de conception pilotée par domaine dans l'architecture de la solution et je pense que ce type de modularité s'intègre parfaitement dans ce domaine.
Toute aide pour enrouler ma tête autour de cela est grandement appréciée.