2007년 2월 1일 목요일

Assert를 잘하자.

오늘의 교훈: Assertion의 습관화.


Code Complete에 보면, Assert에 관해 한 장을 할애할 정도로 중요하게 여기고 있다. The Pragmatic Programmer에서도 중요하게 다루고 있는 주제.


원론적인 면에서 동의하면서도 현실에서 체감한 적은 별로 없었는데... (솔직히, 너무 뻔한 이야기 아닌가... 라는 생각까지 했었다.)


근 2주가까이 한가지 문제를 해결하기 위해 고민하고 있었는데, 정작 문제는 너무나 간단한 곳에 있었다.


[php]
private function doSomething($param=null) {
...
}
[/php]


이런 메쏘드가 있을 때, 이 코드로만 보아서는 $this->doSomething();처럼 호출해도 문제가 없을 것 처럼 보인다. 주석 및 도큐먼트에는 심지어, $param은 optional하다고 적혀있기까지 하다.

그런데 실제로, 코드를 추적해본 결과, 개발자의 의도와는 달리 이 코드는 특정조건 하에서는 $param값이 null이 되면 오작동하도록 만들어져 있었다.

일차적으로는 개발자가 주석과 도큐먼트를 잘못 작성한 셈이지만,
근본적으로는 Assertion을 제대로 하지 않은 코드의 문제. 선행조건을 엄밀히 명시해두지 않았기 때문에 발생했다.


최소한 다음처럼 코드가 작성되어 있었어야 했다. 오류를 해결하는 것보다, 보고하는 것이 먼저다.
(어디가 문제인지 알아야 고치기라도 할 것 아닌가.)


[php]
private function doSomething($param=null) {
assert('$this->someCondition || $param');
...
}
[/php]


물론 동적으로 생성되는 값들에 대해 미리 선행조건을 알고 있기가 불가능한 경우도 있겠다. 그런 경우에라도 크리티컬한 미션을 수행하기 직전에, 해당 미션이 클리어되기 위한 선행조건에 대한 assertion을 붙이는 방어적 프로그래밍을 습관화해야겠다.


* 좋은 Assertion을 위한 지침. (from Code Complete)


1. 여러분이 발생할 것이라고 예상하는 상황들에 대해서 오류처리코드를 사용하라. 즉, 절대로 발생해서는 안 되는 조건을 위해서 어설션을 사용하라.

2. 실행가능한 코드를 어설션내에 입력하지 않는다.

3. 선행 조건과 후행 조건을 문서화하고 검증하기 위하여 어설션을 사용하라.

4. 매우 견고한 코드를 작성하기 위해서는 어설트한 다음 오류를 처리하라.


* PHP를 위한 assert function


[php]
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_BAIL, 1);
assert_options(ASSERT_CALLBACK, 'assertHandler');
function assertHandler($file, $line, $message) {
echo "$file : $line : $message";
}

...

assert('some assertion syntax...');
[/php]

댓글 없음:

댓글 쓰기