Active vs Passive Domain Concepts in Designing Complex Domains

A design principle that helped me survive complexity, maybe it’ll help you too.

Yesterday I was invited to a private OOP design workshop held by Soheil Karami. The task was to explore, learn, model, and design the board game Catan. For someone like me who hasn’t played many board games, this was a seriously complex domain. I was quietly following how the group was approaching the problem.

The funniest and at the same time most interesting part of the day was watching three developers with different experience in terms of quantity, quality and depth, trying to model something none of them fully understood. They were playing the game, drawing diagrams, writing tests, sketching relations, talking and rewriting code. The table quickly turned into a jungle of nouns:

Hexagon, Space, Board, Player, Dice,

Road, Village, City, Robber, Trade,

Brick, Wheat, Wood, Sheep, Ore, …

And pretty soon, they were lost in a jungle of nouns. Endless class discovery. Endless property mapping. Endless shape-drawing that didn’t really move the design forward.

I walked around and finally interrupted them and shared a design principle I use a lot when facing complex domains:


The question that has saved me many times

  1. Is this class supposed to model merely the type of something, or the instances that actually matter when the system runs?

2. Are we modeling the static entity or the real happening?

And I encouraged them:

Start modeling with active domain concepts instead of passive ones.

Design your concepts (aggregates, classes, objects, methods, behaviors, etc.) from the PoV of the actual user and the real usage.

Don’t start by obsessing over static pieces, your objects aren’t going anywhere. Instead, start by describing what actually happens in the system. In the sections below, I’ll break down active vs. passive domain concepts, why they matter, and how they can save you from drowning in complexity. Maybe later I’ll share the other design ideas I mentioned, once I stop tripping over my own metaphors. 😄


What I mean by Active vs Passive Domain Concepts

Passive domain concepts

These are things that exist but don’t do anything on their own. They don’t start any workflow. They just sit there waiting to be used.

In accounting, for example:

GeneralAccount
SubsidiaryAccount
Currency
CostCenter
FiscalYear

They exist. They’re important. But they don’t trigger anything. You define them once and they sit silently until something uses them. 

Active concepts

These are the living concepts, things that move the system, drive behavior, and glue other concepts together. These are entities where something happens, they trigger flows, decisions, and collaboration among other objects.

Examples from accounting:


FinancialTransaction
Posting
TransferMoney
ClosePeriod
SettleBalance

A FinancialTransaction is active, it triggers validations, affects balances, creates journal entries, maybe even publishes integration events. Something happens.

PostTransaction() is what actually causes the accounting system to move. It updates balances. It validates rules. It may generate events. It triggers work. Something happens.


Why This Principle Matters (beyond convenience)

Why Start With Active Instead of Passive?

This is not about shortcuts or avoiding modeling work, it’s about creating clarity and direction in the middle of complexity.

To put it simply, because active concepts reveal how the passive ones interact(believe me, just give it a try). They define the flow and the collaboration between objects. They automatically show which objects are needed and how they’re connected.

Starting with passive concepts gives you:

  • A beautiful diagram of boxes
  • Zero clarity about how they behave
  • Early premature structure
  • Over-modeling and abstraction paralysis

Starting with active domain concepts gives you:

  • A clear entry point into the system
  • A sequence of behaviors rather than infinitely debating structure
  • Natural discovery of required passive concepts
  • Actual business meaning
  • Collaboration and interaction maps, instead of isolated definitions

Starting with passive nouns is like describing every item in a kitchen without knowing what recipe you’re cooking. You’ll list:

Spoon, Salt, Oven, Knife, Table, Fork, Plate…

Great. Now what? What are we cooking? Who is doing what?

Behavior gives shape to structure, not the other way around.

Passive-first modeling gives you a graveyard of objects. Active-first modeling gives you a living system.


Active Concepts as the Glue

Active domain concepts are the glue that connect everything. They combine, trigger, coordinate, and chain objects together into meaningful behavior.

