본문 바로가기

Clean code

Clean Code 12장 - 우수한 설계를 위한 규칙(창발성)

우수한 설계를 위한 규칙

켄트 백이 제시한 다음 규칙을 따르면 설계는 '단순하다'고 우리는 믿고 있다.

  1. 모든 테스트를 실행한다.
  2. 중복을 없앤다.
  3. 프로그래머의 의도를 표현한다.
  4. 클래스와 메소드 수를 최소로 줄인다.

이 순서는 중요도 순이다! 하나하나씩 살펴보자~

우수한 설계를 위한 규칙 1 - 모든 테스트를 실행한다.

모든 테스트를 실행한다가 왜 우수한 설계를 위한 규칙일까? 모든 테스트 케이스를 만들려면 결합도가 높아서는 안된다. 한 클래스 함수에서 하나 이상의 책임을 가지고 있으면 테스트 케이스를 만들기 어려워진다. 그러면 자연스럽게 단일 책임 원칙을 지키게 된다. 또한, 다른 클래스와 결합도가 높으면 테스트가 힘들어지기 때문에 자연스럽게 의존성 주입을 사용하게 된다.

 결국, 테스트 케이스를 모두 실행 시키다보면 낮은 결합도와 높은 응집력이라는 객체 지향 방법론을 자연스럽게 달성하게 된다.


우수한 설계를 위한 규칙 2 - 리팩토링 ( 중복을 없앤다 )

우리는 모든 실행에 대한 테스트를 작성하였기 때문에 리팩토링을 하다 기능이 동작하지 않을까 하는 우려를 할 필요가 없다.

우수한 설계에서 중복은 항상 커다란 적이다. 다음 예제를 통해 어떻게 리팩토링 되었는지 살펴보자.

아래 코드는 최소 법정 일수를 계산하는 코드외에는 두 메소드는 거의 동일하다. 여기에 TEMPLATE METHOD 패턴을 적용해보자.

public class VacationPolicy {
public void accrueUSDivisionVacation() {
// 1. 지금까지 근무한 시간을 바탕으로 휴가 일수를 계산하는 코드
// 2. 휴가 일수가 '미국' 최소 법정 일수를 만족하는지 확인하는 코드
// 3. 휴가 일수를 급여 대장에 적용하는 코드
}

public void accrueEUDivisionVacation() {
// 1. 지금까지 근무한 시간을 바탕으로 휴가 일수를 계산하는 코드
// 2. 휴가 일수가 '유럽연합' 최소 법정 일수를 만족하는지 확인하는 코드
// 3. 휴가 일수를 급여 대장에 적용하는 코드
}
}


아래와 같이 중복되는 코드는 abstract 객체에 공통으로 구현을 하여 중복을 없앴다.

abstract public class VacationPolicy2 {

public void accrueVaction() {
calculateBaseVacationHours();
alterForLegalMinimus();
applyToPayroll();
}

private void calculateBaseVacationHours() {
}

;

protected abstract void alterForLegalMinimus();

private void applyToPayroll() {
}

;
}

public class USVacationPolicy extends VacationPolicy2 {

@Override
protected void alterForLegalMinimus() {
// 미국 최소 법정 일수를 사용함
}
}


우수한 설계를 위한 규칙 3 - 표현하라

작성된 코드는 commit된 이후에 언젠가는 다시 읽어야 한다. 같은 팀원이 될 수도 있고 자기 자신이 될 수도 있다.
코드 작성할 때는 어떻게 흘러가는지 알고 있기 때문에 로우레벨 단의 코드를 작성해놔도 가독성이 떨어지지 않을 것이다.
하지만! 자신이 작성한 코드는 거의 100% 자신이 수정해야 하는 상황이 올 것이다. 이때는 세세한 상황을 잊어버렸기 때문에 표현해 놓지 않으면 가독성이 매우 떨어지게 된다.
결국 유지보수 비용이 증가하게 되는 것이다.
코드는 개발자의 의도를 분명히 표현해야 한다.

  1. 함수의 의도를 나타내는 좋은 이름을 선택한다.
  2. 함수와 클래스의 크기를 최대한 줄인다.
  3. 표준 명칭을 사용한다. 패턴을 적용한 경우, COMMAND, VISITOR를 클래스 이름 뒤에 붙여준다.
  4. 단위 테스트 코드를 꼼꼼히 작성한다. 테스트 케이스는 소위 '예제로 보여주는 문서'이다.

우수한 설계를 위한 규칙 4 - 클래스와 메소드 수를 최소한 줄여라

중복을 제거하고 의도를 표현하다보면 SRP를 준수하기 위해 득보다 실이 많아질 수도 있다. 예를 들어, 무조건 인터페이스를 생성하라거나 자료 클래스와 동작 클래스를 무조건 분리하자는 경우이다. 
 하지만, 이 규칙은 네 개중 가장 우선순위가 낮으며, 우리는 중복을 제거하고 의도를 표현하는 것이 더 중요한 작업이다.