데이터 요청을 그만! “Tell, Don't Ask” 원칙 마스터하기
발행: (2025년 12월 19일 오전 09:57 GMT+9)
4 min read
원문: Dev.to
Source: Dev.to
소개
객체‑지향 프로그래밍(OOP)에서 가장 흔한 실수 중 하나는 객체를 단순한 데이터 구조처럼 다루는 것입니다. 우리는 종종 객체에서 데이터를 꺼내 로직을 수행한 뒤 결과를 다시 넣습니다. 이 글에서는 Tell, Don’t Ask (TDA) 원칙을 설명하고, 간단한 Shop과 Account 예제를 통해 코드가 어떻게 개선되는지 보여줍니다.
Tell, Don’t Ask 원칙
- 묻지 말라(Don’t Ask): 로직을 직접 수행하기 위해 객체에게 데이터를 요청하지 말라.
- 말하라(Tell): 객체에게 무엇을 해야 할지 알려주고, 객체가 자신의 상태를 스스로 처리하도록 하라.
TDA를 따르면 **캡슐화(encapsulation)**와 **응집도(cohesion)**가 향상됩니다.
안티패턴 예시
Shop 클래스가 Account에 속해야 할 로직을 관리함으로써 캡슐화를 위반하고 있습니다.
package com.mateandgit.programming.chapter1_2.problem;
public class Shop {
public void sell(Account account, Product product) {
// ❌ BAD: Asking for data (getMoney)
long price = product.getPrice();
long mileage = account.getMoney();
// ❌ BAD: The Shop decides if the account has enough money
if (mileage >= price) {
// ❌ BAD: Modifying the account's state externally
account.setMoney(mileage - price);
System.out.println(product.getName() + " purchased.");
} else {
System.out.println("Insufficient balance.");
}
}
}
문제점
- 캡슐화 위반 –
Shop이Account의 내부 상세(예:money필드와 잔액 계산 방식)를 알고 있습니다. - 로직 중복 – 돈을 차감해야 하는 다른 클래스는 모두
if (balance >= price)검사를 중복해야 합니다. - 유지보수 어려움 – 검증 규칙(예: “최소 잔액은 100이어야 함”)을 변경하면
Account에 접근하는 모든 클래스에서 업데이트가 필요합니다.
리팩터링된 해결책
로직을 Account 클래스로 옮깁니다. 이제 Shop은 Account에 명령만 내립니다.
package com.mateandgit.programming.chapter1_2.solution;
public class Shop {
public void sell(Account account, Product product) {
// ✅ GOOD: Ask a question (canAfford)
if (account.canAfford(product.getPrice())) {
// ✅ GOOD: Tell the object to do something (withdraw)
account.withdraw(product.getPrice());
System.out.println(product.getName() + " purchased.");
} else {
System.out.println("Insufficient balance.");
}
}
}
Account 클래스 안에는 canAfford()와 withdraw()와 같이 로직을 캡슐화한 메서드가 존재합니다.
리팩터링의 장점
- 향상된 캡슐화 –
Shop은 인출이 어떻게 이루어지는지 알 필요가 없으며, 단지 메시지를 보냅니다. - 재사용 가능한 로직 – 검증 규칙(
canAfford)이Account에 집중되어 있습니다. - 가독성 – 코드가 “계정이 충분히 있으면 인출한다”는 문장처럼 읽힙니다.
- 높은 응집도와 낮은 결합도 – 객체가 자신의 상태를 관리하므로 코드가 더 깔끔하고 유지보수가 쉬워집니다.
Tell, Don’t Ask 적용하기
- 하지 말아야 할 것:
getSomething() → calculate → setSomething(). - 해야 할 것: 객체 안에 메서드를 만들고 그것에게 동작을 말해 주기.
결과: 높은 응집도, 낮은 결합도, 그리고 더 나은 캡슐화.