Without them:

  • You only know who exists
  • You don’t know why they exist
  • Relationships are speculative rather than discovered

With them:

  • You see the object map form naturally
  • You see how entities collaborate
  • You model the real world, not static diagrams

It’s the behavior and interaction between concepts that matter.

Objects in isolation are useless. The system’s value is in how they work together and how they change state over time. Modeling is not about naming nouns. Modeling is about choreographing collaboration.


Applying the Idea to Catan (as an example)

Let’s pretend we are designing Catan. Full disclaimer: I really don’t know the game well (at least at the time of writing this 😄). But it’s just an excuse to illustrate the idea.

When beginners start modeling Catan, they often begin by listing nouns:

Board
Hexagon
Tile
Brick
Wood
Player
Village
City
Road
Dice
Island
Port

These are passive concepts. If you model them first, you’ll drown in details and relationships and constraints, and you won’t get far.


Catan Example, Starting With Player(an active domain concept)

In Catan, instead of beginning with nouns like Board, Tile, Road, Resource… let’s start with the most active concept: Player

What does a Player do?

Player.StartTurn()
Player.RollDice()
Player.CollectResources()
Player.BuildRoad()
Player.BuildSettlement()
Player.UpgradeToCity()
Player.TradeResources()
Player.MoveRobber()
Player.StealResource()
Player.ScorePoint()

Active behavior organically reveals passive structure

From

Player.RollDice():
Dice.Roll()
Board.NotifyTiles(diceResult)
Tile.ProduceResource()
Player.ReceiveResource(resource)

Now we know we need:

Dice, Board, Tile, Resource, ProductionRules

discovered through behavior, not speculation.

From Player.BuildRoad():
Board.ValidateRoadPlacement(position)
Player.PayResourceCost(ResourceCost.Road)
Road.Place(position)

Now we know:

Road, Board, Position, ResourceCost

These concepts appear at the right moment, when needed.No guessing. No overdesigning. No UML graveyard.

Real-World Examples

Food Delivery System

Passive

Restaurant, Menu, Dish, Customer, Address, Courier

Active

PlaceOrder
AcceptOrder
AssignCourier
StartDelivery
DeliverOrder
CancelOrder
RefundPayment

Start from PlaceOrder(), and see the result. I won’t show you the result, it’s your turn!

Healthcare System

Another example for you…

Passive

Patient, Doctor, Prescription, Medication, Clinic

Active

BookAppointment
Diagnose
IssuePrescription
DispenseMedication
ScheduleFollowUp

Start with BookAppointment() and the domain becomes architecture.


So When Should You Model Passive Concepts?

Later. When the behavior reveals what data structure is actually needed.

To twitterify it:

Passive modeling is organization. Active modeling is understanding.

Sorry, It’s Not a Silver Bullet

Is this the only way? No, of course. Is this the right way in every domain? Probably not.

Sometimes starting with passive structure is required (e.g., reverse engineering an existing system or working from legal documents or standards). Sometimes relational modeling is necessary early.

But in greenfield modeling, workshop settings, collaborative exploration, or domains you don’t fully understand yet:

  • Starting with active concepts gives direction.
  • Starting with passive concepts gives confusion.

This principle gives you traction. It fights the paralysis of endless abstraction. It forces you to speak about real business actions instead of hypothetical data buckets.


To Wrap

This workshop reminded me again how powerful the shift can be when you stop listing nouns and instead describe what happens.

Model the living parts.
Start with behavior.
Let interactions give birth to structure.

Maybe in the future I’ll write more about the other ideas I shared with the guys that day, such as:

  • Design your concepts (aggregate, class, object, methods, behavior, etc.) from the PoV of its users and usages.
  • Is this class supposed to model the type of something, or the instances that actually matter when the system runs?
  • Are we modeling the static entity or the real happening?

And yes, maybe by the next workshop I’ll finally learn how to actually play Catan 😄

Leave a Reply

Your email address will not be published. Required fields are marked *