DEV Community

Cover image for Complexity Should Be Earned
Ahmed Abdelgawad
Ahmed Abdelgawad

Posted on

Complexity Should Be Earned

Every engineer eventually reaches a point where they stop asking:

"How do I implement this?"

and start asking:

"What's the right architecture?"

That's a sign of growth.

It's usually when you discover concepts like Domain-Driven Design, CQRS, Event Sourcing, Hexagonal Architecture, and countless other patterns that promise cleaner, more maintainable systems.

The mistake isn't learning those patterns.

The mistake is looking for reasons to use them.

Over the years, I've noticed something interesting: the more experienced engineers become, the more comfortable they are introducing complexity. Sometimes that's exactly what a system needs. But sometimes we're solving tomorrow's problems while today's business is still asking for a simple application.

One of the most valuable engineering skills isn't knowing every architecture pattern.

It's knowing when not to use one.

Every decision has a price

Architecture discussions often focus on what patterns enable.

  • CQRS separates reads from writes.
  • Event Sourcing preserves the history of every change.
  • Microservices allow teams to deploy independently.

Those are all legitimate advantages.

But every architectural decision also introduces long-term costs.

  • More concepts for new engineers to understand.
  • More code paths to debug.
  • More operational overhead.
  • More infrastructure to maintain.
  • More failure modes to think about.

Those costs are worth paying only when they're solving a real problem.

If the business isn't getting enough value in return, you've probably introduced complexity too early.

CRUD isn't something to "graduate" from

CRUD isn't an architecture.

It isn't a design pattern either.

It's simply a way of describing applications whose primary behavior revolves around creating, reading, updating, and deleting data.

Yet I often see teams treating CRUD as something temporary—as if every successful system eventually needs CQRS, Event Sourcing, or a fleet of microservices.

I don't think that's the right mindset.

A well-designed CRUD application can have:

  • clear boundaries
  • rich domain logic
  • comprehensive tests
  • clean abstractions
  • excellent maintainability

None of those qualities require advanced architectural patterns.

Sometimes CRUD isn't the beginner solution.

Sometimes it's simply the right solution.

Let the business earn the complexity

Imagine you're building an inventory system.

At the beginning, inventory is just a quantity.

Receive stock.

Ship stock.

Update the current value.

A straightforward CRUD application is probably all you need.

Now fast-forward two years.

The business introduces:

  • multiple warehouses
  • stock reservations
  • returns
  • warehouse transfers
  • third-party fulfillment
  • inventory audits

Suddenly, inventory is no longer just a number.

Different parts of the system care about different views of the same data. Historical changes become valuable. Read and write workloads start evolving independently.

At that point, introducing concepts like projections or CQRS might actually make the system simpler, not more complicated.

Notice what happened.

The architecture changed because the business changed.

Not because someone wanted to use a particular pattern.

That's exactly how I believe software should evolve.

Start with the problem, not the pattern

One of the most common architecture questions I hear is:

"Should we use this or that pattern?"

I think there's usually a better question.

"What problem are we trying to solve?"

Sometimes the answer genuinely leads to CQRS.

Sometimes it leads to Event Sourcing.

Sometimes it leads to a modular monolith.

And sometimes it leads to a straightforward CRUD application.

The pattern isn't the goal.

It's the consequence of understanding the problem.

Good architecture isn't about collecting patterns.

It's about making thoughtful trade-offs.

The hardest architectural decision isn't choosing the most sophisticated solution.

It's recognizing when the simplest one is enough.

Good engineers learn patterns.

Great engineers learn when not to use them.

Top comments (0)