Architectural Pattern: Caller Dependency Controller
10/16/2011 2:41:00 PM
By Saleh Najar
If you are dealing with multi-layer architecture, you will frequently run into having to make the decision of where to control a dependency. For example, if you're calling the Data Layer should you let the data layer decide which data layer object family to instantiate or should you let the Workflow inject that? Should the Data Layer decide when to submit a transaction or should this be decided at the higher layer?
As a best practice, the Caller Dependency Controller (CDC) dictates that the caller should always act as the controller of the dependency. In our example above, it should be the Workflow layer who gets to decide 1) the type of Data Layer objects to create and 2) when the Data Layer gets to submit or commit the changes. If this pattern is not followed, you'll pay dearly later by having to re-write a lot of code crossing multiple layers right before the release date. Not good.
For instance, submitting from the Data Gateway layer is fine and dandy when you're dealing with simple transactions but what if you're dealing with multi-step transactions? If the transaction involves more than one step such as making a withdrawal and updating a customer balance, the Data Layer (the dependency) must be controlled by the Workflow Layer (the caller) to maintain atomicity, to only submit when both steps are successful.
If we let the Data Layer decide and commit every time it's called then what happens when making the withdrawal succeeds and commits but updating the balance fails? As you can see in this simple scenario the callee has no high level visibility of the full use case or transaction so it shouldn't make that decision.
This pattern is not just limited to layers, it applies to any situation where you have a caller and a callee, a function calling another function, even when a client calling a server (cross-boundary transactions). We know this when we write simple micro functions and it also applies to macro structures. In micro functions, it always makes sense and without much thinking to maintain the result of the calculation in the calling function. By the same token this applies to bigger structures such as layers and systems.
Architects should set the guidelines for developers straight on this one and look for it in their design reviews.
