Download VCard

© 최병일 1981-‘10

Jeff Bay의 객체 건강유지법.

작성자 : yagur rev : 1

  작고 단단한 객체를 작성하기 위해 프로그래머들은 고민을 많이 합니다. 이에 조금은 도움이 될만한 연습방법이 눈에 띄더군요. Thought Works Anthology란 수필 모음집에 객체 건강유지법(Object Calisthenics)이란 흥미로운 수필이 바로 그것이었습니다.

 아래 목록은 잘알려진 7가지 코드 품질에 관련된 항목들입니다.
응집력cohesion, 느슨한 결합loose coupling, 무중복zero duplication, 은닉encapsulation, 테스트 가능성testability, 가독성readability, 집중력focus

 그리고 Jeff Bay는 위의 7가지 코드 품질의 향상을 위한 9가지 실천 항목을 소개하고 있습니다.

 1. 메소드당 한 단계 깊이 이상의 들여쓰기를 하지 않는다.
 2. else 키워드를 사용하지 않는다.
 3. 모든 원형primitive과 문자열을 래핑Wrapping한다.
 4. 한 라인당 하나의 점(.)을 사용한다.
 5. 약어를 쓰지 않는다.
 6. 엔티티를 작게 유지 한다.
 7. 두개 이상의 인스턴스 변수를 가진 객체는 사용하지 않는다.
 8. 일급 객체 모음을 사용한다.
 9. Getters/Setters/properties를 사용하지 않는다.

 제 해석이 틀릴수도 있으니, 원문을 참조 하시고 싶은분은 아래 more를 누르세요.

more..


  일단 이 9가지 실천항목은 Jeff가 제안하는 객체 건강유지법입니다. 규칙과 달리 꼭 지켜야할 강제성이 없는 원칙과 비슷하지만, 그 강제성이 좀더 약한 수준이라고 보고있습니다. 그는 간단한 1000 라인 크기의 프로젝트를 만들어 연습을 시작하되, 위의 실천항목 9가지를 매우 엄격하게 적용하는것을 조건으로 내걸고 있습니다. 그리고 이 건강유지법을 가이드라인 정도로 활용하라고 그는 말하고있습니다. 다시 한번 본다면 몇가지 실천항목은 그다지 새롭지 않은것들도 있습니다.

1. 메소드당 한 단계 깊이 이상의 들여쓰기를 하지 않는다.

 메소드 크기가 클경우 보통 응집도가 떨어지는 경우가 많습니다. 분리해야할 시점에서 분리하지 않고, 관련없는것이 계속 더해져 비대해지는 경우입니다. 이를 피하는 좋은 방법은 작게 작성하는 것입니다. 작게 작성하려다 보면 해당 문제 영역안에서 해결하려는 경향이 생겨납니다. Jeff는 작게 작성하는 버릇을 들이기 위해 한 메소드를 5줄 이내로 작성하라고 권합니다. 물론 이는 그의 건강유지법에 해당하며, 실무에서 모든 메소드를 5줄 이내로 작성하는것은 불가능에 가깝다고 생각합니다. 하지만 좋은 연습이 될것입니다.
  5줄이내로 작성하는것이 들여쓰기와 무슨 상관이 있는가 반문하시는분도 계실것입니다, 적은 줄수로 작성하려면 일단 들여쓰기를 줄일수 밖에 없습니다. 또한 조건 분기로 인한 들여쓰기가 많아지는 경우 CC가 올라가고 높은 CC는 테스트 가능성testability을 떨어트립니다.

2. else 키워드를 사용하지 않는다.

 if-else 문은 조건에 따라 선택적인 수행을 하기 위한 것입니다. 경우에 따라 switch문을 사용할수도 있습니다.

선행 조건문의 예>
if(condition)
{
    DontDoIt();
}
else
{
    DoPreprocess();
    Process();
}
위의 것은 아래와 같이 고칠수 있습니다.
if(condition)
{
    DonDoIt();
    return;
}

