Search

'pdc'에 해당되는 글 1건

  1. 2009.12.09 Beyond the Assertion, Code Contract -1

Beyond the Assertion, Code Contract -1

프로그래밍 2009.12.09 19:30 Posted by 아일레프

블로그에 따로 포스팅 하지 않았지만 사실 이번에 안재우 과 함께 PDC09에 직접 참석하는 영광을 누렸습니다. 앞으로 PDC09에 참여했던 세션 중 인상 깊었던 것 들에 대해 개인적으로 리뷰할 계획입니다. 이 포스팅은 그 첫번째 입니다.

 

첫날의 마지막 세션이었던 Code Contracts and Pex : Power Charge Your Assertions and UnitTests 에서 두 명의 발표자가 “만담”형식으로 재미있게 Code Contract Pex를 함께 사용하는 방법을 소개했습니다.(약간 통통하신 분의 발음이 아주 재미있습니다.) 사실 Code Contracts Pex PDC09에 처음 소개되는 주제가 아닙니다. Pex PDC08에 발표되어 청중의 열혈한 박수를 얻어 낸 바 있으며, Code Contract또한 PDC08에 소개되었으며 Web상에서도 알려진바 있습니다.

 

하지만 이 세션을 볼 당시 전 Code Contract에 대해서는 잘 알지 못했는데 Code Contract Pex보다 더욱 쓸만할 것 같더군요. 어렵지 않게 사용할 수 있으면서도 가벼운 습관을 통해 더 나은 품질의 결과를 얻을 수 있을 거란 생각이 들었습니다. 여러분은 어떤가요? 이 글을 읽으신후 스스로 판단하시기 바랍니다.

 

 

Why the Assertion?

Assertion as Assertion

Assertion, 단언 이라고 표현되는 이 테크닉은 프로그래머가 코드의 특정 지점 내에서 프로그램 논리 흐름상의 반드시 만족해야 하는 ‘가정’을 코드에 넣는 것을 의미합니다. Introduction to Algorithm QuickSort알고리즘에 사용되는 Partition Function을 예로 들어보겠습니다.

 

Partition(A, p, r)

x ß A[r]

i ß p -1

for j ß p to r-1

           do if A[j] <= x

                     then i ß i+1

                                exchange A[i] ßà A[j]

exchange A[i] ßà A[r]

return i+1

 

책에서는 위 알고리즘을 알리는 것으로 끝나는 것이 아니라 다음과 같은 단언이 따라옵니다.

 

For 루프 안에서 다음 3가지 조건이 항상 만족한다.

1.     If p <= k <= i, then A[k] <= x

2.     If i+1 <= k <= j-1, then A[k] > x

3.     If k = r, then A[k] = x

 

3가지 expression이 바로 알고리즘 논리 상의 Assertion입니다. 만약 for 루프 내에서 1,2,3번 중 하나라도 만족하지 않는 것이 있다면 이 알고리즘은 올바르지 않은 것입니다.

다른 예로 최근 포스팅을 들 수 있겠습니다. 해당 포스팅을 보면 알고리즘 나열 도중 -**단언-으로 시작되는 줄이 보입니다. 그들이 제가 생각 했을 때 반드시 참이어야 하는 논리상의 가정입니다.(실제로는 저 단언중 몇가지가 옳지 않아 알고리즘을 수정해야 했습니다.)

프로그래머는 System.Diagnostics Debug 클래스의 Assert( bool condition)메소드를 이용해 Assertion을 코드에 삽입할 수 있습니다. Debug클래스의 Assert는 조건를 만족하지 않으면 메시지와 함께 프로그램을 종료시켜 버립니다. 이런 Assertion의 사용으로 인해 프로그래머는 자신의 알고리즘에 대해 확신을 가질 수 있고, 만약 논리상의 오류가 있을 때 그 원인을 보다 쉽게 추리할 수 있습니다.

 

Assertion as Contract.

Assertion을 프로그래머간의 ‘계약’으로 사용할 수 있습니다. Argument Check가 좋은 예입니다. 관습적으로 Public 메소드의 Argument Check Assertion이 아닌 Exception으로써 명시합니다. 예를 들어 Math 클래스의 Round메소드의 Signiture는 다음과 같습니다.

