Mohammad YahiaMohammad Yahia
Back to all articles

Is Software Architecture a Necessity, or Have We Turned It Into an Unproven Dogma?

Examining the persistent divide between architectural ideals (Rich Domain Models, DDD, Clean Architecture) and real-world procedural production code.


Over the years, working across large-scale systems, I’ve observed a persistent divide between the architectural paradigms we are taught and how real-world code actually gets written in production.


The Architectural Ideal vs. Production Reality

On one side, software engineering literature presents a clear, elegant ideal:

  • Rich Domain Models & Real OOP: Encapsulating behavior and business invariants close to the data, rather than relying on anemic data bags.
  • Domain-Driven Design (DDD) & BDD: Aligning code directly with a ubiquitous domain language, concrete discovery examples, and living behavior specifications.
  • Hexagonal & Clean Architecture: Isolating business rules completely from databases, external frameworks, and delivery mechanisms through strict port-and-adapter boundaries.

Yet, when inspecting production codebases across the industry, the default is overwhelmingly procedural execution:

  • Sequential pipelines and step-by-step method chains.
  • Dumb, mutable DTOs manipulated across procedural service layers (OrderService, PaymentProcessor).
  • Database-first schemas driving the application logic and domain models.

The Case for Procedural Simplicity

The compelling case for procedural design is immediate cognitive simplicity:

  • Flowchart Thinking: Developers naturally reason about business workflows as linear execution flowcharts.
  • Traceability: It is linear and easy to trace directly without jumping through multiple layers of interfaces, factories, and DTO mappers.
  • Velocity: It is fast to deliver, reduces initial cognitive friction, and generates real business revenue immediately.

The Compounding Cost of Technical Debt

However, the counter-argument is the well-known cost of unmanaged technical debt:

As business logic expands, state mutations get buried under deep hierarchies of nested procedural calls. The core business invariants become invisible, regression risks rise, and engineering teams eventually develop a palpable fear of touching critical legacy paths.


The Core Dilemmas

This tension brings us to three fundamental questions:

1. Over-Complicating Simple Problems

Are we blindly applying complex paradigms—rich OOP hierarchies, DDD aggregates, and multi-layered onion boundaries—to problems that simply do not need them, creating massive accidental complexity?

2. Dogma vs. Empirical Proof

The industry often treats Clean Architecture and DDD as unquestioned gospel. But where is the empirical proof? Software engineering is not a deterministic physical science; what works for one team and domain often fails or creates excessive friction in another.

3. The Abstraction Tax

Does paying a heavy upfront design tax really guarantee a longer system lifespan, or does it just trade conditional complexity for layers of indirection that slow down daily delivery?


Perspective: A Multi-Dimensional Decision Spectrum

A system’s architectural success is heavily tied to team cognitive capacity, business volatility, and organizational culture—not just adherence to design patterns.

Even if adhering to best practices worked across several high-profile case studies, there is no guarantee it won’t introduce worse overhead under different project constraints, domain maturity, and scale.

Rather than viewing software design as a binary choice between “dirty procedural code” and “clean architectural purity,” it belongs on a multi-dimensional decision spectrum. The real answer is not dogmatic upfront purity, but the discipline of continuous evaluation, contextual pragmatism, and iterative refactoring.