In this post I am discussing a problem that I have faced several times in the past year. Simplicity is always a goal in design as it saves resources during development and maintenance. But it’s not always clear which design is simpler. Sometimes a seemingly complex design turns out to be simpler to develop, maintain and extend.
In a master-slave architecture, assume S1 is the master. It produces one or more tasks form a given job and transfers them to S2 (the slave); S2 does the tasks and return the results back to S1. S2, the slave, depends on S1, the master.
If the next time that S1 assigns a task to S2 it uses the information that exists in the result of a previous task that had been assigned to S2 then S1 also depends on S2 and we have a mutually dependent couple.
In our terminology the systems are mutually dependent if and only if S1 uses the information it gained as a result of a previous task that it had already assigned to S2. It doesn’t matter if S2 has completed the previous task or not, but it should have reported something to S1 that is useful for S1 for a next assignment of a task to S2.
If S1 is only using the fact that S2 is busy or free then we don’t call it a mutual dependency. S1 must use the information that is generated by processing a task at S2. For example a MapReduce system is not a mutually dependent system.
Why is it important? You should have already guessed that S2 is the name of a class of slave systems that work with S1. There could be many instances of S2. Let’s define a homogenous mutually dependent system as a system that in which all slaves of S1 are in the same class.
Two slaves are of the same class if they share a common interface for communicating with S1.
Now assume that S3 is also a slave for S1. S3 is in a different class other than S2 if either its input or its output interface is different from S2’s.
When designing mutual dependent systems we have to always decide whether to keep the mutual dependencies or to break them by introducing new nodes. It’s mainly a decision over complexity. The other factor that may affect your decision is the swiftness of the system. Introducing a new node will usually reduce the responsiveness.
For instance a new node must not be added if S1 waits for S2 to return. Generally you should try to keep the number of nodes as small as possible if the operations are not asynchronous.
Homogenous mutual dependency is OK (when the systems are simple and synchronous) but things get much dirtier as we introduce new classes to the system. On the other hand if extensibility is a goal you should try to avoid mutual dependencies.
For a conclusion, use mutual dependent systems in live systems, when a rapid response is required, and try to avoid them by introducing middle nodes if you have many classes of slaves or if extensibility is a goal.