← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Transaction Script Pattern

Code Quality Intermediate
debt(d7/e7/b7/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no' and the only tool listed is phpstan, which cannot reliably detect architectural pattern mismatches. Recognising that a Transaction Script has grown too large or that a Domain Model is needed requires human code review — no linter or static analyser flags this automatically.

e7 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix acknowledges that when the domain grows complex, you must 'refactor to Domain Model when business rules grow complex.' Migrating from Transaction Script to a Domain Model touches every use-case function, introduces new abstractions (entities, value objects, repositories), and affects all callers — this is a cross-cutting architectural refactor, not a localised patch.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (e7). The pattern applies_to web, cli, and queue-worker contexts, meaning it shapes how all business logic is structured across the entire application. Common mistakes include scripts tangling multiple concerns and business logic split across stored procedures — once entrenched, every new feature is authored in the same procedural style, and the pattern shapes every work stream until a major refactor occurs.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap — a documented gotcha most devs eventually learn' (t5). The misconception field captures the canonical trap precisely: developers assume Transaction Script is always inferior and reach for Domain Model even for simple CRUD, or conversely they stick with Transaction Script as complexity grows. This is a well-documented architectural mismatch that most developers encounter and learn about, but it requires experience to navigate — not an instantly obvious mistake.

About DEBT scoring →

Also Known As

procedural design script-based architecture stored procedure pattern

TL;DR

A pattern where each business operation is a single procedure — simple, linear, and appropriate for straightforward workflows without complex domain logic.

Explanation

Transaction Script (Martin Fowler, PoEAA) organises logic as a set of procedures — one function per business transaction. The procedure reads data, applies logic, and writes results. Simple, easy to understand, easy to trace. Best for: simple CRUD applications, scripting, reporting, and ETL. Problems at scale: duplicate logic across scripts, difficult to reuse, logic grows unwieldy as rules multiply. The contrast with Domain Model: Transaction Script = logic in procedures; Domain Model = logic in objects.

Common Misconception

Transaction Script is always inferior to Domain Model — for simple workflows Transaction Script is cleaner and easier to understand than a full domain model; choose based on actual complexity.

Why It Matters

Applying Domain Model to a simple CRUD app is over-engineering; applying Transaction Script to a complex billing system produces an unmaintainable tangle of duplicated logic — matching pattern to complexity is the skill.

Common Mistakes

  • Sticking with Transaction Script as the domain grows — recognise when duplication signals time to introduce a domain model.
  • Long transaction scripts with 200+ lines — extract helpers but consider whether a domain model is needed.
  • Business logic split between scripts and stored procedures — consolidate in one place.
  • No service layer abstraction — transaction scripts directly calling SQL make testing difficult.

Code Examples

✗ Vulnerable
// Transaction script — appropriate for this simplicity:
function createUser(array $data): int {
    $pdo->prepare('INSERT INTO users (name, email) VALUES (?, ?)')
        ->execute([$data['name'], $data['email']]);
    return $pdo->lastInsertId();
}
// Fine for simple CRUD — no need for domain model complexity here
✓ Fixed
// Transaction script becoming unwieldy — time to refactor to domain model:
function processOrder(int $orderId): void {
    // 50 lines: fetch order, check inventory, apply discount rules,
    // calculate tax, charge payment, update inventory, send email,
    // update loyalty points, generate invoice...
    // Each rule duplicated in processReOrder(), processSubscriptionOrder()...
    // Signal: extract Order domain object with these methods
}

Added 16 Mar 2026
Edited 22 Mar 2026
Views 131
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 1 ping F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 3 pings F 1 ping S 3 pings S 1 ping M 1 ping T 3 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W
No pings yet today
PetalBot 1
ChatGPT 44 Perplexity 19 Amazonbot 15 Google 9 Scrapy 5 Unknown AI 4 Ahrefs 3 Claude 2 Sogou 1 Bing 1 SEMrush 1 PetalBot 1
crawler 101 crawler_json 4
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: Low
⚡ Quick Fix
Use Transaction Script for simple operations where Domain Model is overkill — a PHP function that handles one use case from start to finish is fine for CRUD; refactor to Domain Model when business rules grow complex
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Simple CRUD over-engineered with DDD; transaction script grown too large with mixed business logic; use case functions tangling multiple concerns
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: File Tests: Update


✓ schema.org compliant