[독후감]Extreme Programming – 켄트 벡

최범균님의 추천으로 Extreme Programming 책을 처음 접하게 되었다.

전부터 계속 Agile 방법론에 대해 궁금해하고 있던 찰나에 만나게 된 단비같은

책이다.

extreme programming

책을 읽기 시작한 후 부터는 손에서 놓을 수 없을 정도로 강한 흡입력을 보여준 책이다.

특히나 개인적으로 인상깊었던 부분은, XP 기본 실천방법 중 “짝 프로그래밍“과

10분빌드“의 조합이다.

둘이서 짝 프로그래밍을 하고 10분동안 전체시스템을 빌드하고 모든 테스트를 돌리는

그 10분이라는 시간동안 번갈아가면서 작업했던 내용들을 서로 대화하는 가운데

복기하고, 그 속에 서로 상대방에게 배우면서 성장해가는 모습을 머릿속에 그려보는 것은

생각만으로도 굉장히 매력적이고 유쾌한 일이었다.

물론, 서로간의 열정이 비슷하고 짝 프로그래밍을 하는데 부담을 느끼지 않아야 한다는

전제조건이 있어야 하겠지만 말이다.

짝 프로그래밍“을 한번도 경험해보지 않은 나로서도 처음엔 당연히 거부감이 있을 것

같지만, “짝 프로그래밍“에 저런 매력이 있다면 한번쯤 즐거운 마음을 가지고

도전해 보는것도 의미있는 일이 아닐까 생각해 보았다.

아니, 그런 환경을 만들고 도전해보고 싶은 마음이 이 책을 읽으면서 생겼다.

그 만큼, XP에선 “짝 프로그래밍“을 강조하고 있다는 얘기이다.

그리고 또 한가지 인상깊었던 것은 역시나 “자동화된 테스트“의 중요성이다.

이 책에선 XP의 기본적인 실천방법으로   “테스트 우선 프로그래밍“을 제시한다.

코드를 한 줄이라도 변경하기 전에 먼저 실패하는 자동화된 테스트를 작성하라는 것이다.

난 사실, TDD를 제대로 공부해 본 적도 없고 실무에서 활용한 적도 없지만

올해들어 자동화된 유닛테스트를 작성하면서 junit의 초록색막대를 보는 재미에 흠뻑

빠져있다. 그리고 유닛테스트를 작성하면 할 수록, 그것을 작성하는데 드는 시간이

결코 낭비가 아니라 내가 작성한 코드에 대한 결함을 줄이고,  이 코드가 정상적으로

돌아가리라는 믿음을 주어 점차 내 개발 프로세스의 핵심으로 자리잡고 있는 중이다.

그리고 더불어 TDD에도 관심을 가지고 공부하게 되는 계기를 만들어 주었다.

이런 가운데, XP에서 “테스트 우선 프로그래밍“의 항목을 보았을 때 절로 고개가

끄덕여지는 건 당연한 것이었다.

내가 이론적 지식이 없는 상태에서 경험으로 조금씩 체득한 것들을 XP에선 아래와 같이

테스트 우선 프로그래밍“을 했을 경우에 장점을 설명한다

  • 슬금슬금 늘어나는 범위 : 프로그램의 목적 명시화
  • 결합도와 응집성 : 결합도는 낮고 응집성은 높은 코드
  • 신뢰 : 작동하는 깨끗한 코드와 자동화된 테스트로 의도 드러내기
  • 리듬 : 테스트 – 코드 – 리팩토링 – 테스트 – 코드 -리팩토링

마지막으로, 이 책을 다 읽고 난 후의 XP의 초점을 생각해 본 내 나름대로의 결론은

결국엔 “사람“이었다.

서로 함께 앉아서 짝 프로그래밍을 하는 가운데 전체팀에서 소속감을 느끼고,

불필요한 프로세스를 줄이고 원활한 의사소통(분명하고 솔직한!)과 빠른 피드백을 통해

프로젝트를 성공적으로 이끄는 그 중심에 바로 “사람“이 있다는 것을 깨달았다.

