{
    "slug": "table_module_pattern",
    "term": "Table Module Pattern",
    "category": "quality",
    "difficulty": "intermediate",
    "short": "One class per database table handling all logic — a pragmatic middle ground between Transaction Script and full Domain Model.",
    "long": "Table Module (Martin Fowler, PoEAA): all business logic for a table's rows in one class, operating on collections not individual objects. Good for: moderate business logic that outgrows Transaction Script but does not justify full Domain Model.",
    "aliases": [
        "table module"
    ],
    "tags": [
        "patterns",
        "database",
        "architecture"
    ],
    "misconception": "Table Module is the same as Repository — Repository returns domain objects one at a time; Table Module works on the table as a unit.",
    "why_it_matters": "Table Module fits database-centric applications where the domain logic is thin and SQL is the natural expression of business rules. It avoids the object-relational impedance mismatch of Active Record for read-heavy reporting use cases. The limitation is that it becomes awkward when business logic complexity grows — the module accumulates methods that would be better distributed across domain objects. It works well as an intermediate step when migrating from procedural database code toward a richer domain model.",
    "common_mistakes": [
        "Growing into a God Class",
        "Mixing data access with presentation",
        "One per every table regardless of need"
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "domain_model_pattern",
        "transaction_script",
        "active_record_pattern"
    ],
    "prerequisites": [
        "data_mapper_vs_active_record",
        "database_indexing",
        "single_responsibility"
    ],
    "refs": [
        "https://www.martinfowler.com/eaaCatalog/tableModule.html"
    ],
    "bad_code": "// Logic scattered across files:\n// file1.php: $pdo->query('SELECT * FROM orders WHERE...');\n// file2.php: $pdo->query('UPDATE orders SET...');",
    "good_code": "class OrderTable {\n    public function findPendingOverdue(): array { return $this->db->query(...)->fetchAll(); }\n    public function markAsProcessing(int $id): void { $this->validateTransition($id); $this->db->execute(...); }\n}",
    "quick_fix": "Use the Table Module pattern for simple domain logic where an Active Record is overkill but a full Domain Model is unnecessary — one class handles all business logic for a database table",
    "severity": "info",
    "effort": "medium",
    "created": "2026-03-16",
    "updated": "2026-03-23",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/table_module_pattern",
        "html_url": "https://codeclaritylab.com/glossary/table_module_pattern",
        "json_url": "https://codeclaritylab.com/glossary/table_module_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": "[Table Module Pattern](https://codeclaritylab.com/glossary/table_module_pattern) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/table_module_pattern"
            }
        }
    }
}