데이터를 묻는 것을 멈춰라! ‘Tell, Don't Ask’ 원칙을 마스터하라
Source: Dev.to
소개
객체지향 프로그래밍(OOP)에서 가장 흔한 실수 중 하나는 객체를 단순한 데이터 구조처럼 다루는 것입니다. 우리는 종종 객체에서 데이터를 꺼내어 로직을 수행한 뒤 결과를 다시 넣습니다. 이 글에서는 Tell, Don’t Ask (TDA) 원칙을 설명하고 간단한 Shop과 Account 예제를 통해 코드가 어떻게 개선되는지 보여줍니다.
Tell, Don’t Ask 원칙
- 묻지 말라: 객체에게 데이터를 요청해 직접 로직을 수행하지 마세요.
- 지시하라: 객체에게 무엇을 해야 할지 알려주고, 객체가 스스로 상태를 관리하도록 하세요.
TDA를 따르면 캡슐화와 응집도가 향상됩니다.
안티패턴 예시
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(). - 할 것: 객체에 메서드를 만들고 지시하여 동작을 수행하게 합니다.
결과: 높은 응집도, 낮은 결합도, 그리고 향상된 캡슐화.