본문 바로가기
프로그래밍 놀이터/Tips

[실용주의 프로그래머] 계약에 의한 설계

by 돼지왕 왕돼지 2018. 10. 24.
반응형

[실용주의 프로그래머] 계약에 의한 설계


class invariant, DBC, design by contract, ensure, postcondition, precondition, require, [실용주의 프로그래머] 계약에 의한 설계, 계약에 따른 설계, 계약에 의한 설계, 권리와 책임 문서화, 단정문, 런타임, 루프 불변식, 문서화, 방어 코드, 불변식의 다른 용도, 선행조건, 실용주의 편집증, 언어 지원, 완벽한 소프트웨어는 만들 수 없다, 의미론적 불변식, 전처리기, 컴파일러, 클래식 불변식, 후행조건


실용주의 편집증


-

완벽한 소프트웨어는 만들 수 없다.



-

우리는 방어적으로 코딩하도록 가르침 받았다. 만약 조금이라도 의심이 들면, 주어진 모든 정보를 확인한다. 잘못된 데이터를 찾아내기 위해 assertion 을 사용한다. 일관성을 확인하고 데이터 베이스 컬럼에 constraint 를 걸면서 대부분은 스스로 만족해한다.


하지만 실용주의 프로그래머들은 여기서 한 걸음 더 나아간다. ‘그들은 자기 자신 역시 믿지 않는다’ 어느 누구 심지어는 자기 자신도 완벽한 코드를 작성할 수 없음을 알기 때문에 실용주의 프로그래머는 자신의 실수에 대비해 방어적으로 코드를 짠다.





계약에 의한 설계


-

정직한 거래를 보장하는 최선의 해법 중 하나는 계약이다.

계약은 상대편은 물론 자신의 권리와 책임을 정의한다.

뿐만 아니라 한쪽이 계약을 어겼을 경우의 손해에 대해서도 계약 사항에 포함된다.





DBC


-

게약에 의한 설계는 단순하지만 강력한 기법으로, 프로그램의 정확성을 보장하기 위해 소프트웨어 모듈들의 권리와 책임을 문서화(및 이에 대한 동의)하는 데에 초점을 맞춘다.


정확한 프로그램이란 스스로 자신이 하는 일이라고 주장하는 것보다 많거나 적지도 않게 딱 그만큼만 하는 프로그램을 말한다.

이 주장을 문서화하고 검증하는 것이 계약에 의한 설계(Design By Constract, DBC) 이다.



-

소프트웨어 시스템의 모든 함수와 메서드는 뭔가를 한다.

그 뭔가를 시작하기 전에 해당 루틴은 세상의 상태에 대해 어떤 기대를 갖고 있을 테고, 루틴이 끝난 후에 세상의 상태가 어떠해야 한다는 진술을 할 수 있다.


선행조건(precondition)

    루틴이 호출되기 위해 참이어야 하는 것, 루틴의 요구사항.


후행조건(postcondition)

    루틴이 자기가 할 것이라고 보장하는 것, 루틴이 완료되었을 때 세상의 상태.


클래스 불변식(class invariant)

    호출자의 입장에서 볼 때는 이 조건이 언제나 참이라고 클래스가 보장.

    루틴의 내부 처리 중에는 불변식이 참이 아닐 수도 잇지만, 루틴이 종료하고 호출자로 제어권이 반환되는 때에는 불변식이 참이 되어야 한다.



-

계약 당사자 중 어느 한쪽이든 이 계약 내용을 지키지 못하면 배상이 이루어진다.

예를 들면, 예외가 발생하거나 프로그램이 종료하거나 하는 것이다.

무슨 일이 벌어지든지 간에 계약에 부응하지 못하는 게 버그가 되어버리는 실수를 저지르지 마라.



-

계약에 따른 설계를 하라.





DBC 구현


-

DBC 를 사용하는 최고의 장점은 요구사항과 보증의 문제를 전면으로 내세운다는 것이다.

입력 도메인 범위가 무엇인지, 경계 조건이 무엇인지, 루틴이 뭘 전달한다고 약속하는지(혹은 더 중요하게 무엇을 전달한다고 약속하지 않는지) 하는 것들을 설계 시기에 나열하는 것만으로도 더 나은 소프트웨어를 작성하는 데 엄청난 도움이 된다.


이런 것들을 명시하지 않으면 우연에 맡기는 프로그래밍으로 돌아가게 되고, 많은 프로젝트들이 시작하고 종료하고 또 실패한다.





단정문


-

가정문들을 문서화하는 것은 꽤나 훌륭한 출발이 되겠지만, 컴파일러가 대신 계약을 검사하도록 한다면 훨씬 더 큰 이익을 얻을 것이다.

몇몇 언어에서는 단정문을 사용해서 이걸 부분적으로나마 흉내 낼 수 있다.





언어 지원


-

DBC 를 자체 지원하는 언어(아이펠(Eiffel) 과 Sather)는 선행, 후행 조건을 컴파일러와 런타임 시스템에서 자동으로 검사한다.


C, C++, Java 같은 언어에서는 원 소스코드에 특별한 주석문으로 포함된 계약을 처리하는 전처리기가 있다.

그러나 전처리기는 내장 기능만큼 좋지는 않다.






DBC 와 일찍 멈추기


-

아이펠의 경우 선행조건은 require 키워드로 선언하고, 후행조건은 ensure 로 선언한다.



-

문제를 찾고 원인을 밝히기 위해서는, 사고가 났을 때 일찍 멈추는 것이 유리하다.





불변식의 다른 용도


-

호출자와 호출되는 루틴 중에 선행조건을 확인하는 것은 누구의 책임인가?

언어의 일부로 구현되어 있는 경우, 대답은 어느 쪽도 아니다.

선행조건은 호출자가 루틴을 부른 뒤, 그러나 루틴 자체로 들어가기 전에 무대 뒤에서 테스트된다.

명시적으로 체크해야 할 매개 변수가 하나라도 있으면, 이것은 호출자가 테스트를 수행해야 한다.





루프 불변식


-

ex)

int m = arr[0];

int i = 1;

// 반복문 불변식 : m = max(arr[0:i-1]])

while( i < arr.length ){

    m = Math.max(m, arr[i]);

    i = i + 1;

}





의미론적 불변식


-

고정 불변의 법칙인 요구사항과 새로운 경영진에 의해 얼마든지 바뀔 수 있는 단순한 정책을 혼동하지 말아야 한다.

우리가 의미론적 불변식이라는 용어를 사용하는 것은 이 때문이다.

불변식은 어떤 것의 바로 그 의미의 중심이 되어야 하며, 일시적인 정책(좀 더 동적인 비지니스 법칙)에 영향을 받으면 안 된다.


자격이 있는 요구사항을 찾았다면, 어떤 문서에든 잘 드러나도록 만들라.





동적 계약과 에이전트


-

‘자율’의 정의에 따르면 에이전트는 자신이 따르길 원치 않는 요구는 거절할 자유가 있다.

계약을 재협상할 자유가 있다.

“그걸 제공해 드릴 수는 없지만 만약 여러분이 이걸 주신다면 그럼 저는 뭔가 다른걸 드릴 수는 있겠어요.”




반응형

댓글