skip to content

A code reviewer notices a class named AccountManager with a method processTransaction(), but in the requirements meeting for the same feature, domain experts kept saying 'wiring a payment' and 'posting to the ledger'. What design smell does this mismatch indicate, and what should the reviewer do about it?

level: seniorimportance: must knowfreq 58%

answer

  1. generic names (Manager/Processor/Handler) are a red flag
  2. name mismatch = leading indicator of model drift
  3. rename cheaply, but check if the shape is also wrong
  4. don't just relabel a structurally wrong class
  5. Smart UI / God-object Manager anti-pattern

basics

~20 s

The code's names don't match what the business actually says, which is a warning sign the design has drifted from the real domain. The reviewer should flag it and suggest renaming things to match the real terms, like Ledger.postPayment(), before the mismatch gets baked in further.

solid answer

~50 s

This is a language-mismatch smell — a leading indicator that the model has drifted from the domain, usually because early technical abstractions (generic words like Manager, Transaction, Processor) got adopted before anyone checked them against what domain experts actually say. Left alone, it compounds: new features get built against the wrong abstraction, onboarding engineers learn the wrong mental model, and eventually a costly rename-and-restructure is needed. A reviewer should treat this the same as a correctness bug — flag it in the PR, propose names that mirror the domain experts' actual words (e.g., Ledger.postPayment() instead of AccountManager.processTransaction()), and if the mismatch is deep (not just a name but a wrong shape, like one 'Transaction' class standing in for what's really two distinct domain events), raise it as a design conversation rather than a pure naming nit, since fixing only the label without fixing the model would just hide the smell.

go deeper

for a junior

Can notice that the names in the code don't match what people said in the meeting and flag it as odd; not expected to categorize it as a specific design smell or propose a fix strategy.

for a middle

Recognizes this as a naming/ubiquitous-language issue, proposes a rename in review, and can articulate why generic names like Manager or Processor are worth watching for.

for a senior

Distinguishes a pure naming fix from a deeper modeling problem, decides which one this is, and knows how to verify the distinction by going back to domain experts with a concrete question.

for a principal

Treats recurring instances of this smell across a codebase as a signal about process (e.g., engineers building features without domain-expert conversations) and addresses the root cause — team practice — not just the individual PR.