public static double Round(double value, int digits, MidpointRounding mode);

Visual Studio 상에서 위 메소드의 주석을 펼쳐보면 다음을 발견할 수 있습니다. Digits 메소드가 0보다 작거나 15보다 크면 Exception을 발생시킨다는 것입니다. 즉 이 메소드는 digits argument 0<= digits <= 15라는 전제 내에서 동작하며, 이 메소드를 이용하는 사용자가 이 전제를 지켜주기를 요구하고 있는 것입니다.

//   System.ArgumentOutOfRangeException:

//     digits is less than 0 or greater than 15.

 

이와 같이 프로그래머는 자신의 코드를 최초에 디자인 할 때 반드시 만족해야 할 “최소한의 조건”를 자신 또는 다른 사용자에게 노출 시킬 필요가 있습니다. 이것을 명시하는 것을 “계약”이라 하겠습니다. 이러한 계약의 종류로 크게 다음 3가지를 들 수 있겠습니다.

 

A.    PreCondition

특정 작업이 시작되기 전에 반드시 지켜져야 하는 전제 조건을 의미합니다. 이미 설명한 메소드의 Argument체크가 이에 해당됩니다.

메소드의 시작에 계약 코드를 삽입하며, public 메소드에는 if-then throw exception 코드가 사용되며 private 메소드에는 Assert가 사용됩니다.

 

B.     PostCondition

특정 작업이 끝난 후에 보장되어야 하는 조건을 의미합니다. 예를 들어 Arc Sine 메소드를 디자인 한다고 했을 때 결과 값이 -π/2 ≤θ≤π/2 를 만족하는 Radian값인 θ이라는 것을 보장할 수 있어야 합니다. 메소드의 마지막에 계약 코드를 사용하게 됩니다.

 

C.     Object Invariants

이것은 클래스 내의 모든 특정 작업이 종료된 후에 항상 지켜져야 하는 불변의 조건을 의미합니다. 예를 찾기 힘들어 Reference로 사용한 Programmin with Assertion의 예를 그대로 말씀드리겠습니다. 여러분이 어떤 필요에 있어서 Balanced Binary Tree 를 만들어야 한다고 가정하겠습니다. 이 때 Balanced Binary Tree는 특정 연산이 이루어지기 전이나 후에 “Balanced, Binary”라는 조건을 항상 만족해야 합니다. Tree내의 모든 Node Node자신의 자식의 수가 0보다 같거나 크고, 2보다 같거나 작다는 조건을 항상 만족해야 하며(Binary), 모든 Node Node 자신의 자식들(많아야 2)간의 Depth의 차이가 1보다 같거나 작아야한다는 사실을 만족해야 합니다.(Balanced)

모든 public 코드 뒤에 Object Invariants Assert코드가 존재하는 메소드를 호출하는 것으로 이 작업을 수행할 수 있습니다.

 

 

Break Point!

여러분은 여기까지 읽었을 때 Assertion -- if-then throw 를 제외한 순수 Assertion -- 이 프로그램을 사용하는 사람을 위한 것이 아니라 프로그램을 개발하는 사람들을 위한 것이라고 추측 할 수 있습니다. 그리고 그 추측은 완전히 옳습니다. 또한 이 추측은 또 한가지 결론으로 우리를 이끌어 가는데, 바로 Release시에는 Assert는 존재해야할 이유가 없다는 것입니다. 따라서 보통 아래와 같이 사용합니다.

#if DEBUG

AssertCode..

#end if

하지만 매번 #if DEBUG를 쓴다는 것도 힘든 일이지요. 따라서 우리를 배려한 Microsoft는 Debug.Assert 메소드가 오직 Debug시에만 컴파일되게 했습니다.

 

 

Why the Code Contract?

Code Contract as Assertion

Code Contract는 이름에서 알 수 있듯이 “계약”을 위한 필요와 목적에서 출발했지만 Assertion으로써의 기능도 할 수 있습니다. Contract클래스의 Assert, Assume 메소드가 그것입니다. 이 기능은 기존의 Debug.Assert의 기능과 완전히 동일합니다.

