Event-Driven Architecture - Mediator Topology

Don't let complexity trick you
Published on 2024/11/19

In a previous post, I touched on event-driven architecture and broker topology. While I have yet to work with a broker topology, its comparison to the mediator one helped consolidate my understanding of it and build a better intuition. Let's get right into it.

One of the most significant selling points of a broker topology is its scalability. This can be achieved by being strongly decoupled, allowing individual components to scale without " worrying" about the rest of the system. The processors operate independently, so any failure doesn't affect the overall system's health. This also means that there are no inherent mechanisms in place to manage errors or retries (but that doesn't mean you can't; dead letter queues and retry policies are examples). As mentioned earlier, this decoupling helps scalability, making broker topologies a good choice for systems with high throughput demands (parallelization is "built-in").

Mediator topologies, on the other hand, are designed for fulfilling workflows. A mediator manages the lifecycle of an event and its related processes, ensuring state is tracked throughout. This is a big differentiator compared to a broker topology, where the broker itself does not worry about what happens in individual processors and the event they are handling. The mediator, by overseeing the processing end to end, is able to act on failures and course-correct before the processing continues to the next step. This added responsibility introduces scalability challenges. Since the mediator controls the workflow, it can become a bottleneck in high-performance systems. There are patterns to follow to mitigate the scalability limitations. You can get creative here; the book covers hierarchical mediators or distributed designs. Either way it's hard to escape complexity, which can make managing a mediator topology challenging.

I liked highlighting the difference between events and commands. In a broker topology, events can be ignored by processors, emphasizing loose coupling and flexibility. Mediators, however, treat messages as commands that must be processed, prioritizing reliability and workflow completion. It was the first time I read about this perspective (event vs command) when comparing the two topologies.

I also enjoyed the example distinguishing responsiveness and performance. Responsiveness measures how quickly a system allows you to move on to the next task, even if the previous one is still processing. Performance, on the other hand, refers to how fast a task is actually completed. With their ability to retry and track state, mediator topologies often improve responsiveness but may suffer in raw performance due to bottlenecks.

Thoughts

Broker topologies excel in scalability and simplicity, while mediator topologies bring reliability and state management at the cost of increased complexity. I'm not a fan of complex systems as they give a team headaches as soon as things go wrong. Depending on requirements, it becomes an art the way an engineering team can adapt by leveraging hybrid systems. But again, the more you steer away from a "classic" architecture, the more its complexity can bite you down the road. This is not an impossible task, but it requires a disciplined architectural design process.

That said, the key takeaway is not to memorize every detail of these topologies but to develop a high-level understanding of their strengths and weaknesses. This foundational knowledge empowers you to participate in discussions, make informed decisions, and adapt these patterns to your needs. I like to go back to the basics, mostly to dust off the tools in my toolset.

Finally (and I can't stress this enough), remember that simplicity is often harder to achieve than complexity. When designing or working with event-driven systems (or any system, really), aim to balance functionality and maintainability, making sure your architecture satisfies the requirements without unnecessary complexities. Keep It Stupid Simple.

0
← Go Back