skip to content

How do you recognize a "god class" (a class that has accumulated far too many responsibilities) in a codebase, and which signals are reliable versus misleading?

level: middleimportance: must knowfreq 72%

answer

  1. cohesion clusters over disjoint field sets (LCOM4 ≥ 2)
  2. constructor arity = test fixture pain
  3. churn + change coupling from git history
  4. Manager / Util / Helper naming smell
  5. size alone lies; ask who requests each change

basics

~20 s

Look for a class that many unrelated features depend on, has a vague name like Manager or Helper, holds lots of loosely related fields, needs many dependencies to construct in a test, and shows up in almost every commit.

solid answer

~40 s

A god class is one that centralizes logic belonging to many actors. Reliable signals are behavioral, not cosmetic: (1) low cohesion — methods split into clusters that touch disjoint subsets of fields (LCOM-style metrics quantify this); (2) many constructor dependencies, so tests need large fixtures; (3) high change frequency and high change coupling — the file appears in commits from unrelated feature streams; (4) a name that cannot be stated without "and" (OrderManager, UtilService); (5) many inbound dependencies from unrelated packages. Misleading signals: raw line count alone, method count alone, and generated or purely declarative code. Size correlates with god classes but does not define them: a large parser serving one grammar is cohesive. Confirm by asking who requests changes to each cluster — distinct requesters mean distinct responsibilities and a real split candidate.

go deeper

for a junior

Name concrete smells: huge class, vague name, many dependencies, hard to test, touched by everyone.

for a middle

Add cohesion reasoning (methods clustering over disjoint fields), constructor-arity pain, and explicitly reject line count as the criterion.

for a senior

Bring in evidence from history (churn, change coupling, hotspots), prioritize by churn × pain rather than ugliness, and describe a safe facade-based extraction path.

for a principal

Frame it as portfolio management: which bottleneck classes throttle team throughput, what the split costs organizationally, and why layer-splitting without actor-splitting yields no change-isolation benefit.

## What a god class is A **god class** (also "blob", "god object") is a class that has absorbed responsibilities belonging to several distinct actors. It becomes the place every feature reaches for, so every feature's changes land in it. It is the flagship SRP violation. ## Reliable detection signals ### 1. Low cohesion (the strongest structural signal) **Cohesion** = how strongly a class's members belong together. Operationally: partition the methods by which fields they touch. If you get two or more clusters that share no fields, the class is really two classes stapled together. Metrics that formalize this are the **LCOM family** (Lack of Cohesion of Methods). *LCOM4*, the most usable variant, builds a graph where methods are nodes and an edge joins two methods if they touch a common field or one calls the other; the metric is the number of connected components. **LCOM4 = 1** means cohesive; **LCOM4 ≥ 2** literally means the class decomposes into that many independent parts. Treat metrics as a *search light*, never a verdict. ### 2. Dependency count / test setup pain Count constructor parameters and static/global calls. When a unit test needs eight fakes before it can assert one behavior, the class is coordinating several concerns. This is a cheap, honest signal because it is felt by everyone who writes a test. ### 3. Change frequency and change coupling (evidence from history) Mine version control: how many commits touch this file, and which other files change alongside it? A file appearing in commits from unrelated feature streams (billing, notifications, reporting) is serving multiple actors *empirically*, not theoretically. This technique is often called **behavioral code analysis**; "hotspot" = high churn × high complexity. ### 4. Naming that resists precision Names like `Manager`, `Processor`, `Helper`, `Util`, `Service`, `Controller` with a broad noun are placeholders for "assorted things". If you cannot name the class without "and", you cannot state a single responsibility for it. ### 5. Inbound coupling breadth Many *unrelated* packages/modules depending on it — a bottleneck through which unrelated concerns pass. ### 6. Feature envy / data-class pairing A god class is often flanked by anemic data holders whose fields it manipulates. If the logic for a data structure lives elsewhere, responsibility has drifted. ## Misleading signals - **Line count alone.** A 1,200-line hand-written lexer, a big exhaustive `switch` over one enum, or a state machine can be perfectly cohesive. Conversely a 60-line class calling three subsystems can be a miniature god class. - **Method count alone.** A `String`-like value type has dozens of methods and one responsibility. - **Generated / declarative code.** Mappers, DTOs, migrations, generated clients — size means nothing there. - **"It imports a lot."** Aggregation at a composition root (where the object graph is assembled) is legitimate. ## Turning a signal into a decision Signals only nominate candidates. Confirm with the SRP question itself: **for each cluster of methods, who asks for it to change?** Distinct requesters → real split. Same requester → probably just a big cohesive class; leave it. Then weigh cost: a god class that is stable (rarely edited) and well-tested is a poor refactoring target even if ugly. A moderately sized class edited weekly by three teams is a great one. **Prioritize by churn × pain, not by ugliness.** ## Common trap Splitting a god class purely by *technical layer* (`OrderValidator`, `OrderMapper`, `OrderRepository`, `OrderCalculator`) can leave every business change still touching four files — you traded one big edit for four small ones. Split by **reason to change** first; layer-splitting is a secondary, orthogonal concern.

  • You found a class with LCOM4 = 4. Should you split it into four classes?
    Not automatically. LCOM4 says it decomposes structurally into four parts; SRP asks whether those parts answer to different actors. Merge clusters that serve the same actor and change together, and only split where change sources genuinely differ.
  • How would you split a god class safely when it is widely referenced?
    Extract collaborators behind the existing class first (keep the old type as a thin facade delegating to the new parts), get tests around each extracted piece, then migrate call sites incrementally and finally shrink or delete the facade.

context