{
    "slug": "domain_model_pattern",
    "term": "Domain Model Pattern",
    "category": "quality",
    "difficulty": "advanced",
    "short": "An object model of the domain that incorporates both behaviour and data — entities with methods expressing domain operations rather than just data containers.",
    "long": "The Domain Model pattern (Martin Fowler, PoEAA) puts business logic inside the domain objects themselves. Unlike Anemic Domain Model (data containers with no behaviour) or Transaction Script (logic in service layer), a rich domain model has Order::place(), Invoice::generate(), and User::grantPermission() — the objects do things. This aligns with DDD aggregates and is the foundation for DDD tactical patterns. Best for: complex business logic with many rules and invariants. Overkill for: simple CRUD with few rules.",
    "aliases": [
        "rich domain model",
        "domain object",
        "business object"
    ],
    "tags": [
        "patterns",
        "ddd",
        "oop",
        "architecture"
    ],
    "misconception": "Domain models and database models are the same thing — domain models represent business concepts and rules; database models represent storage concerns; they should be separate classes.",
    "why_it_matters": "A domain model that enforces business invariants in its methods makes invalid states unrepresentable — you cannot have an Order in an impossible state if the Order class prevents it in its own methods.",
    "common_mistakes": [
        "Domain model extending ORM base class — couples domain to persistence, prevents pure unit testing.",
        "Getters and setters on all fields — allows external code to put the object in invalid state.",
        "Domain methods that take primitive arguments instead of value objects — Order::apply(42) vs Order::apply(new Discount(42, 'percent')).",
        "Logic that crosses aggregate boundaries in a single method — use domain events instead."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "ddd_aggregates",
        "anemic_domain_model",
        "active_record_pattern",
        "transaction_script"
    ],
    "prerequisites": [
        "domain_driven_design",
        "anemic_domain_model",
        "value_object"
    ],
    "refs": [
        "https://www.martinfowler.com/eaaCatalog/domainModel.html"
    ],
    "bad_code": "// Anemic model — no behaviour:\nclass Order {\n    public int $status;\n    public float $total;\n    // No methods — just data\n}\n\n// Logic in service — scattered:\nclass OrderService {\n    public function ship(Order $order): void {\n        $order->status = 3; // Magic number\n        $order->shipped_at = now(); // Direct mutation\n    }\n}",
    "good_code": "// Rich domain model — behaviour in the object:\nclass Order {\n    private OrderStatus $status;\n    private Money $total;\n\n    public function ship(TrackingNumber $tracking): void {\n        if (!$this->status->canBeShipped()) {\n            throw new InvalidOrderTransition('Order cannot be shipped from ' . $this->status);\n        }\n        $this->status = OrderStatus::Shipped;\n        $this->trackingNumber = $tracking;\n        $this->raise(new OrderShipped($this->id, $tracking));\n    }\n}",
    "quick_fix": "Move business rules into the domain classes they belong to — if an Order knows its own rules (can it be cancelled? is it complete?), services become thin coordinators not rule engines",
    "severity": "medium",
    "effort": "high",
    "created": "2026-03-16",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/domain_model_pattern",
        "html_url": "https://codeclaritylab.com/glossary/domain_model_pattern",
        "json_url": "https://codeclaritylab.com/glossary/domain_model_pattern.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Domain Model Pattern](https://codeclaritylab.com/glossary/domain_model_pattern) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/domain_model_pattern"
            }
        }
    }
}