## Why generic names are a smell Generic, technical-sounding names are a well-documented anti-pattern in domain-driven design precisely because they're 'safe' words that any programmer can invent without ever talking to a domain expert: - `Manager` - `Handler` - `Processor` - `Transaction` - `Data` - `Info` - `Util` `AccountManager.processTransaction()` could describe almost any financial operation in almost any business; it carries no domain-specific meaning at all. When a reviewer notices that this generic vocabulary coexists with domain experts using specific, meaningful terms like 'wiring a payment' and 'posting to the ledger', the mechanism at fault is usually the same: the class was designed by an engineer working from a vague requirement, before or without a real conversation with someone who does this work for a living, and nobody has gone back to reconcile the two since. ## Why this matters beyond aesthetics Why this matters goes beyond aesthetics. Ubiquitous language exists so that the code is a reliable expression of the domain — so that a domain expert reading a test name, or an engineer reading a requirements doc, don't have to mentally translate between two vocabularies. A generic name like `processTransaction()` hides the actual domain operation behind an abstraction so broad it could be wrong in several different ways and nobody would notice from the name alone: - is this wiring a payment to an external bank, - posting an internal ledger entry, - or both as one atomic unit? The name gives no signal, which means the next engineer to touch this code has to read the implementation from scratch every time, and worse, might implement a similar-but-distinct concept (say, a refund) by copy-pasting and lightly modifying `processTransaction()`, further entrenching the wrong abstraction. ## The trade-off a reviewer weighs The trade-off a reviewer has to weigh is **scope of the fix versus cost of delay**. - **A pure rename** (`AccountManager` to `Ledger`, `processTransaction` to `postPayment`) is cheap — an IDE refactor and a re-review — and should almost always happen immediately, in the same PR if feasible, because renames only get more expensive as more code depends on the old names. - **But sometimes the mismatch is a symptom of a deeper modeling error**: 'processTransaction' might actually need to become two distinct operations, `postPayment` and `reverseChargeback`, because domain experts treat them as different things with different rules, and squeezing both into one generic method is itself the design smell. Fixing only the label in that case is worse than doing nothing, because it makes the smell invisible — the class now sounds domain-accurate while still being structurally wrong underneath. A senior reviewer's job is to tell these two cases apart: is this a naming fix, or does the name reveal that the shape of the model itself needs to split or merge? ## How it shows up in production In production, unresolved language-mismatch smells show up as a specific failure pattern: - **new features consistently take longer than expected to build correctly**, because engineers keep misinterpreting what a generically-named class is actually for, and bugs cluster around code where the implementation's real behavior has quietly diverged from what its name implies (e.g., `processTransaction()` started as 'debit an account' but through incremental feature work now also silently handles refunds, chargebacks, and fee assessments, none of which a caller would guess from the name); - **another common symptom is that onboarding new engineers takes disproportionately long**, because the class and method names actively mislead rather than help; new hires have to be told 'don't trust the names, read the code', which defeats the entire purpose of naming. ## The documented anti-pattern and its fix A well-known real-world pattern for this is the DDD 'Smart UI anti-pattern' and its cousin, the generic 'God object' `Manager` class — both are documented failure modes in Eric Evans's original work and in subsequent DDD literature (e.g., Vaughn Vernon's *Implementing Domain-Driven Design*) precisely because `Manager/Processor/Handler` classes are a magnet for unrelated behavior once they exist, since any new requirement can plausibly be bolted onto something with such a generic name. The fix pattern is consistent across sources: 1. go back to the domain experts, 2. find out what they actually call the operation and why they distinguish the cases they distinguish, 3. and let the class and method names — and often the class boundaries themselves — mirror that distinction directly, so `AccountManager.processTransaction()` becomes something like `Ledger.postPayment(PaymentInstruction)` as a first pass, with a follow-up design conversation about whether payment posting and chargeback reversal deserve to be separate operations entirely.

  • Is every generically-named class automatically a problem?
    Not automatically — some concepts genuinely are generic infrastructure (a retry Handler, a logging Processor) that domain experts never talk about at all, and forcing a domain-specific name onto pure technical plumbing is overcorrection. The smell specifically applies when the class represents domain behavior that domain experts do have specific language for, and the code's name ignores that language.
  • How would you actually verify that 'wiring a payment' and 'posting to the ledger' are meaningfully different operations rather than just two ways of saying the same thing?
    Ask the domain experts directly, ideally with a concrete example: does a payment ever get wired without a ledger post, or vice versa, and if a wire fails partway through, what happens to the ledger entry? If the answers reveal different triggers, different failure handling, or different actors responsible, they're distinct domain concepts and likely deserve separate methods or even separate aggregates; if the answers show they always happen together atomically with identical rules, one method with a name reflecting the combined step may be accurate.
  • What's the cheapest first step a reviewer can take without blocking the PR on a full redesign?
    Leave the rename as a required change (Ledger/postPayment instead of AccountManager/processTransaction) since that's low-cost and safe to do immediately, but open a separate, non-blocking design discussion or ticket about whether the operation should actually be split, so the team doesn't let a real modeling question get lost while also not holding up unrelated work waiting for a full redesign.

Like a hospital chart that labels every kind of care 'Patient Processing' instead of 'administering medication', 'drawing blood', or 'discharge planning' — the vague label doesn't just look sloppy, it hides which specific, differently-regulated procedure actually happened, and someone reading the chart later can't tell without re-reading every note.

saying these in an interview costs you the question

  • Treats the mismatch as purely cosmetic, not worth blocking a PR over
  • Suggests renaming without checking whether the underlying class shape is also wrong
  • Can't explain why 'Manager'/'Processor'/'Handler' names are a specific warning sign in DDD
  • Assumes domain experts should learn to use the code's technical terms instead
  • Never proposes going back to talk to domain experts to resolve the ambiguity

context