패턴, 가치, 원칙

“패턴, 가치, 원칙” 세 가지를 사용하면 균형있는 개발을 할 수 있다.

  • 패턴은 지금 당장 무엇을 해야할지 알려준다.
  • 가치는 패턴을 사용해야하는 동기를 알려준다.
  • 원칙은 동기를 어떻게 행동으로 바꿔줄지 알려준다.

가치

훌륭한 프로그래밍에서 공통적인 가치는, “커뮤니케이션, 단순성, 유연성” 이다.

커뮤니케이션

코드를 쉽게 이해하고 수정하고 사용할 수 있으면, 그 코드는 개발자와 커뮤니케이션을 한다.

프로그램을 작성할 때 타인을 고려하면, 코드는 이해하기 쉽고 명확해진다.
또한 경제적으로도 효과가 높아진다.
기존 코드를 읽고 수정하는데 걸리는 시간이 새로 짜는데 걸리는 시간을 압도한다.
따라서 이 개발 비용을 줄이기 위해 이해하기 쉬운 코드를 작성해야한다.

단순성

복잡도를 낮추면, 프로그램을 읽고 수정하는 사람들이 프로그램을 쉽게 이해할 수 있다.

프로그램을 최대한 단순화하자.
의미 없는 코드는 제거하고, 설계 시 과도한 요소는 제거하자.
요구 사항을 분석해서 꼭 필요한 사항만 추출하자.

유연성

유연성은 비효율적인 코딩이나 설게를 정당화해주는 가치다.
예를 들어, 상수 값을 얻기 위해 환경 변수를 읽어 상수를 가지고 있는 파일의 디렉토리 이름을 읽어오는 경우가 있다.

당장 비용이 들어가지만, 앞으로 이득을 얻을 수 있을지 불확실한 패턴이면 사용을 자제하자.
그리고 정말 필요할 때 적용하자.

원칙

원칙을 이해하면, 각 패턴의 세부 내용뿐만 아니라 패턴을 사용하는 근본적인 이유에 대해 이해할 수 있다.

지역적 변화

코드를 수정할 때 같이 변경해야하는 부분을 최소화하자.
특정 부분을 수정하는 것이 다른 부분에 문제를 일으키면 수정에 대한 비용이 커진다.

최소 중복

“지역적 변화” 를 돕기 위해, 최소 중복의 원칙을 지키자.

같은 코드가 여러 곳에 반복되면, 하나를 바꿀 때 중복된 다른 코드도 바꿔야야 할지 여부를 결정해야한다.
중복 코드가 많으면 코드 수정이 어려워진다.

중복을 절대적으로 피해야하는 요소로 보기보다, 코드 수정 비용을 높이는 위험 요소로 보자.

로직, 데이터 결합

“지역적 변화” 원칙에 근거한 다른 원칙은, 로직과 데이터를 함께 유지하는 것이다.

프로그램을 수정할 때, 로직과 데이터를 모두 수정해야하는 경우가 많다.
그래서 로직과 데이터가 같이 있다면 프로그램을 수정하더라도 그 영향이 일정 영역에 머물게 된다.

대칭성

코드의 대칭성은 한 아이디어를 프로그램 전체에서 일관된 방식으로 표현하는 통일성이다.

다음을 보자.

1
2
3
4
5
fun process() {
input()
count++
output()
}

count++ 는 다른 구문에 비해 구체적이다. 대칭성을 고려해서 다음처럼 수정하자.

1
2
3
4
5
fun process() {
input()
incrementCount()
output()
}

input() 과 output() 는 메서드의 이름이 목적을 반영한다.
그런데, incrementCount() 는 구현을 반영한다.
왜 count 를 증가시키는지 고려해서,

1
2
3
4
5
fun process() {
input()
tally() // "일치시키다" 라는 의미
output()
}

선언적 표현

수행 순서가 중요한 구문이나 조건부 구문이 없는 일반 구분은, 선언적 표현이 이해하기 쉽다.

다음은 junit 의 수행할 테스트 집합을 반화하는 코드다.
수행할 테스트를 확인하기 위해 실제 메서드 내부를 보고 이해해야한다.

1
2
3
4
5
6
public static junit.framework.Test suite(){
Test result = new TestSuite();
// ..

return result;
}

다음은, junit4 에서 선언적 표현을 통해 이 문제를 해결했다.
여러 클래스에 있는 테스트를 수행해주는 테스트 수행 클래스를 사용했다.
그래서, TestClasses 만 봐도 어떤 테스트가 수행될지 알 수 있다.

1
2
3
4
5
6
7
8
@RunWith(Suite.class)
@TestClasses({
SimpleTest.class,
ComplicatedTest.class
})
class AllTests {

}

변화율

같이 변하는 로직과 데이터를 함께 관리하고, 변화율이 다른 로직과 데이터는 분리하자.

세금 계산 소프트웨어에서, 일반 세금 계산 루틴과 특정 년도 세금 계산 루틴을 별도로 구현할 수 있다.
코드의 변화율이 다르기 때문이다.
연도별 세금 계산을 별도로 분리해서 구현하면 코드 수정에 대한 영향을 제한할 수 있다.

데이터에도 적용할 수 있다. 하나의 객체에 있는 모든 필드는 가급적 같이 변해야한다.

예를 들어, 함께 변하는 필드 value, currency 가 있다.

1
2
3
4
setAmount(int value, String currency) {
this.value = value;
this.current = currency;
}

아래 처럼 개선할 수 있다.

1
2
3
setAmount(int value, String currency) {
this.value = new Moeny(value, currency);
}

더 개선하면,

1
2
3
setAmount(Money vlaue) {
this.value = value;
}

대칭적인 필드를 별도의 객체에 묶어서 대칭성을 표현하면, 프로그래머의 의도를 잘 전달할 수 있다.
그리고, 중복을 줄이고 코드 수정에 대한 영향을 제어하기 쉽다.


켄트 벡의 구현 패턴 <켄트 벡>

Comments