달력

032010  이전 다음

  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  
주말에 랄프 존슨 특강에 참석했다. 프로젝트 초기라 바쁜 와중에 맞이하는 주말인데 굳이 유명인사 특강에 참석해야 할까 싶은 생각을 안고 자리에 나갔다. 아마도 특강 개설 과정에 참여하지 않았으면 그 자리에 있진 않았을 것이다.

랄프 존슨 특강을 듣기 시작한 지 얼마 지나지 않아 생각이 바뀌었다. 기름기가 잔뜩 꼈던 정신상태에 경종을 울렸다. 먼저 두 가지 사항을 반성했다.

  • 영어에 자유로워지겠다고 결심했지만, 실제 행동은 그렇지 못했다.
  • 디자인 패턴에 대해 충분히 안다고 생각했는데, 사실 아무것도 모르는 사람과 별반 다르지 않음을 느꼈다.
내 블로그가 반성을 위한 일기 역할을 하지만, 방문객을 고려해서 반성은 그만두겠다. 짧은 영어 실력 탓에 대가의 특강을 충분히 소화하지 못했다. 그럼에도 화학반응을 통해 영감을 얻어 쏟아진 생각을 메모할 겸 공유하고자 한다.

1강: Fifteen Years of Design Patterns
베스트셀러인 GoF 디자인 패턴. 실제 발표는 94년 OOPSLA인데 출간은 95년이다. 이유가 무엇일까? 출판업자는 우리나라와 다르지 않았다. 연초에 출간해야 매출에 유리하기 때문에 해를 넘겨 책을 볼 수 있었다. 후속으로 쏟아진 관련 서적이 매우 많다. 랄프는 그중에서 4권을 꼽았다. 그 중 두 권에 대한 논평이 인상깊다. 하나는 그 유명한 헤드 퍼스트 시리즈다. 헤드 퍼스트는 자신의 책보다 더 많이 팔렸다며 미소를 지었다. 그리고, 헤드 퍼스트의 독특한 전개 방식에 대해 높이 평가했다. 두 번째는 에릭 에반스의 DDD에 대한 평이다. 랄프는 크리스토퍼 알렉산더를 글 잘 쓰는 사람으로 평가했다. 그리고 컴퓨터 과학과 건축(building)은 다르다고 이야기했다. DDD는 알렉산더류에 가까우면서 매우 독창적인(very unique) 책이라는 점을 강조했다.

책 소개 이후에는 디자인 패턴 자체에 대해 설명했다. 디자인 패턴을 고급(advanced) 객체지향 프로그래밍 전형으로 소개한 점이 인상적이었다. 객체지향에선 보통 명사는 객체이고, 동사는 행위이다. 그런데 고급이란 표현은 일반적(not normal)이 아니란 의미다. 예를 들어 Strategy는 알고리즘인데, 함수가 아니라 객체로 존재한다. 뒤이어 스스로 코어라 정의한 14개 패턴을 나열했다.
  • Composite
  • Strategy
  • Decorator
  • State
  • Iterator
  • Observer
  • Value Object
  • Mediator
  • Facade
  • Proxy
  • Command
  • Template Method
  • Adapter
  • Null Object (Exceptional Object)
기울임체로 표기한 두 개 패턴은 GoF 책에는 없던 내용이다. Value Object에 대해서는 DDD에서 제대로 설명한 바 있다. 랄프가 그 이야기를 해서 반가웠다. 2판에서는 (Data) Transfer Object로 고쳤지만, 단순히 데이터 운반 수단으로만 쓰였던 Core J2EE Patterns에서 Value Object라고 작명한 내용은 틀렸다고 말했다. 그래서, 본인과 Kent Beck(Implementation Patterns 28쪽), Martin Fowler 각각 스스로 Value Object를 정의했다고 한다. 셋 모두 수긍할 수 있었던 Value Object에 대한 정의는 Eric Evans의 DDD에 나온 설명이라고 한다. :)

주로 언급한 패턴에 대해 기억에 남는 내용을 메모한다.
  • Composite
