Software Developer · The Gambia

Domain-Driven Design

Domain-Driven Design (DDD) is the modeling approach I default to on every system I build that’s more complex than a handful of CRUD screens. It isn’t a framework or a library — it’s a set of practices, introduced by Eric Evans in his 2003 book Domain-Driven Design: Tackling Complexity in the Heart of Software, for keeping software aligned with the real-world process it’s meant to support, using a model and a vocabulary that the code and the people who do the work actually share.

Why model the domain at all?

Most systems don’t fail because a developer couldn’t write the code — they fail because the business rules end up scattered across controllers, database triggers, and UI components, with no single place that reflects how the process actually works. Every new feature becomes a search for every place a rule might be hiding. DDD front-loads that modeling work: you sit down with the real process first — the entities, the rules, the edge cases — before a line of code gets written, and the resulting model becomes the backbone the rest of the system is built around.

The building blocks I use

DDD comes with its own vocabulary. Here’s what each piece actually means in practice, with a real example from the visitor management platform I built for a government agency.

Ubiquitous language

A vocabulary shared, word for word, between the code and the people who actually do the work — no translation layer between what a domain expert says and what a variable is named.

In practice: On the visitor management platform, front-desk staff, the code, and the UI all use the same words — “Visitor,” “Check-in,” “Department,” “Sign-out.” Nobody has to translate between how staff describe their day and how the system models it.

Entities

Objects defined by a persistent identity rather than their attributes — the same entity even after its details change, because it's still the same underlying thing.

In practice: A Visitor is an entity: their record persists across visits, updates when their details change, and stays the same Visitor whether they're currently checked in or not.

Value objects

Objects defined only by their value, with no identity of their own — two of them with the same data are simply interchangeable.

In practice: A check-in time window or a badge number is a value object — it doesn't matter which specific instance it is, only what it says.

Aggregates

A cluster of related objects treated as one unit for the purpose of data changes, with a single aggregate root that enforces the rules and is the only entry point in or out.

In practice: A Visit is an aggregate root that owns its own check-in and check-out timestamps, and enforces the rule that one visitor can't be checked into two departments at the same time.

Bounded contexts

An explicit boundary around a model where a term means exactly one thing — the same word can mean something slightly different in another context, and that's fine as long as the line between them is drawn on purpose.

In practice: “Front-desk registration” and “Analytics reporting” are separate bounded contexts on the same platform — both use the word “Visitor,” but each owns its own shape of what that means for its purpose.

Domain events

Something meaningful that happened in the domain, recorded as a first-class fact — other parts of the system react to it instead of being tightly wired to whatever caused it.

In practice: A CheckedIn event fires the moment someone signs in at the front desk, and that's what drives the live analytics dashboard to update in real time — the dashboard doesn't need to know how check-in works internally.

Repositories

A layer that hides how objects are actually stored and retrieved, so the domain logic can work with plain domain objects instead of database rows.

In practice: A VisitorRepository is the only thing in the system that knows whether visitor records live in Postgres or MySQL — the domain logic above it never has to care.

Why it matters once a system grows

None of this matters much for a five-page site. It matters a great deal once a system has been in production for two years, passed through a few hands, and grown past the point where one person can hold the whole thing in their head. A codebase structured around bounded contexts and aggregates is still readable at 50 files. One without that structure is often unmanageable at 10 — every change risks breaking a rule that lives somewhere unexpected, because there was never a single place that rule was supposed to live.

How I apply it, step by step

In practice it follows the same sequence every time: discover and model the real-world process first, turn that model into bounded contexts and aggregates, then build backend, frontend, and mobile together against that shared model — so nothing gets bolted on after the fact. The full five-step process, through testing and long-term support, is laid out on the Approach page.

Further reading

This approach is built directly on two sources, if you want to go deeper than a portfolio page can:

Domain Language — Eric EvansThe site of the person who coined the term and wrote the original 2003 book.DomainDrivenDesign — Martin Fowler’s blikiA concise, widely-cited explanation of the core ideas from one of the field’s most respected voices.
Get in touch

Have a project in mind?

Whether it’s a full platform, a mobile app, or a system that needs AI woven in — I’m glad to talk through what you’re building.