Events Donāt Eliminate Dependencies
Event (or message) driven systems (in their two flavors) have some benefits. Iāve already discussed why I think they are overused. But thatās not what Iām going to write about now.
Iām going to write (very briefly) about ādependenciesā and ācouplingā. It may seem that when we eliminate the compile-time dependencies, we eliminate coupling between components. For example:
class CustomerActions {
void purchaseItem(int itemId) {
//...
purchaseService.makePurchase(item, userId);
}
}vs
class CustomerActions {
void purchaseItem(int itemId) {
//...
queue.sendMessage(new PurchaseItemMessage(item, userId));
}
}It looks as though your CustomerActions class no longer depends on a PurchaseService. It doesnāt care who will process the PurchaseItem message. There will certainly be some PurchaseService out there that will handle the message, but the former class is not tied to it at compile time. Which may look like a good example of āloose couplingā. But it isnāt.
First, the two classes may be loosely coupled in the first place. The fact that one interacts with the other doesnāt mean they are coupled ā they are free to change independently, as long as the PurchaseService maintains the contract of its makePurchase method
Second, having eliminated the compile-time dependencies doesnāt mean we have eliminated logical dependencies. The event is sent, we need something to receive and process it. In many cases thatās a single target class, within the same VM/deployment. And the wikipedia article defines a way to measure coupling in terms of the data. Is it different in the two approaches above? No ā in the first instance we will have to change the method definition, and in the second instance ā the event class definition. And we will still have a processing class whose logic we may also have to change after changing the contract. In a way, the former class still depends logically on the latter class, even though thatās not explicitly realized at compile time.
The point is, the logical coupling remains. And by simply moving it into an event doesnāt give the āpromisedā benefits. In fact, it makes code harder to read and trace. While in the former case youād simple ask your IDE for a call hierarchy, it may be harder to trace who produces and who consumes the given message. The event approach has some pluses ā events may be pushed to a queue, but so can direct invocations (through a proxy, for example, as spring does with just a single @Async annotation).
Of course thatās a simplified use-case. More complicated ones would benefit from an event-driven approach, but in my view these use-cases rarely cover the whole application architecture; they are most often better suited for specific problems, e.g. the NIO library. And Iāll continue to perpetuate this common sense mantra ā donāt do something unless you know what exactly are the benefits it gives you.
| Reference: | Events Donāt Eliminate Dependencies from our JCG partner Bozhidar Bozhanov at the Bozho’s tech blog blog. |


