Return to site

🛑⚡ WHEN NOT TO USE EVENT-DRIVEN ARCHITECTURE (EDA) inspired by Java Champion Victor Rentea

· kafka

TL;DR ☕

Event-Driven Architecture (EDA) is one of the most powerful architectural styles for scalable distributed systems... but it is NOT a universal solution.

Many teams adopt Kafka, RabbitMQ, Pulsar or cloud messaging because they are trendy, only to discover months later that they have added complexity without solving any real problem.

The best architects know when to use EDA.

The great architects also know when NOT to use it.

Section image

🔸 WHY THIS ARTICLE?

Modern software architecture often swings between extremes.

Yesterday everything was a monolith.

Today everything becomes asynchronous.

Tomorrow... we'll probably rediscover moderation. 😄

EDA is amazing for reacting to events.

It is often terrible for coordinating workflows.

A useful rule of thumb is:

Coordination → Think twice.

Let's see the most common situations where EDA may actually be the wrong architectural choice.

Section image

🔸 1. SIMPLE CRUD APPLICATIONS

If your application is:

▪️ one small team

▪️ one deployable

▪️ one database

▪️ a few hundred users

...adding Kafka or another event broker usually creates more problems than value.

Instead of:

REST

Database

you suddenly have:

REST

Producer

Broker

Consumer

Database

Congratulations 🎉

You just added:

✅ brokers

✅ retries

✅ dead-letter queues

✅ replay

✅ monitoring

✅ serialization

✅ versioning

...to update one row.

Example: Direct CRUD is enough

@PostMapping("/customers")

public Customer create(@RequestBody Customer c) {

return repository.save(c);

}

One request, one transaction, one database update. For small CRUD applications this is easier to maintain than introducing asynchronous messaging and distributed infrastructure.

The complexity budget of EDA should be paid only when it brings clear business value.

🔸 2. WHEN STRONG CONSISTENCY IS REQUIRED

Some domains cannot tolerate eventual consistency.

Examples:

🏦 Banking

💳 Payments

📦 Inventory reservation

✈️ Airline booking

Imagine:

Debit account

Publish event

Credit account

If something crashes in the middle...

Money disappears.

Not ideal.

Some business rules require:

either everything succeeds

or

everything fails.

Those are classic ACID transaction scenarios.

Example: One transaction

@Transactional

public void transfer(Account from, Account to, BigDecimal amount) {

from.withdraw(amount);

to.deposit(amount);

}

Some business operations require atomicity. Distributed events introduce temporary inconsistency that may violate business invariants.

Notice that this does NOT mean EDA is incompatible with finance.

Many banks use EDA extensively...

...but usually after the transactional boundary.

🔸 3. WHEN USERS EXPECT AN IMMEDIATE RESPONSE

Imagine clicking:

Pay Now

Would you like the UI to answer:

"We'll eventually process your payment."

Probably not.

Sometimes users expect:

Click

Immediate validation

Immediate confirmation

Synchronous APIs are often the right tool.

EDA works wonderfully for background processing:

📧 sending emails

📊 analytics

📱 notifications

🧾 invoice generation

Those actions don't block the user experience.

Example: Immediate response

@PostMapping("/login")

public Token login(LoginRequest request) {

return authenticationService.authenticate(request);

}

Authentication is conversational. The client waits for the answer before continuing. An asynchronous workflow would only increase latency and complexity.

🔸 4. WHEN THERE IS NO FAN-OUT

One of the biggest strengths of EDA is:

One producer

Many consumers

Example:

OrderCreated

Inventory

Shipping

Analytics

Recommendation Engine

Fraud Detection

Email

Beautiful.

Now imagine:

Producer

One consumer

That's basically an asynchronous method call.

You added a broker...

to replace:

service.process(order);

Not a great trade-off.

Example: Direct service call

orderValidator.validate(order);

paymentService.process(order);

