I’m in a situation where part of my system has a dependency on another module in the same system, but the modules themselves need to remain independently deployable, where the parts they depend on would be filled in with another implementation.
A module in this instance is the concept of a bunch of components that all contribute to servicing a business function. The system is also built in C#.
So, where I depend on another module, the source module defines an interface describing the functions it needs the dependent party module to implement. The contract types (domain model objects) are also interfaces for the dependent module.
Here is where it gets a bit hazy to me. The dependency inversion principle doesn’t sit well in my head at this point. Both of those “modules” are of the same importance as each other. Which should define interfaces and force the other to reference it? I’m suspecting a 3rd project sitting between the modules that handles setting up the dependencies (probably a DI container). Should the entities in the modules be interfaced? They are simply bags of get/set (no DDD here).
Can anyone offer any guidance here?
Thanks in advance.
Edit 1:
The project structure:
Module1.Interfaces IModuleOneServices Module1.Models ModuleOneDataObject Module1 Module1 implements IModuleOneServices Module2.Interfaces IModuleTwoServices Module2.Models ModuleTwoDataObject - has property of type ModuleOneDataObject Module2 Module2 implements IModuleTwoServices depends on IModuleOneServices
Module2 needs to be deployable by itself, and remains compilable, and sometimes, run without a Module1 present at all.
2
Hmm, sounds like you need a glue module. How about an orchestrator which knows both the modules and can mediate between them? The modules themselves needn’t know each other then.
Another option is to put the “shared” classes in a shared library that both the modules can depend on.
This is not exactly dependency inversion but why would you follow that approach dogmatically. I suspect that you are building an application with those two modules so a top down approach is fine here imho.
4
The dependency inversion principle would very nicely apply to what you are trying to do.
Let me exemplify. If A uses B, than A depends on B. To brake the dependency you introduce an interface. The interface must belong to package A and can be implement by B or C or any other module. The important part here is the belonging to A. If you do that, you can deploy A without deploying or recompiling B. A depends on an interface, which is the most abstract thing you can have in OO. Depending on abstract things is also the best you can do.
Now, this solved the problem where A uses B. If I understand you correctly, your B module also uses A. So you have a reverse dependency also. This cyclic dependency should be avoided whenever possible. However, if it happens, just create an interface belonging to B and implemented by A. Do the reverse of my previous paragraph.
This way you can deploy each of your modules independently. The only reason to deploy both is when you change the interface in such a way that it is not backward compatible any more.
2