DoPreprocess();
Process();
 다른책에서도 너무나 많이 봐온 방법입니다.

전략적 조건문의 예>
if(conditionA)
{
    WriteLog();
    return false;
}
else if(conditionB)
{
    DoSomethingByStrategyA();
    return true;
}
else if(conditionC)
{
    DoSomethingByStrategyB();
    return true;
}
else
{
    WriteLog();
    return false;
}
  혹은 Switch문을 통해 저런 선택을 했을수도 있습니다. 이런경우엔 StrategyPattern을 통해 구조를 개선해볼수 있습니다.
사용자 삽입 이미지



3. 모든 원형
primitive과 문자열을 래핑Wrapping한다.

 "Where everything's an object"라는 Ruby와 같은 언어와 달리 Java나 C++과 같은 언어들의 원형primitive은 객체가 아닙니다. 정수, 실수, 문자열과 같은 것들은 객체로서 접근하지 않습니다.

  Ruby

returnedNumber = -42.abs
   Java
returnedNumber = Math.abs(-42);

  극단적인 예였지만, 가독성면에서 본다면 원형을 객체로 다루는것은 컴파일러와 사람에게 좀더 의미있는 형을 부여하는 셈이 됩니다. 원형인 정수(int)로서의 dollar(미 화폐단위)보다, 객체로서 다루작성된다면 좀더 유지보수성이 높은 코드가 됩니다. 저 dollar를 pound로 환산하려면 어떻게 해야할까요? int 라면 getter를 이용해 값을 받아온후 환율을 곱해 pound에 집어넣어야 할것입니다. 이럴 경우 클래스로 화폐를 표현하였다면, 좀더 유연하고 유지보수성과 확장성을 지니게 된다고 생각합니다. 물론 이는 명세와 관련이 깊습니다. 필요 없는 구현을 유연성을 위해 구현한 꼴이니까요. 하지만 이 연습은 작은 객체들로 작성함으로서 어떤것을 객체로 분류하는것이 좋을지를 판단해보는 좋은 연습이 되리라생각합니다.
   분해를 해봄으로서 좋은 연습이 되지만, 과도한 객체화로 인해 응집력을 잃어버려서는 않됩니다. 예를 들어 3D vector를 표현할때 vector의 float x, y, z를 멤버로 지니고 있는것은 딱 적당한 수준입니다. 하지만 x, y, z조차 객체로 분해해 버린다면 제가 보기엔 과도한 분해라고 생각합니다. 하지만 적당히 일반화 시킬순 있습니다.
template <typename T>
class vector3
{
    ....
    T x;
    T y;
    T z;
};
  멤버의 유연성을 위해 객체화 시키는 방법도 있지만, 과도한 분해를 피하기위한 방법중엔 일반화란 방법도 존재합니다. 멤버 타입 변경이 필요하고, 동일한 행위를 유지시킨다면 일반화 선택도 그리 나쁘지 않습니다. 이 연습엔 일반화 연습을 포함시키는것도 유익할듯 합니다.

4. 한 라인당 하나의 점(.)을 사용한다.
  일단 . 이나 ->가 여러개 거치고 있다면 캡슐화를 위배하는지 의문을 품어봐야합니다. 참조에 참조를 거듭한다는것은, 참조자가 너무 깊은 관여를 하고 있다는 느낌을 지울수 없습니다. 캡슐화 하고 행위를 요청합시다.

5. 약어를 쓰지 않는다.
  두말 할것 없습니다. 동료의 코드가 암호화 되기 원하시는건 아니겠죠.

6. 엔티티를 작게 유지 한다.
  이것 역시 작게(응집력있게) 작성하기의 또다른 연습입니다. 50줄 넘이 넘지 않는 클래스, 열개의 파일이 넘지 않는 패키지가 목표입니다.(저자는 자바를 기준으로 이야기하고있으니 C++의 경우는 헤더도 있고 하니, 줄수와 파일수를 2.5배정도 하면 적당할듯 합니다.). Jeff의 내용을 요약하자면, 길이가 길어지면 SRP를 위배하게 될 확률이 높다입니다. 그리고 객체의 길이가 길면 보통 책임의 양도 증가합니다. 객체를 이해하기에도 노력이 더 필요하고, 여러가지 기능이 복합적으로 모여있다면 재사용시에도 문제가 될 소지가 있습니다.

