I am currently reading Clean Architecture by Uncle Bob, and there's a discussion in Chapter 24 (Partial Boundaries) about reciprocal polymorphic boundary interfaces. To provide more context, Uncle Bob says that a boundary is used to "separate software elements from one another, and restrict those on one side from knowing about those on the other".
I do understand what polymorphic interfaces are, however, I do not know about reciprocal interfaces. What are reciprocal interfaces in this context?
I've tried searching the web for an answer, however, I couldn't find any discussion on the matter.
I guess what he wants to say is that if you want to completely separate two components - a full-fledged architectural boundary, it means that dependencies should not point directly to the other component in both directions. So you have to introduce interfaces, data structures on both sides.
If you do that you have to answer the question: Where should I place the boundard interfaces?
The answer to this question you have to think about the deployment structure. Which components should be released and deployed together. But deployment highly depends on the language you use. E.g. in Java the JAR files are a deployment unit. I use a Java example here but you can adapt it to many languages.
An interface is more bound to a client then to a provider, since it declares what the client needs. So you might want to put the interface in the same module (JAR file in Java) then the client. If you do that the providers depend on that module. Since the module also contains the client the provider also depends on everything the client needs.
So if you want a full isolation you need to introduce a new deployment unit that only contains the interface and also the data structures the interface needs.
But if you do that, you also need to build and release the
spi.jar, manage versions, an own directory structure in your project and so on. If you use Java with Maven your structure might look like this:What Uncle Bob says is that
You can also put everything into one module (deployment unit). But this opens the door to bypass the interfaces and therefore break the decoupling. Uncle Bob also mentioned this later when he speaks about his FitNesse project:
A side note about dynamic languages
In dynamic languages like Python you don't need to use interfaces or abstract classes like in Java to do polymorphism. Therefore the deployment unit problem I described above will not arise. I guess this is one aspect why dynamic languages are popular. But even in this languages you still need to ensure that dependencies do not cross boundaries in the wrong direction.