What is the Tell, Don’t Ask Principle?
Learn the Tell, Don’t Ask OOP principle — avoiding ask-then-mutate anti-patterns — with a Java before/after example.
Expected Interview Answer
Tell, Don’t Ask is the object-oriented design guideline that you should tell an object what to do by calling a method that performs the behavior internally, rather than asking it for its internal data via getters and then making decisions and mutating state from outside the object.
The anti-pattern it corrects is the “anemic” style: calling account.getBalance(), checking it externally, then calling account.setBalance(newValue) — logic that rightfully belongs inside the Account class leaks out and gets duplicated everywhere the check is needed, and invariants are no longer guaranteed by the object itself. Tell, Don’t Ask instead has the caller say account.withdraw(amount), letting Account internally check sufficient funds and update its own balance atomically. This keeps behavior colocated with the data it operates on, which is the essence of encapsulation, and prevents the same validation logic from drifting out of sync across multiple call sites. It is not absolute — read-only queries for display or reporting purposes are legitimate uses of “ask” — but any decision that changes an object’s state based on its own data should live inside that object.
- Keeps validation and business rules colocated with the data they protect
- Prevents duplicated, drifting logic across multiple call sites
- Strengthens real encapsulation instead of exposing raw getters/setters
- Makes objects responsible for their own consistency (fewer anemic classes)
AI Mentor Explanation
Instead of a captain asking the physio “what is the player’s exact fitness percentage?” and then deciding themselves whether to substitute, a well-run team tells the physio “clear this player for the field or not” — the physio, who has all the relevant data, makes the call internally and reports only the decision. Tell, Don’t Ask works the same way in code: you tell the object to perform an action (clearForPlay()) rather than asking it for raw data (getFitnessPercent()) and deciding externally, keeping the decision logic where the data actually lives.
Step-by-Step Explanation
Step 1
Spot the anti-pattern
Find code that calls a getter, checks/computes on the result, then calls a setter to write back — logic that belongs inside the object.
Step 2
Move the decision into the object
Add a behavior method (e.g. withdraw(amount)) that performs the check and the state change internally.
Step 3
Replace the ask-then-act call site
Callers now invoke the single behavior method instead of extracting data and mutating externally.
Step 4
Keep legitimate queries as queries
Read-only display or reporting getters remain fine — Tell, Don’t Ask targets decisions that change state.
What Interviewer Expects
- A clear before/after example distinguishing ask-then-mutate from tell
- Understanding that this strengthens encapsulation, not just style preference
- Recognition of the “anemic domain model” anti-pattern it corrects
- Awareness that read-only queries for reporting are still legitimate
Common Mistakes
- Treating Tell, Don’t Ask as “never call a getter,” which is too extreme
- Leaving validation logic duplicated at every call site instead of moving it into the object
- Confusing this principle with encapsulation itself rather than seeing it as a corollary practice
- Applying it to pure read/reporting use cases where asking is appropriate
Best Answer (HR Friendly)
“Tell, Don’t Ask means you should instruct an object to perform an action using a method — like withdraw(amount) — instead of pulling its data out with getters, deciding what to do outside the object, and then writing the result back in with a setter. It keeps the decision logic next to the data it depends on, so the same validation doesn’t end up duplicated and drifting across the codebase.”
Code Example
class Account {
private double balance;
Account(double balance) { this.balance = balance; }
// "Ask" style exposes raw data, forcing callers to duplicate logic:
double getBalance() { return balance; }
void setBalance(double value) { this.balance = value; }
// "Tell" style: caller commands behavior, object owns the decision
void withdraw(double amount) {
if (amount <= 0 || amount > balance) {
throw new IllegalArgumentException("Invalid withdrawal");
}
balance -= amount;
}
}
// Anti-pattern: ask, decide externally, then write back
Account acc = new Account(100);
if (acc.getBalance() >= 40) {
acc.setBalance(acc.getBalance() - 40); // logic leaked outside the class
}
// Tell, Don’t Ask: command the object, it protects its own invariant
acc.withdraw(40);Follow-up Questions
- What anti-pattern does Tell, Don’t Ask correct?
- Is it ever acceptable to call a getter under Tell, Don’t Ask? When?
- How does Tell, Don’t Ask relate to the anemic domain model anti-pattern?
- How does this principle strengthen encapsulation compared to plain getters/setters?
MCQ Practice
1. Tell, Don’t Ask primarily discourages which pattern?
The principle targets ask-then-mutate call sites, where decision logic that belongs inside the object leaks out to the caller.
2. Under Tell, Don’t Ask, which is the preferred call for a withdrawal?
Calling withdraw(amount) lets the object validate and update its own state internally, rather than the caller computing and writing the new value.
3. Is calling a read-only getter for a report ever acceptable under this principle?
Tell, Don’t Ask targets ask-then-mutate decisions, not legitimate read-only queries used for display or reporting.
Flash Cards
Tell, Don’t Ask in one line? — Instruct an object to perform behavior internally, rather than pulling its data out to decide and mutate externally.
Anti-pattern it corrects? — Ask-then-mutate: getter, external decision, setter — leaking logic out of the class.
Still acceptable under this principle? — Read-only queries for display/reporting that don’t drive an external mutation.
Related design smell? — The anemic domain model, where objects hold data but no behavior.