[프로그래밍] 계약에 의한 설계와 서브타이핑
계약에 의한 설계(Design by Contract, DbC)(계약 프로그래밍, 계약에 의한 프로그래밍)는 컴포넌트 간 계약(contract)을 기반으로 하는 소프트웨어 설계 기법이다. 계약이란 소프트웨어를 구성하는 컴포넌트 중 클라이언트 컴포넌트와 서버 컴포넌트 간의 상호작용에 따른 오퍼레이션(동작)에 관한 명세(규약)를 의미한다. 이 계약은 객체 간 상호작용 또는 협력의 제약조건이 되기도 한다.
인터페이스에 대한 프로그래밍을 통해 메서드(또는 함수)의 시그니처(메서드명, 반환 타입과 파라미터 타입)를 정하고 이를 따르도록 함으로써 객체 간 상호작용은 어느정도 명세화될 수 있지만 오퍼레이션의 구체적인 구현 내용까지 제어되지는 않는다. 클라이언트는 메서드의 시그니처를 확인하여 요청이 어떤 서버에 의해 처리될 수 있는지, 서버가 요청에 대한 어떤 응답을 주는지를 알 수 있다. 하지만 메서드 시그니처는 클라이언트의 요청과 서버의 응답이 올바른지, 관련 데이터가 정합성을 따르는지에 대한 정보를 제공하지는 않는다. 계약에 의한 설계는 객체 간 상호작용에 계약이라는 제약을 가하여 특정 조건(비즈니스 로직)을 만족시키는 올바른 객체 간 상호작용이 일어날 수 있도록 한다.
계약에 의한 설계에서 계약의 종류는 다음과 같다.
- 사전조건 (precondition): 메서드를 호출하는 클라이언트가 만족해야하는 조건이다. 사전조건을 만족시키는 것은 메서드를 호출하는 클라이언트의 의무이다.
- 사후조건 (postcondition): 메서드를 실행(처리)하는 서버가 만족해야하는 조건이다. 사후조건을 만족시키는 것은 메서드를 실행하는 서버의 의무이다. 클라이언트가 사전조건을 만족시켰지만 서버가 사후조건을 만족시키지 못한 경우 서버는 클라이언트에게 예외를 던져야 한다.
- 불변식 (invariant): 일반적으로 불변식이란 프로그램이 유효한 상태를 유지하기 위해 항상 참이어야 하는 일련의 단언(assertion)을 말한다. 계약에서는 항상 참이라고 보장되는 서버의 조건이 된다. 메서드가 실행되기 전이나 종료된 후에 불변식은 항상 참이어야 한다. 메서드가 실행되는 도중에는 불변식을 만족시키지 못할 수도 있다. 이 경우 계약이 위반되는 것으로 볼 수 있다.
서브타이핑(subtyping)이란 상속 관계에 있는 타입에서 하위 타입이 상위 타입을 대체하는 것을 말한다. 계약에 의한 설계에서 계약의 만족 여부에 따라 서브타이핑의 가능 여부가 변경되기도 한다. 아키텍처 및 소프트웨어 설계 원칙 중 하나인 SOLID 원칙에서 리스코프 치환 윈칙(Liskov Substitution Principle, LSP)이란 상호 대체 가능한 구성요소를 이용하여 소프트웨어를 만들기 위해 구성요소들은 반드시 서로 치환 가능해야 한다는 계약을 반드시 지켜야 함을 의미한다. 계약이 위반되면 서브타이핑이 불가능해질 수 있다. 계약의 위반은 리스코프 치환 원칙 위반을 의미한다. 따라서 객체지향 프로그래밍의 다형성을 통해 변경에 따른 유연성과 확장성을 설계에 부여하기 위해서는 계약을 위반하는 상황을 피해야 한다.
계약이 위반됨에 따라 서브타이핑이 불가능한 경우는 다음과 같다.
- 하위 타입에 정의된 사전조건을 강화하는 경우 하위 타입을 사용하는 클라이언트는 하위 타입을 상위 타입으로 대체할 수 없다. 메서드를 호출하는 클라이언트는 기존 보다 강화된 사전조건을 만족시켜야 하며 이는 계약 위반이다. 클라이언트의 변경이 필요하다.
- 하위 타입에 정의된 사후조건을 완화하는 경우 하위 타입을 사용하는 클라이언트는 하위 타입을 상위 타입으로 대체할 수 없다. 클라이언트의 요청을 받아 메서드를 실행하는 서버는 기존 보다 완화된 사후조건을 만족시키면 되지만 기존 보다 완화된 사후조건을 만족하는 서버의 응답은 클라이언트가 기대하던 응답과는 다르므로 이는 계약 위반이다.
- 상위 타입이 던지는 예외와 하위 타입이 던지는 예외가 서로 상속 관계가 아닌 경우 하위 타입은 상위 타입을 대체할 수 없다. 클라이언트는 상위 타입 대신 하위 타입을 사용했을 때 발생하는 예외를 처리할 수 없다. 이는 계약 위반이다.
Comments