If only one service consumes the information, direct calls are usually simpler, easier to debug and cheaper to operate than an event broker.

🔸 5. WHEN YOUR TEAM IS NOT OPERATIONALLY READY

EDA is an operational architecture.

Not just a programming model.

Successful EDA requires:

✅ metrics

✅ tracing

✅ replay

✅ dead-letter queues

✅ dashboards

✅ alerting

✅ idempotency

✅ schema evolution

✅ on-call discipline

Without those...

Events become mysteries.

Imagine hearing:

"The event disappeared."

Where?

Nobody knows.

Without observability, debugging distributed systems becomes painful.

Example: Idempotent consumer

if(processedIds.contains(event.id())) {

return;

}

handle(event);

Consumers should safely process duplicate events. Idempotency is one of the foundations of reliable event-driven systems.

🔸 6. WHEN THE BUSINESS PROCESS IS ACTUALLY A CONVERSATION

EDA excels at notifications.

It struggles when every step depends immediately on the previous answer.

Example:

Client

Validate

Calculate

Reserve

Confirm

Return result

Each step requires immediate feedback.

This is more of a conversation than a reaction.

REST or gRPC are usually better suited.

Example: Orchestrated workflow

Quote quote = pricingService.calculate(order);

reservationService.reserve(quote);

Sequential workflows where each step depends on the previous result are often easier to express using synchronous service calls.

🔸 7. WHEN YOU DON'T HAVE AN EVENT MODEL

Some teams create events like:

CustomerUpdated

OrderUpdated

ProductUpdated

InvoiceUpdated

Those are often just CRUD notifications.

Great events usually represent business facts, not database operations.

Examples:

✅ OrderPlaced

✅ PaymentAuthorized

✅ ShipmentDispatched

✅ SubscriptionCancelled

Those events have meaning beyond the database.

Example: Business event

publisher.publish(

new OrderPlaced(orderId, customerId)

);

Events should describe something meaningful that happened in the business domain, not simply mirror SQL UPDATE statements.

🔸 WHAT EDA IS EXCELLENT AT

EDA shines when you need:

🚀 scalability

📈 multiple consumers

⚡ loose coupling

🌍 distributed systems

📊 analytics

📬 notifications

📱 integrations

🧠 reactive architectures

It becomes even more powerful when combined with patterns such as:

▪️ Outbox Pattern

▪️ Saga Pattern

▪️ CQRS

▪️ Event Sourcing (when appropriate)

▪️ Idempotent Consumers

▪️ Dead Letter Queues

▪️ Schema Registry

🔸 COMMON ANTI-PATTERNS

❌ Kafka replacing every REST call

❌ Events for simple CRUD updates

❌ Event storms with dozens of tiny events

❌ No replay strategy

❌ No observability

❌ No idempotency

❌ Using events to hide slow services

❌ Assuming asynchronous always means scalable

🔸 TAKEAWAYS 🎯

▪️ EDA is a powerful architectural style; not a silver bullet.

▪️ Complexity should be introduced only when it solves a real problem.

▪️ Strong consistency often favors synchronous transactions.

▪️ Immediate user interactions usually benefit from synchronous APIs.

▪️ Fan-out is where EDA creates significant value.

▪️ Operational maturity is a prerequisite for production-grade event-driven systems.

▪️ Design business events around domain facts, not CRUD operations.

▪️ A good architect chooses the simplest solution that satisfies today's requirements while leaving room for tomorrow's growth.

Architecture is about trade-offs, not trends.

Sometimes the best event is...

no event at all. ☕⚡

#EventDrivenArchitecture #EDA #Kafka #ApacheKafka #SoftwareArchitecture #Microservices #Java #SpringBoot #DistributedSystems #CloudNative #CQRS #EventSourcing #SystemDesign #Backend #SoftwareEngineering #Architecture #TechLeadership

Go further with Java certification:

Java👇

Spring👇

SpringBook👇

JavaBook👇