public static void Assert(bool condition);

public static void Assume(bool condition);

이는 물론 DEBUG시에만 컴파일 대상이됩니다. Assert Assume의 차이점은 이 후에 설명하도록 하겠습니다.

 

Code Contract as Contract

Assertion Assertion으로써의 기능만을 수행한다면 아무런 불만이 없습니다. 그러나 Assertion Contract의 기능까지 함께 할 때 몇 가지 불만이 따라오게 됩니다. 대충 생각해 보면 다음과 같습니다.

 

1.     Assertion또는 if-then throw exception를 계약의 목적으로 사용했을 때, 그 계약이 실재로 존재한다는 사실은 Runtime에 그 계약을 어겼을 때에만 확실하게 알 수 있습니다. 이것은 분명히 비극입니다.

2.     PreCondition, PostCondition, Class Invariants 각각의 계약의 특성에 따른 고유의 기능이 필요한데 기존의 Assertion, if-then throw exception은 그러한 요구를 만족시켜줄 수 없습니다.

3.     그놈의 코드 중복 때문입니다.

4.     Interface에 계약을 명시하고 싶습니다.

5.     상위 Type의 계약이 하위 Type에 ‘반드시’ 상속되었으면 좋겠습니다.

6.     컴파일시 바이너리에 포함될지 결정하는 조건을 다양하게 하고 싶습니다.

 

1번의 필요성 때문에 Code Contract 2가지 유용한 기능을 가지고 있습니다. Document Generation Static Verification 기능이 그것입니다. Documentation Generation으로 개발자들은 계약을 보기도 싫은 코드 조각과 런타임시에만 존재하는 Error 메시지가 아닌 분명한 문서로 받아 볼 수 있게 되었습니다.(문서가 더 싫은 가요? ^^) 또한 Static Verification으로 계약을 잘 지켜서 코딩 했는지 빌드 시에 Warning 메시지로 알 수 있습니다.

 

2번의 필요성 때문에 -- 2번의 필요성에 대한 자세한 설명은 다음 포스팅으로 미루겠습니다. -- Code Contract Precondition, PostCondition, Object Invariants에 특화된 별개의 메소드를 고안했습니다. Require, Ensure, Invariant가 그것입니다. 각각의 설명은 다음 포스팅에 자세히 소개하겠습니다.

 

3번은 사실 4번과 5번을 포함합니다. Assertion만으로 Object Invariants를 구현한다고 상상해보시기 바랍니다. 모든 public 메소드의 마지막에 Object Invariants를 확인하기 위한 Assert 코드를 추가해야 할 것입니다. 이러한 중복은 당연히 사라져야 합니다.

 

4번의 필요성은 상당히 중요합니다. Interface는 물론 다형성을 위한 것이지만 계약은 통일되어야만 합니다. 각각의 Interface 구현 클래스가 다른 계약을 가지는 것을 절대 허용하면 안됩니다. 따라서 Interface에 계약을 명시해야 하며, 그 계약은 모든 구현 클래스에 적용되어야만 합니다.

 

5 입니다. virtual 메소드를 가진 Super클래스가 있다고 가정합니다. Virtual 메소드안에 계약코드를 넣었는데 sub클래스에서 이것을 override해 계약 코드를 지우는 것을 허용하면 안됩니다. 때에 따라서 정해진 계약을 ‘강화’시키는 것을 막아야 할 필요성도 있을 수 있습니다.

 

 

Next

Code Contract가 등장하게 된 배경에 대해 간략히 설명했습니다. 여러분이 스스로 생각하고, 상상할 수 있는 권리를 빼앗고 싶지 않기 때문에 Code Contract가 어떻게 이 일을 해냈는지 말하는 것은 다음 포스팅으로 미룹니다.
감사합니다.
 

 

 

References

Code Contracts and Pex : Power Charge Your Assertions and UnitTests

MSDN Magazine : Code Contracts

Code Contract

Code Contract Manual

Programming With Assertions

저작자 표시
신고