XP에서는 아래와 같은 사람이 가치있는 직원이라고 말한다.

  • 다른 사람을 존중하는 행동을 한다.
  • 다른 사람과 잘 어울린다
  • 솔선수범한다
  • 자신이 약속한 것을 지킨다

이 책을 읽고 난 후에, 나 자신은 그 동안 얼마나 다른 “사람“을 존중하고 또 함께

성장하기 위해 무슨 노력들을 해왔는지에 대해서 반추해보는 좋은 경험이었다.

책 끝자락에 저자가 남긴 문구를 함께 공유하면 좋을 것 같아 남긴다.

“XP를 통해, 나는 스스로 존중받을 가치를 지니도록 일하고, 또 다른 사람들을 존중한다.

나는 기꺼이 최선을 다하면서 언제나 개선하려고 애쓴다.

나는 내가 자랑스럽게 생각하는 가치들을 믿으며 거기에 어울리는 행동을 한다”

Advertisements

[리팩토링]빌더패턴을 활용해 객체 생성하기

스프링MVC로 만들어진 기존 서비스단 코드에 아래와 같이 매개변수 별로

동일객체를 만드는 코드가 있었다.

아래는 알림객체인 Notification을 만들어 전송하는 코드이다.

public void createNotificationByCase1(int a, int b, int c, String d, String f) {
    Notiifcaiton notification = new Notificaiton(a, b, c, d, f);
    sendAlarm(notification);
}
public Notification createNotificationByCase2(int a, int b, String d, String e) {
    Notiifcaiton notification = new Notificaiton(a, b, d, e);
    sendAlarm(notification);
}
public Notification createNotificationByCase3(int a, int b, int c, String d) {
    Notiifcaiton notification = new Notificaiton(a, b, c, d);
    sendAlarm(notification);
}

메서드Case1 ~ Case3별로 각기 다른 매개변수를 가지고 Notification 객체를 만든다.

그리고 Notification 클래스 내부는 아래와 같다.

public class Notification {
    private int a;
    private int b;
    private int c;
    private String d;
    private String e;
    private String f;

    Notification(int a, int b, int c, String d, String e, String f) {
       this.a = a;
       this.b = b;
       this.c = c;
       this.d = d;
       this.e = e;
       this.f = f;
     }
     Notification(int a, int b, int c, String d, String f) {
         this(a, b, c, d, null, f);
     }
     Notification(int a, int b, String d, String e) {
         this(a, b, 0, d, e, null);
     }
     Notification(int a, int b, int c, String d) {
         this(a, b, c, d, null, null);
     }
}

Notification 클래스 필드 6개 중, Notification 객체를 만드는 데 필요한 필수 멤버변수는

a, b, d고, 나머지 c, e, f는 선택 멤버변수이다.

위 Notification 클래스의 생성자를 보면 값이 없는 건 기본값(0 혹은 null)을 넣어서

다른 생성자를 호출하는 것을 알 수 있다.

위의 예제는 샘플코드를 만드느라 멤버변수를 6개만 넣었지만, 실제 리팩토링 한 코드의

클래스 멤버변수는 총 12개였고, 필수와 선택 멤버변수가 각각 6개씩이었다.

이런 상황하에 각 서비스에서 알림객체를 만들어 전송하려고 notificationService에 각기

다른 매개변수를 가진 메서드(Case1 ~ Case3 메서드)를  호출한 것이다.

notificationService를 이용하는 서비스단의 코드는 아래와 같다.

notificationService.createNotificationByCase1(a, b, c, d, f);

위와 같이 알림객체를 생성할 경우, 새로운 서비스에서 알림서비스를 사용할  때

또 다른 매개변수를 가진 메서드를 알림서비스에 만들어야 할 것이고, 그것을 이용하는

각 서비스들의 코드는 이해할 수 없는 매개변수의 나열로 가독성이 매우 나빠질 것이다.

타인은 물론 본인도 추후에 해당코드를 유지보수 할 경우, 어떤 데이터가 어디에 들어가

있는지 정확히 기억하기도 힘들고, 생성자 매개변수가 많으면 많을수록 그 복잡도는

매개변수 갯수에 비례해 증가하게 된다.

