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

Principle of Least Astonishment

Code Quality Beginner
debt(d8/e6/b6/t7)
d8 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'silent in production' (d8), since phpstan/psalm listed in detection_hints cannot detect surprising naming or hidden side effects — these only surface during code review or when developers integrate against the misleading API and hit bugs.

e6 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor' (e6), because renaming a misleading method like getUser() that has side effects requires updating every caller across the codebase, plus separating the side effect into a properly-named method — quick_fix says 'rename or redesign' which touches many files.

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

Closest to 'strong gravitational pull' (b6), since applies_to spans web/cli/queue and surprising APIs become load-bearing — every caller works around the astonishment, and the misleading contract shapes how downstream code is written.

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

Closest to 'serious trap' (t7), grounded in the misconception that POLA only applies to UI/public APIs — developers routinely assume getUser() is a pure read, and the common_mistakes list (constructors doing I/O, inverted booleans) shows the 'obvious' interpretation contradicts actual behaviour.

About DEBT scoring →

Also Known As

POLA principle of least surprise least astonishment

TL;DR

Code should behave in a way that minimises surprise — functions should do what their name implies, with no unexpected side effects.

Explanation

The Principle of Least Astonishment (POLA), also called Principle of Least Surprise, states that a component should behave consistently with users' reasonable expectations. In practice: a method named getUser() should never delete a record, a parameter named $count should accept only positive integers, and a function that returns false should not also send an email. Violations create subtle bugs and erode trust in an API. POLA is closely related to Command Query Separation, Tell Don't Ask, and good naming conventions — together they produce APIs that behave predictably.

Common Misconception

POLA only applies to UI and public APIs. It applies equally to internal APIs, method names, and parameter ordering — a method called getUser that sometimes returns null and sometimes throws should astonish no developer who calls it.

Why It Matters

Code that behaves unexpectedly causes bugs even when it is technically correct — predictable names, signatures, and side effects reduce cognitive load and prevent integration mistakes.

Common Mistakes

  • A method named getUser() that also updates a last_seen timestamp — unexpected side effect.
  • A constructor that makes HTTP requests or writes to a database.
  • Functions that modify their array argument in place in a language where pass-by-value is expected.
  • Boolean parameters that invert expected behaviour: delete($id, true) meaning 'soft delete' and delete($id, false) meaning 'hard delete'.

Code Examples

✗ Vulnerable
// Method name suggests read, but performs a write
public function getOrder(int $id): Order {
    $order = Order::find($id);
    $order->increment('views'); // side effect — astonishing!
    return $order;
}

// Constructor with side effects — surprises callers
public function __construct() {
    $this->connect(); // unexpected network call
    $this->migrate(); // unexpected DB migration
}
✓ Fixed
// Name accurately describes behaviour
public function findOrder(int $id): Order {
    return Order::findOrFail($id); // pure read — no surprises
}

public function recordView(int $id): void {
    Order::find($id)->increment('views'); // explicit — callers opt in
}

// Constructor only assigns — side effects via explicit method calls
public function __construct(private readonly DatabaseConfig $config) {}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 95
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T
No pings yet today
Twitter/X 1
Amazonbot 10 ChatGPT 7 Ahrefs 7 SEMrush 7 Scrapy 6 Google 5 PetalBot 5 Twitter/X 4 Unknown AI 3 Applebot 2 Perplexity 1 Meta AI 1 Brave Search 1 Bing 1
crawler 52 crawler_json 7 pre-tracking 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Name functions so the caller can predict the outcome without reading the implementation — if the return value, side effects, or exceptions would surprise a reasonable developer, rename or redesign
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
isValid() that also saves to DB; getUser() that creates user if not found; sortArray() that also deduplicates; getter with side effects
Auto-detectable: ✗ No phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: File


✓ schema.org compliant