The Pattern of Decay
Every codebase that ages without architectural discipline grows one: OrderManager, AppController, UtilManager — a class absorbing responsibility after responsibility until it becomes the system’s single point of knowledge. It is the runtime form of SRP violation, and its growth follows a recognizable arc:
Week 1: OrderService places orders (fine)
Month 3: + payment handling ("it's order-related")
Month 6: + inventory checks, email sending ("already has the data")
Year 1: 4,000 lines, 40 fields, 120 methods:
┌────────────────────────────────────────────────────┐
│ OrderGod │
│ place() cancel() refund() chargeCard() │
│ checkStock() reserveStock() sendEmail() │
│ generateInvoice() exportCsv() validateTax() │
│ ...and every other method in the codebase │
└────────────────────────────────────────────────────┘
every feature change edits this file → merge conflicts → fear → freeze
Diagnostic Signals
| Signal | Threshold intuition |
|---|---|
| Lines/methods | Thousands of lines or hundreds of methods |
| Fields | Dozens; clusters unused together |
| Reasons to change | You can name 5+ unrelated stakeholders who’d force edits |
| Imports | Touches persistence, HTTP, formatting, domain — everything |
| Test profile | One test class with hundreds of cases mocking half the app |
| Team folklore | ”Don’t touch that file” is spoken aloud |
Refactoring Playbook
Step 0 Pin behavior with characterization tests FIRST — no refactor blind.
Step 1 Group members by reason-to-change:
pricing cluster / payment cluster / notification cluster ...
Step 2 Extract Class per cluster → PaymentProcessor, InventoryService,
NotificationService, InvoiceGenerator
Step 3 Inject collaborators into the now-thin orchestrator;
god methods delegate instead of implementing.
Step 4 Move data WITH behavior (Feature Envy cure) so new classes own state.
Step 5 Iterate — extraction is incremental; ship each seam separately.
BEFORE AFTER
┌───────────────┐ OrderService (orchestrates only)
│ OrderGod │──extract──► ├── PaymentProcessor
│ everything │ ├── InventoryService
└───────────────┘ ├── NotificationService
└── InvoiceGenerator
Why God Objects Happen Anyway
- Convenience gravity: “the data’s already here” justifies one more method.
- Missing vocabulary: without named subdomains, responsibilities have nowhere to go.
- Review gaps: PRs adding 200 lines to the god file pass because it compiles and tests stay green.
Prevention is process, not heroics: enforce file-size review signals early; require new responsibilities to justify joining existing classes.
Related Smells
God object = LargeClass at terminal stage, usually hosting Feature Envy by the ton, surrounded by Middle Men that merely forward to it.
Interview Framing
Asked to fix one: tests first → cluster by change-reason → extract class per cluster → thin orchestrator remains. Saying “incremental, each seam shippable” marks production experience over textbook ambition.
Premium Content
Unlock God Object and all premium lessons with a subscription.
From ₹199.99/year — See plans