결국, 유지보수 시간이 기하급수적으로 늘게돼 나중에는 쳐다보기도 싫은

코드로 전락해버릴지도 모른다.

그래서, 이 복잡한 객체생성코드를 빌더패턴을 사용해서 리팩토링 하기로 했다.

빌더패턴을 사용해 객체생성을 하는 코드는 아래와 같다.

public class Notification {
    private int a;
    private int b;
    private int c;
    private String d;
    private String e;
    private String f;

    private Notification(Builder builder) {
        this.a = builder.a;
        this.b = builder.b;
        this.c = builder.c;
        this.d = builder.d;
        this.e = builder.e;
        this.f = builder.f;
     }

     public static class Builder {
        // Require Fields
        private int a;
        private int b;
        private String d;

        // Option Fields
        private int c;
        private String e;
        private String f;

        public Builder(int a, int b, String d) {
            this.a = a;
            this.b = b;
            this.d = d;
        }

        public Builder c(int c) {
            this.c = c;
            return this;
        }

        public Builder e(int e) {
            this.e = e;
            return this;
        }

        public Builder c(int f) {
            this.f = f;
            return this;
        }

        public Notification build() {
            return new Notification(this);
        }
    }
}

빌더패턴을 사용하고 난 이후에는 Notification클래스에 각 매개변수별로 만들어져 있던

생성자가 사라지고, Builder클래스의 build메서드를 통해 단일창구로 Notification객체를

만들게 되었다.

그리고 각 서비스에서 notificationService에 전달할 Notification 객체를 빌더패턴을

사용해 생성하고 아래와 같이 전달한다.

Notification notification = new Notification.Builder(a, b, d).c(c).f(f).build();
Notification notification = new Notification.Builder(a, b, d).e(e).build();
Notification notification = new Notification.Builder(a, b, d).d(d).build();
notificationService.sendNotification(notification);

Notification객체를 생성하는 필요한 필수 멤버변수인 a, b, d는 Builder클래스의 생성자를

통해 전달하고, 나머지 선택 멤버변수인 c, e, f는 set메서드 역할을 하는 메서드를 사용해

필요할 때 호출해서 값을 세팅하고 마지막에 build메서드를 호출해 Notification 객체를

생성하게 된다.

이로 인해, Notification 객체를 생성해 전송하던 notificationService의 각기 다른

매개변수를 가지던 메서드는 사리지고, Notificaiton객체 하나만을 받는

메서드 하나로 리팩토링 되었다.

긴 매개변수를 받던 메서드들이 사라지고, Notification 객체 하나만을 받도록 리팩토링 한

아래 코드를 보면 전과 비교해 코드 가독성이 월등히 좋아졌음을 알 수 있다.

public void sendNotification(Notification notification) {
    //기존 Notification 객체생성부분 삭제
    sendAlarm(notification);
}

빌더패턴을 사용해 객체 생성부분을 리팩토링해서 얻은 결과는 아래와 같다.

  • 각기 다른 매개변수별로 중구난방으로 만들어져있던 notificationService의 메서드를 Notification객체를 받는 단 하나의 메서드로 통일시킴
  • Notification클래스에 각기 다른 매개변수별로 만들어져있던 생성자를 Builder객체를 이용해 객체를 만드는 방법으로 통일시킴
  • 각 서비스별로 notificationService의 각기 다른 매개변수들을 가진 메서드를 호출하고 있던 것을 빌더패턴을 이용해 Notification객체를 생성하고 Notification객체를 받는 하나의 메서드를 호출하는 것으로 통일시킴

무엇보다 제일 좋은 것은 리팩토링으로 얻은 코드 가독성이다.

전에는 쳐다보기조차 싫었던 코드가 빌더패턴을 사용해 객체생성부분을 수정함으로써,

다음에 또 수정사항이 생겨도 빠른 시간안에 대처할 수 있는 여력이 생겼다는 것이다.

역시나 일상 속에 지속적인 리팩토링과 이를 뒷받침하는 테스트코드의 중요함을 다시

한번 느끼는 하루였다.

혹시나, 빌더패턴에 대해 궁금하신 분은 Effective java 항목2를 읽어보면 많은

도움이 될 것이다.