컴포넌트를 종국에는 종단(Leaf)과 복합체(Composite)로 나누어 이분법의 강력함을 활용할 수 있다는 점이 눈에 띄었다. 하지만, 핵심은 복합체와 구성요소(Component) 모두가 정확하게 같은 인터페이스를 갖는다는 점이다.
  • Strategy
알고리즘을 (일반적인 경우와 달리) 객체에 담았다. Strategy에 대해선 바로 설명하지 않고, 발표자료에서도 상당한 지면을 할애해 깊이 있게 다뤘다.
  • Observer
Subject의 하위 클래스는 Observer 수에 무관하게 자기 일만 충실할 수 있다. 스타크래프트에서 선수가 Observer를 신경 쓰지 않고 자기 플레이만 하듯이 말이다.

그리고 위험한 패턴으로 Mediator와 Singleton을 언급했다. 많은 사람이 잘못 사용하면서, 나쁜 패턴이라 칭하는 데 대해 일침을 가했다. Mediator는 반드시 재사용을 전제로 해야 하며, 종종 데이터와 코드를 구분하는 우를 범하기 쉬운 패턴이다. 싱글턴을 써야 하는 경우를 명확하게 정의해줬다.

encapsulate global state when it cannot be eliminated

코어에 이어서 생성 패턴을 열거했다.
  • Abstract factory (peripheral)
  • Factory method
  • Prototype
  • Builder
  • Singleton
  • Dependency Injection
스프링 사용자인터라 Dependency Injection 등장이 반가웠다. 랄프 존슨은 Dependency Injection에 대해서 의존성을 객체 외부에 보존해(Keep dependencies out)서 생기는 DI의 이점에 대해 짧은 말로 명쾌하게 설명했다. 그 외 보조(peripheral) 패턴을 7개로 분류했다.
  • Memento
  • Chain of responsibility
  • Bridge
  • Visitor
  • Type Object
  • Extension Object
  • Generation Gap
Type Object에 대한 활용은 놀라움이었다. 패턴에 대한 나의 무지를 혁혁하게 보여주었다. 랄프는 Visitor에 대해 "Cool"이라는 극찬을 감추지 않았다. 다형성을 지켜주는 보석 같은 존재로 설명했다. Extension Object를 설명할 때는 Eric Gamma와 이클립스를 예로 들었다.

마지막 카탈로그로 복합(Compound) 패턴을 두 개 꼽았다.
  • Flyweight
  • Interpreter
Flyweight를 설명하면서 flyweight pool을 활용해서 flyweght 객체를 만들어주는 클래스를 Memorizing Factory라 명명했다. 퍼뜩 떠오르는 녀석이 Bean Factory다. 이에 대해서는 더 고민해봐야 할 듯하다. 1강의 전반부는 여기까지다. 대가에 대한 존경심과 반성을 불러온 놀라운 강의는 후반부 Patterns in Business Software에 대한 설명이다. 그 내용은 짤막한 메모로 내가 받은 놀라운 인상을 전해줄 수 있을까 싶기도 하고, 너무 긴 글에 지쳐서 다음으로 미루겠다. 긴 글이나 예제를 시도할 수도 있어 포스트로 정리하지는 않을지 모르겠다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 영회
다음과 같은 코드가 있다.

score += 10 + rolls[frameIdx + 1] + rolls[frameIdx + 2];

rolls[frameIdx + 1] + rolls[frameIdx + 2] 부분을 메소드로 뽑아내고자 한다. 이클립스에서 블록 지정을 하고 Alt+Shift+M 단축키를 누르면, 다음과 같은 메시지를 만날 수 있다.

Can only extract a single expression or a set of statements.[각주:1]

두 가지 해결책이 있다. 하나는 굳이 이클립스 명령을 쓰지 않는 방법이다. 다른 방법은 블록 지정 부분을 괄호로 묶고 나서 Extract Method 명령을 수행하는 방법이다.

score += 10 + (rolls[frameIdx + 1] + rolls[frameIdx + 2]);

