Transaction Script Pattern
debt(d7/e7/b7/t5)
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.
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.
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.
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.
Also Known As
TL;DR
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
Why It Matters
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
// 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
// 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
}