Whiteship's Note


[Tell, Don't Ask] 물어보지 말고 시켜라

Design Pattern : 2010.04.07 15:51


http://c2.com/cgi/wiki?TellDontAsk
http://www.pragprog.com/articles/tell-dont-ask
http://www.ccs.neu.edu/research/demeter/related-work/pragmatic-programmer/jan_03_enbug.pdf

주요 내용
- 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; }
이 코드는 봄싹의 MemberServiceImpl 코드중 일부입니다. 즉 위와 같은 코드는 저 원칙에 위배되는 코드로 객체 지향적이지 못한 코드입니다. 객체 지향적인 코드라면 함수 호출이 아니라 어떤 작업을(method) 지시해야 합니다. 그런데 지금은 authCode를 가져와서 매개변수의 authCode와 같은지 판다하고 있지요. 바로 이 예제가 Tell, Don't Ask에서 지적하고 있는 대표적인 사례입니다.

boolean result = storedMember.isConfirmed(authCode);

이렇게 매개변수로 필요한 정보를 전달하고 결과를 돌려받으면 됩니다. 즉 isConfirmed()라는 Query 메서드를 사용해서 정보를 조회하면 됩니다. Command 메서드가 아니라 Query 메서드기 때문에 당연히 객체 내부 정보를 변경하지 않도록 주의해야 합니다. Command 메서드와 Query 메서드를 잘 구분하는 것이 저 원칙을 지키는 지름길입니다. 또한, 이렇게 하는 것이 '데메테르 법칙'을 지키는 일이기도 합니다. 최측근에게만 일을 시키게 되니까 말이죠.

단, 단점이 있는데 그건 바로. 저 상태로 끝나면 모를까. 그게 아니라 Member 클래스에 isConfirm() 메서드를 만들어 줘야 한다는 거죠. 만약 3중, 4중으로 건너 건너 요청하던 코드를 저 원칙에 따라 고친다면 그만큼 자잘한 코드들이 생길 겁니다. 

그런 단점들 대신에 얻을 수 있는 장점으로 시스템 내부의 클래스간 의존도를 낮출 수 있다는 것입니다. 따라서 그 둘간의 저울질을 잘 하고 선택하시기를...

봄싹 코드는 이제 저 기준에 따라 모든 클래스의 코드를 리뷰하고 코드 뜯어고치기 작업을 진행합니다. 그게 끝나면 패키지 간의 의존성을 점검해봐야겠습니다.

'Design Pattern' 카테고리의 다른 글

[OOAD] 객체지향 원칙 1. SRP  (2) 2010.05.07
[Tell, Don't Ask] 물어보지 말고 시켜라  (8) 2010.04.07
Visitor 패턴  (2) 2010.03.12
Holub on Pattern 좋은데요~  (4) 2008.12.07
프로토타입 패턴(Prototype Pattern)  (2) 2008.10.31
데코레이터(Decorator) 패턴  (0) 2008.10.01
프록시(Proxy) 패턴  (0) 2008.09.26
JUnit 공부하자.  (0) 2008.09.01
H.F.OOAD 5장 문제  (0) 2007.11.20
상위 클래스 보다는 인터페이스를...  (4) 2007.08.31
Singletons and lazy loading  (2) 2007.01.27
top

  1. Favicon of http://toby.epril.com BlogIcon 토비 2010.04.07 17:56 PERM. MOD/DEL REPLY

    1. ask는 물어보지 말라는 얘기가 아니라 데이터를 요청하지 말라는 것.
    2. result가 false면 예외인데 리턴은 또 머하러 하나. 결과를 전달하는 방법을 하나로 결정할 것.
    3. confirm 작업이 목적이라면 아예 storedMember에 confirm() 메소드를 만들고,
    confirm시 하는 storedMember의 내부 작업(아래 두 줄)은 그 안에서 하도록 하는게 더 나을 듯
    storedMember.join();
    storedMember.makeAvatar();
    InsufficientAuthenticationException 예외도 거기서 발생시키고.

    4. 전반적으로 메소드 작업의 추상화 레벨이 산만하고, 뭐하는 용도인지도 불분명 한 듯.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.04.07 19:22 신고 PERM MOD/DEL

    1. 데이터 요청 -> 물어보다. 로 매핑하기엔 좀 그런가요 흠.. 전 어울리다고 생각했는데.. @_@;

    2. 헐.. 그렇네요;; false를 리턴하던지 Member에서 예외를 던지던지 할껄;;

    3. 오호. 그게 좋겠습니다.

    4. 넵.

    Favicon of http://toby.epril.com BlogIcon 토비 2010.04.07 19:49 PERM MOD/DEL

    다시 만든 isConfirmed()도 물어보는 거자나.

    Favicon of http://whiteship.me BlogIcon 기선 2010.04.07 21:46 PERM MOD/DEL

    그럼 원제에 Tell, Don't Ask (data for making decisions) 라고 써줬으면 좀 더 명확했을텐데; Query 메서드 이야기를 봐서는 isConfirmed() 같이 물어보는건 괜찮지 않을가요?

    글 내용들이 아주 물어보지 말라는것도 아니면서 원제를 일부러 (짧게 쓰려고) 저렇게 지은 듯.

    저는 단지 원제에 충실하게 번역했을 뿐이라는.. @_@

  2. Favicon of http://toby.epril.com BlogIcon 토비 2010.04.07 17:58 PERM. MOD/DEL REPLY

    아래 부분은 repository내 데이터 로직으로 만들어도 될 듯. findRequestedMember... 어쩌고.

    if (storedMember == null) {
    throw new UsernameNotFoundException(email + " 에 해당하는 사용자가 없습니다.";);
    }

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.04.07 19:22 신고 PERM MOD/DEL

    그부분도 역시 위치가 영 아니였군요. 그러고보니 정말 Repository 쪽이 더 어울립니다.

  3. Favicon of http://toby.epril.com BlogIcon 토비 2010.04.07 17:58 PERM. MOD/DEL REPLY

    스프링 책 5장 1절 참고 해보면 좋을 듯.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.04.07 19:23 신고 PERM MOD/DEL

    그러니까 어서 달려주세요!! 꼬고고!!

Write a comment.