결코, 빠른 방법은 아니지만 몇 가지 사소한 이점이 있다.
  • 타이핑 절감
  • 오타 방지
  • 자동 줄맞춤
  • inline 리패토링하면 다시 제거 가능



  1. 젠장. 보안 툴 탓에 이미지 파일을 못 올린다. [본문으로]
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 영회
사용자 삽입 이미지
디렉터리 정리를 하려는데 리팩터링(Refactoring)이 떠올랐다. 우선 Kent Beck를 인용해보자.

The goal is clean code that works. [...] First we'll solve the "that works" part of the problem. Then we'll solve the "clean code" part. This is the opposite of architecture-driven development, where you solve "clean code" first, then scramble around trying to integrate into the design the things you learn as you solve the "that works" problem.

마치 정리하지 않은 디렉터리처럼 코드 역시 마냥 필요에 따라 고쳐가도 작동(works)한다. 그러나 애초부터는 고사하고 시간이 지나고 깨끗이(clean) 정리하지 않으면 작동을 하더라도 유지하기 어렵다. 4개월 넘게 디렉터리 정리 없이 즉흥적으로 썼더니 파일이 중복으로 존재한다. 4개월간 쌓인 파일을 새로운 기준으로 정리하려니까 만만치 않다. 무슨 일이든 작동과 정리(간결히 하기) 사이는 짧을수록 좋다.
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 영회
“In order to do Scrum or XP or any form of Agile successfully, you must refactor. Sorry, not optional. Necessary.”

We must evolve the infrastructure. It’s not a rule, it’s worse. It’s essentially a law of nature.

Ron Jeffries의 촌철살인이다. 요즘 공개한 API를 다시 돌아보면서, 온 힘을 다해 정제하지 않은 과거가 부끄러웠다. 의기소침해진 나에게 '그러면서 배우는 것이야.'라고 격려하는 듯하다.

어느 시점에서든 최고의 코드를 만들자고 눈에 불을 켜고 검토하고 수정해도 최고일 순 없었을 것이다. 적절한 간격으로 영리하고 기민하게 일을 하지 못했을 뿐이다. [각주:1]
  1. 의지가 부족해 게을리 보냈던 시간이 있었음이야 물론 말할 필요도 없다. [본문으로]
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 영회
public abstract String findByDong(String dong);

반환값이 String이었는데 여러 개의 객체 배열로 반환받고 싶다. 그리고, static 메소드로 변경하고 싶다. 이럴 때도 이클립스 리팩토링 기능을 이용할 수 있다. 편집기에서 메소드 부분(주석 포함)을 선택하거나 패키지 탐색기에서 메소드를 선택하고 오른쪽 마우스를 누른다.


Alt+Shift+C 조합키를 단축키로 사용할 수 있음을 알 수 있다.


접근 지정자, 반환값 유형, 매개변수, 예외, 메소드 이름 등 모든 것을 바꿀 수 있다. ^^; 아쉽게도 static 은 여기서 부여할 수 없다. 변경을 적용하기 전에 Preview 버튼을 선택하면 미리 보기를 통해 변경되는 부분을 확인할 수 있다.


인터페이스와 이를 구현한 클래스에 적용이 미침을 알 수 있고, 코드 비교를 통해 구체적으로 어떻게 바뀌는지 확인할 수 있다.

원문 작성 일시: 2004/11/19 (금) 13:57
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 영회
리팩토링 카다로그에 보면 Extract Interface가 있다.
Several clients use the same subset of a class's interface, or two classes have part of their interfaces in common.

동일한 클래스 인터페이스(public method)를 여러 클라이언트가 공유하는 경우, 혹은 두 개 이상의 클래스가 동일한 인터페이스를 공통으로 갖고 있는 경우 이를 인터페이스를 뽑아낸다.




이클립스에서 이러한 기능을 지원해준다. 물론, 도와주는 것이지 판단은 사람의 몫이다. ^^;
아래와 같은 코드가 있다고 하자.

