Modular monolith or microservices: choosing on team shape
Microservices solve organisational scaling problems and introduce distributed systems problems. Most teams should start with a well-structured monolith.
Events decouple producers from consumers and make the overall flow harder to see. Both effects are real and need managing.
A producer emits a fact without knowing who consumes it. New consumers are added without changing the producer, work is absorbed asynchronously during spikes, and a slow consumer does not block the request path.
For workflows with several independent reactions to the same occurrence, this is a genuinely better model than direct calls.
The complete flow is no longer visible in one place. Debugging requires tracing across components, ordering guarantees vary by transport, and duplicate delivery is normal rather than exceptional.
Consumers must therefore be idempotent, and that has to be designed rather than assumed.
Dead letter queues for messages that cannot be processed, with someone responsible for reviewing them. Monitoring on consumer lag, because a silently falling-behind consumer is a common failure.
Distributed tracing carrying a correlation identifier through the whole chain is what makes an event-driven system debuggable. Without it, investigating a problem becomes archaeology across several logs.
Testing is harder when the flow spans components, and teams often compensate with heavy end-to-end tests that are slow and brittle.
Test each consumer in isolation against representative events, use contract tests to verify that producers emit what consumers expect, and reserve a small number of end-to-end tests for the most important flows.
Make events replayable in a test environment. Being able to feed a recorded sequence through a consumer is the fastest way to reproduce a production problem.
Managed queues suit straightforward asynchronous work. Log-based systems like Kafka suit high throughput, replay and multiple independent consumers of the same stream. Start with the simpler option.
Ordering guarantees vary. Where it matters, partition by a key so related events are ordered relative to each other, and design consumers to tolerate what the transport does not guarantee.
No. Synchronous calls are simpler and appropriate when the caller needs an immediate answer. Use events where reactions are genuinely independent.
Keep reading
Microservices solve organisational scaling problems and introduce distributed systems problems. Most teams should start with a well-structured monolith.
Relational databases handle the overwhelming majority of business workloads well. Alternatives should be chosen for specific reasons.
Complete rewrites fail at a high rate. Incremental strangulation delivers value earlier and carries far less risk.