11

I'm looking at architecting a new solution that is very modular by nature and would like to create a structure that supports that design to allow for easy future expansion, clear separation of concerns, licensing by module, etc. Most of what I've found on the web about modular or composite applications are UI-centric, focused on Silverlight, WPF, etc. In my case, I am developing a WCF service application that will be consumed by other developers working on various UI projects.

Background

The goal of my project is to create a centralized source of business/domain logic to support several of our business applications that currently duplicate process, rules, etc. And while not every benefit of modularity will be achieved, I'd like to seize the opportunity to establish a framework that will leverage those parts we can take advantage of.

I've started the design by looking at the API exposed by the service application. It is clear that the services can be segregated along the modular lines that I was considering. For instance, I will have FinanceService, InventoryService, PersonnelService, etc. services that group my service operations to provide high-cohesion in the API while keeping the coupling low so clients only have to consume the services that are pertinent to their application.

It makes sense to me that I can then have separate modules for each of these services, such as MyApp.Finance, MyApp.Inventory, My.Personnel and so on. Cross-cutting concerns and shared types would be in the MyApp shared assembly. From here I get a little tied up.

(Oh, I should mention that I'll be using an IoC container for Dependency Injection to keep the application loosely-coupled. I won't mention which one because I don't want to open Pandora's box!)

In MyApp.ServiceHost, I will create a service host file (.svc) corresponding to each module, FinanceService.svc for example. The service host needs the name of the service which corresponds to the information in the configuration file that contains the interface defining the service contract. The IoC configuration is then used to map the concrete implementation of the interface to use.

1. Should the service layer implement the API and delegate to the modules or should the modules be self-contained (in that they contain everything related to that module, including the service implementation)?

One way of approaching the problem is to have a MyApp.Services "module" which contains the implementation of the service contracts. Each service class simply delegate to another class int eh appropriate module which contains the domain logic for the operation. For example, the FinanceService WCF class in MyApp.Services delegates to another interface which is implemented in the Finance module to carry out the operation. This would allow me to maintain a thin service facade and 'plug-in' the implementation to the service implementation and eliminate the need for the modules to worry about WCF, for instance.

On the other hand, maybe it's preferred to have each module self-contained in that it has the interface and the implementation. The service host refers to the service contract interface found in the module and the IoC is configured to use the appropriate implementation from the module as well. This means that adding a new module can be done with no changes to the service layer other than adding a new .svc file and IoC configuration information.

I'm thinking about the impact if I switch from standard WCF to a RESTful service interface or maybe go to RIA services or something. If each module contains the implementation of the service contract, then I have to make changes in every module if I change the service technology or approach. But, if the facade is its own module, then I only have to swap out that part to make a change. The modules would then have to implement a different set of contracts (interfaces), possibly defined in the shared assembly???

2. What is the best way to handle sharing resources between modules and/or dependencies between modules?

Take, for instance, a Receiving operation. At first blush it makes sense that this goes into the Inventory module as receiving goods is an inventory function. However, there is also a financial aspect in that we need to generate a Receipt and authorize payment.

On the one hand, I would expect to use some type of domain events / messaging to communicate the operation. The Inventory module raises a GoodsReceivedEvent which is handled by the Financial module to generate the Receipt and initiate the payment process. However, this means that the Financial module needs to know about the inventory items that were received. I can simply refer to them by ID but what if I need additional information for the Receipt, such as the name and/or description, unit cost, etc.? Does it make sense for each module to have their own version of an inventory item that is designed to suit the needs of that module? In that case, the Financial module would have to perform its own lookup of the inventory items when handling the GoodsReceivedEvent. Or do I now have to put my domain objects into a shared location (at which point I lose some cohesion)?

...

I used this example on purpose because I've worked a lot with various ERP systems and know they are designed with this type of modularity - I just don't know how. I also don't explicitly mention it above, but I prefer to follow Domain Driven Design principals in architecting the solution and believe that this type of modularity fits right into that area.

Any help getting my head wrapped around this is greatly appreciated.

11
  • 1
    Sorry. Can't find a question in all the thinking. What's the question?
    – S.Lott
    May 12, 2011 at 19:59
  • 1
    Look for the question marks. There are several points where I offer up options but don't presume a solution and several specific questions to help guide the process down the right path. May 12, 2011 at 20:05
  • 1
    @SonOfPirate: Sorry. I was hoping you might take the time to highlight or emphasize the questions so that other folks could help you out.
    – S.Lott
    May 12, 2011 at 20:22
  • 4
    I agree with S.Lott. I'm sorry, but this isn't a question, it's a stream-of-consciousness. We can help you a lot better if you condense this down to one or two focused questions, and try to separate the architectural concerns from the implementation details.
    – Aaronaught
    May 12, 2011 at 21:14
  • 1
    @SonOfPirate: "Architecture" is about structure and communicating that structure to the other developers. It starts with the description. It must achieve a level of clarity and transparency that allows other developers to totally "get" it and follow the architectural design principles in everything they do.
    – S.Lott
    May 12, 2011 at 21:24

1 Answer 1

2

Does it make sense for each module to have their own version of an inventory item that is designed to suit the needs of that module? In that case, the Financial module would have to perform its own lookup of the inventory items when handling the GoodsReceivedEvent. Where do I draw the line between modularity and the need to share information?

You will always have to accept trade-offs. That's all there's to say to your questions really. It has been a good practice to keep the entities in a separate assembly, so many applications keep them in a shared library. But that means that there're no (physical) business-logical boundries. Performing your own lookups means a lot of redundant code which I'd only implement if you have special requirements in both the modules. Of course, looking at it from an architectural point of view, your Financial Module and your Inventory Module have to share a dependency anyway. The Financial Module is most likely dependent on the Inventory Module. If requirements permit you to let one module depend on another module, then I'd say it's ok to encapsulate the entities within the modules they belong to the most. You'll need to find a good balance between physical distinction (shared dependencies) and maintenance. Too many shared dependencies could cause a maintenance nightmare of versions. Also, with an ORM there'll be troubles if you want to map new relations to existing entities or extend them from modules which depend on the module containing the entity.

If you don't use ORM then keep in mind all your modules probably share the same database anyway, as that's often the case. You could use that as a common ground.

You could also keep the data plain (in terms of CSV/resultsets e.g.) and use a central messaging service to notify modules that registered to it about new data with along with some meta information. That means no real dependencies, but sacrifices type safty and contracts and there can be troubles with malformed data. I guess that's how many big ERP systems do it.

So in short, you'll have to decide which kind of interface you want. More modularity leads to less contracts and vice versa.

Id'probably use a shared library for my data objects and a central messaging service with a publish subscibe pattern, that seems the best solution to me.

1
  • Also agree with this - messaging + pub/sub and shared libraries for dto contracts (internal nuget repo). I was wondering the same questions as @SonOfPirate until this article put it in perspective for me: msdn.microsoft.com/en-us/library/bb245678.aspx
    – diegohb
    Jan 25, 2014 at 3:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.