7. 두개 이상의 인스턴스 변수를 가진 객체는 사용하지 않는다.
  제목만 보고 화가 날수도 있습니다. 하지만 이건 연습입니다. 일단 이 연습의 의도는 분해Decomposition입니다.
응집력을 떨어트릴수 있는것들을 분해해서 그 책임을 분리해버리는 것입니다. 예를 들면 컨터에너에 들어갈수 있는것을 장황하게 멤버로 나열하였거나, 의존성을 역전해야할부분을 결합해버린 경우를 분해하는 것입니다. 멤버가 줄수록 그럴 확률이 높아집니다. 의도적으로 SRP를 실천하는것입니다. 원칙은 필요에 의해 적용해야 하지만, 적용하는것도 연습이 필요합니다. 그를 위한 연습인것으로 보입니다.

8. 일급 객체 모음을 사용한다.
  원형을 래핑해서 쓰는것과는 조금 다른 연습입니다. 원형 배열이나 동종 객체들의 모음(예> container에 담긴 개체들)을 지니고 있는 경우, 이들을 위한 행위만을 갖는 객체를 작성하는 연습입니다. 다른 멤버 변수를 사용하지 않고 저 응집체에만 집중하는 것입니다. C++에서 찾아볼수 있는 예로는 STL의 container 객체들이 아닐지.. 물론 일반화된 컨테이너 객체라, 지극히 일반화된 행위들만을 모아놓았지만 말이죠. 그 컨테이너를 멤버로 채용하는 객체는 일단 컨테이너에 관련된 멤버함수들만을 내부적으로 갖고있습니다. 컨테이너의 원소에 요구하거나 행해지는 행위들만을 모은 객체를 작성하는 연습입니다. SRP(Single Responsibilty Principle)에도 부합합니다. 많은 멤버를 갖는다는 것은 그 만큼 클래스가 책임질것이 많다는것을 뜻하니까요.
  이 연습 역시 또다른 작은 객체 작성하기 연습입니다.

9. Getters/Setters/properties를 사용하지 않는다.
  일단 getter/setter가 많다면, 캡슐화를 한 의미가 줄어듭니다. 거기다 객체에 행위를 요청하면 될것을 멤버를 참조해서 별도의 로직을 만들기 때문에, 아주 다양한 오류에 직면하게 됩니다. 또한 그 책임은 참조자인지, 제공자인지 구분하기도 힘들며, 스파게티가 되는것은 순식이라 생각합니다. "Tell, Don't Ask"라고 Jeff의 마지막 문장에 쓰여있군요. 캡슐화, 책임 지정의 좋은 연습이 될것같습니다.

'개발' 카테고리의 다른 글

Jeff Bay의 객체 건강유지법.  (0) 2008/10/01
이럴때 테스트 셋을 만든 보람이 있습니다.  (0) 2008/04/12
Eiffel 과 DBC.  (2) 2008/01/04
Overloading과 Overriding [Part 2]  (0) 2007/05/26
Overloading과 Overriding [Part 1]  (0) 2007/05/22
Unicode 2  (1) 2006/08/11
Comment 0 Trackback 1

Trackback : http://yagur.impon.net/trackback/141 관련글 쓰기

  1. 강성희의 생각

    paranoiase's me2DAY | 2008/10/01 15:20 delete

    Yagur의 Juggling - Jeff Bay의 객체 건강유지법 - '두개 이상의 인스턴스 변수를 가진 객체는 사용하지 않는다.' ㄷㄷㄷㄷ

Top

prev 1 2 3 4 5 6 7 8 ... 81 next