public class ZipcodeInDB {
  public String findByDong(String dong){
      
       return "";
      
  }
}

내용은 없지만, findByDong이 다른 클래스에도 있을 수 있어, Zipcode라는 인터페이스를 만들어보겠다. 패키지 탐색기에서 ZipcodeInDB를 선택하고 오른쪽 마우스를 누르면, Refactor > Extract Interface 라는 메뉴를 선택할 수 있다.


Interface name란에 원하는 인터페이스(자바 Inteface) 이름을 넣고, 인터페이스에 포함시킬 메소드를 선택한다. 가장 상당은 옵션은 현재 ZipcodeInDB라는 클래스를 참조하는 코드에서 ZipcodeInDB 대신에 Zipcode 타입으로 참조하게 하고자 할 때 선택한다.


이렇게 하면, 당연히 코드에 변경이 일어나야 한다. 확인해보자.

public class ZipcodeInDB implements Zipcode
ZipcodeInDB에는 "implments Zipcode" 부분이 추가되었고, 인터페이스 코드는 새로 생성되었다.

public interface Zipcode {
  public abstract String findByDong(String dong);
}

인터페이스를 외부에 공개하기 위해서 패키지를 변경하겠다. 이때는 코드를 직접 수정하는 것보다 역시 이클립스에서 제공하는 리팩토링 기능을 확용하는 것이 좋다. Refactor > Move 메뉴를 통해 패키지를 변경하게 되면, 인터페이스를 참조하는 기존 코드의 패키지 명시부분이 모두 자동으로 바뀐다. 옮기고자 하는 패키지가 이미 존재할 경우에는 패키지 탐색기에서 인터페이스를 단순히 드래그 앤 드롭하는 것으로도 동일한 작업이 가능하다.


원문 작성 일시: 2004/11/19 (금) 13:27
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 영회
Spring을 사용하다 보면 협업 객체의 IoC 기능 활용을 위해 setter가 요구된다.
public class ArticleListController extends AbstractController{
private ArticleLinkDao articleLinkDao;

@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
...
}

public void setArticleLinkDao(ArticleLinkDao articleLinkDao) {
this.articleLinkDao = articleLinkDao;
}
}

그런데 이러한 클래스가 또 만들어야 한다고 가정해보자. 중복이 발생한다.
public class ThemePageController extends AbstractController{
private ArticleLinkDao articleLinkDao;

@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
...
}

public void setArticleLinkDao(ArticleLinkDao articleLinkDao) {
this.articleLinkDao = articleLinkDao;
}
}

중복을 막기 위해서 BaseController를 만들어 이들을 상속하게 하자.

1. AbstractController -> BaseController로 변경
public class ArticleListController extends BaseController{
private ArticleLinkDao articleLinkDao;

@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
...
}

public void setArticleLinkDao(ArticleLinkDao articleLinkDao) {
this.articleLinkDao = articleLinkDao;
}
}

2. 빠른 수정(Quick fix)으로 BaseController 생성


BaseController가 AbstractController를 상속해야 함을 잊지 말자.

3. Refactor > Pull up... 메뉴 선택


상위 클래스로 올릴 속성과 메소드를 선택한 후에 Finish 혹은 Next를 눌러서 미리보기를 하고 Finish.
리팩토링을 하고 나면 기분까지 개운(?)해진다. ^^;

4. BaseController 변경
public abstract class BaseController extends AbstractController {
protected ArticleLinkDao articleLinkDao;
@Override
abstract protected ModelAndView handleRequestInternal(HttpServletRequest request,
  HttpServletResponse response) throws Exception;
public void setArticleLinkDao(ArticleLinkDao articleLinkDao) {
this.articleLinkDao = articleLinkDao;
}
}

BaseController를 abstract로 만들어 반드시 handleRequestInternal을 구현하게 하고, 매개변수 이름을 request, response과 같이 보다 의미있게 바꿔주는 센스를 발휘하면, 마법사 혹은 빠른 수정으로 상속 객체를 생성할 때 이를 그대로 사용하게 된다. ^^
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 영회