[Tell, Don't Ask] 물어보지 말고 시켜라
http://c2.com/cgi/wiki?TellDontAsk
주요 내용
- Shy Code를 작성하라.
- 어떤 객체로부터 정보를 가져와서 판단하지 말고 그 객체가 판단하도록 시키자.
- Command와 Query를 구분하자.
- Law of Demeter를 지키자.
메서드가 어디에 어느 클래스에 위치 해야 하는지에 대한 이야기인데, 가끔 코딩하다보면 이 코드가 여기 있어야 되는건지..저기로 가야하는건지 판단의 기준이 잘 서지 않을 때가 있는데 그럴 때 이 말을 떠올리면 도움이 될 것 같습니다.
public boolean confimMember(String email, String authCode) {
Member storedMember = repository.findByEmail(email);
if (storedMember == null) {
throw new UsernameNotFoundException(email + " 에 해당하는 사용자가 없습니다.");
}
boolean result = storedMember.getAuthCode().equals(authCode);
if (!result) {
throw new InsufficientAuthenticationException(authCode
+ " 인증 코드가 올바르지 않습니다.");
} else {
storedMember.join();
storedMember.makeAvatar();
addMemberRole(storedMember);
update(storedMember);
}
return result;
}
Member storedMember = repository.findByEmail(email);
if (storedMember == null) {
throw new UsernameNotFoundException(email + " 에 해당하는 사용자가 없습니다.");
}
boolean result = storedMember.getAuthCode().equals(authCode);
if (!result) {
throw new InsufficientAuthenticationException(authCode
+ " 인증 코드가 올바르지 않습니다.");
} else {
storedMember.join();
storedMember.makeAvatar();
addMemberRole(storedMember);
update(storedMember);
}
return result;
}
이 코드는 봄싹의 MemberServiceImpl 코드중 일부입니다. 즉 위와 같은 코드는 저 원칙에 위배되는 코드로 객체 지향적이지 못한 코드입니다. 객체 지향적인 코드라면 함수 호출이 아니라 어떤 작업을(method) 지시해야 합니다. 그런데 지금은 authCode를 가져와서 매개변수의 authCode와 같은지 판다하고 있지요. 바로 이 예제가 Tell, Don't Ask에서 지적하고 있는 대표적인 사례입니다.
boolean result = storedMember.isConfirmed(authCode);
이렇게 매개변수로 필요한 정보를 전달하고 결과를 돌려받으면 됩니다. 즉 isConfirmed()라는 Query 메서드를 사용해서 정보를 조회하면 됩니다. Command 메서드가 아니라 Query 메서드기 때문에 당연히 객체 내부 정보를 변경하지 않도록 주의해야 합니다. Command 메서드와 Query 메서드를 잘 구분하는 것이 저 원칙을 지키는 지름길입니다. 또한, 이렇게 하는 것이 '데메테르 법칙'을 지키는 일이기도 합니다. 최측근에게만 일을 시키게 되니까 말이죠.
단, 단점이 있는데 그건 바로. 저 상태로 끝나면 모를까. 그게 아니라 Member 클래스에 isConfirm() 메서드를 만들어 줘야 한다는 거죠. 만약 3중, 4중으로 건너 건너 요청하던 코드를 저 원칙에 따라 고친다면 그만큼 자잘한 코드들이 생길 겁니다.
그런 단점들 대신에 얻을 수 있는 장점으로 시스템 내부의 클래스간 의존도를 낮출 수 있다는 것입니다. 따라서 그 둘간의 저울질을 잘 하고 선택하시기를...
봄싹 코드는 이제 저 기준에 따라 모든 클래스의 코드를 리뷰하고 코드 뜯어고치기 작업을 진행합니다. 그게 끝나면 패키지 간의 의존성을 점검해봐야겠습니다.