코드 계약을 사용해야하는 이유


26

최근에 코드 계약에 대한 Microsoft의 프레임 워크를 우연히 발견했습니다.

나는 약간의 문서를 읽었으며 "정적 분석을 수행하지 않거나 종종 수행 할 수 없기 때문에 왜 이것을하고 싶습니까?"

이제는 다음과 같은 예외를 제외하고는 일종의 방어 적 프로그래밍 스타일을 가지고 있습니다.

if(var == null) { throw new NullArgumentException(); }

또한 NullObject Pattern을 많이 사용하고 있으며 거의 ​​문제가 없습니다. 여기에 단위 테스트를 추가하면 모든 준비가 완료된 것입니다.

나는 결코 단언을 사용하지 않았고 결코 놓치지 않았다. 꽤 대조적 인 것. 나는 의미없는 주장이 많은 코드를 정말로 싫어합니다. 이것은 나에게 소음이며 실제로보고 싶은 것에서 멀어집니다. 코드 계약은 적어도 Microsoft 방식과 거의 동일합니다. 코드에 많은 노이즈와 복잡성을 추가합니다. 어쨌든 99 %에서는 예외가 발생하므로 어설 션 / 계약 또는 실제 문제인지는 상관하지 않습니다. 프로그램 상태가 실제로 손상되는 경우는 거의 없습니다.

솔직히 코드 계약을 사용하면 어떤 이점이 있습니까? 전혀 있습니까? 이미 단위 테스트와 코드를 방어 적으로 사용하는 경우 계약 도입은 비용이 들지 않으며 코드가 무엇을하는지 알 수 없을 때처럼 관리자가 해당 방법을 업데이트 할 때 저주 할 코드에 소음을 줄 것이라고 생각합니다 쓸데없는 주장 때문에. 나는 그 가격을 지불 할 충분한 이유를 아직 보지 못했다.



1
왜 "정적 분석을 수행하지 않거나 수행 할 수 없습니다"라고 말합니까? 나는 이것이 Asserts 또는 방어 예외 던지기를 사용하는 것과는 대조적 으로이 프로젝트의 요점 중 하나라고 생각 했습니까?
Carson63000

@ Carson63000 문서를주의 깊게 읽으면 정적 검사기가 불필요하게 많은 경고를 출력 할 것입니다 (개발자가 승인 한 경우). 대부분의 정의 된 계약은 예외를 발생시키고 그 밖의 작업은 수행하지 않습니다. .
팔콘

@ 팔콘 : 이상하게도 내 경험은 완전히 다릅니다. 정적 분석은 완벽하게 작동하지 않지만 꽤 잘 작동하며 경고 수준 4 (가장 높음)에서 작업 할 때도 불필요한 경고가 거의 표시되지 않습니다.
Arseni Mourzenko

나는 그것이 어떻게 행동하는지 알아 내기 위해 그것을 시도해야한다고 생각합니다.
팔콘

답변:


42

정적 타이핑이 동적 타이핑보다 나은지 물었을 수도 있습니다. 끝이 보이지 않는 채 몇 년 동안 격렬한 논쟁. 동적 및 정적 유형 언어 연구 와 같은 질문을 살펴보십시오.

그러나 기본 논거는 컴파일 타임에 프로덕션에 빠졌을 수있는 문제를 발견하고 수정할 가능성이 있습니다.

계약 대 경비

가드와 예외가 있더라도 시스템이 의도 한 작업을 수행하지 못하는 문제에 여전히 직면 해 있습니다. 아마도 매우 비판적이고 실패하는 비용이들 것입니다.

계약 및 단위 테스트

이것에 대한 일반적인 주장은 테스트가 버그의 존재를 증명하는 반면 유형 (계약)은 부재를 증명한다는 것입니다. F.ex. 유형을 사용하면 프로그램의 경로가 유효하지 않은 입력을 제공 할 수 없다는 것을 알고 있지만 테스트는 대상 경로가 올바른 입력을 제공했음을 알려줄 수 있습니다.

계약 대 Null 개체 패턴

이제 이것은 적어도 같은 볼 파크에 있습니다. Scala 및 Haskell과 같은 언어는 프로그램에서 null 참조를 완전히 제거하는이 방법으로 큰 성공을 거두었습니다. (스칼라가 공식적으로 null을 허용하더라도 규칙은 절대로 사용하지 않습니다)

NRE를 제거하기 위해이 패턴을 이미 사용하는 경우 기본적으로 런타임 오류의 가장 큰 원인을 제거했습니다. 기본적으로 계약에서 허용하는 방식이 있습니다.

차이점은 계약에는 null을 피하기 위해 모든 코드를 자동으로 요구하는 옵션이 있으므로 더 많은 장소에서이 패턴을 사용하여 컴파일을 전달해야한다는 것입니다.

또한이 계약은 null 이외의 것을 대상으로하는 유연성을 제공합니다. 따라서 버그에 더 이상 NRE가 없으면 계약을 사용하여 다음으로 발생할 수있는 가장 일반적인 문제를 해결할 수 있습니다. 하나만? 범위를 벗어난 인덱스?

그러나...

말한 모든 것. 구문 노이즈 (및 구조적 노이즈) 계약이 코드에 추가되는 것은 상당히 상당하며 분석이 빌드 타임에 미치는 영향을 과소 평가해서는 안된다는 데 동의합니다. 따라서 시스템에 계약을 추가하기로 결정했다면 어떤 종류의 버그를 해결하려고하는지에 초점을 맞추는 것이 매우 신중할 것입니다.


6
프로그래머에게 좋은 첫 답변입니다. 커뮤니티에 참여하게되어 기쁩니다.

13

나는 "정적 분석을 수행하지 않거나 종종 수행 할 수 없다"는 주장이 어디에서 왔는지 모른다. 주장의 첫 부분은 분명히 잘못되었습니다. 두 번째는 "종종"의 의미에 달려 있습니다. 차라리 말 것 종종 , 그것은 정적 분석을 수행하고 거의 그것에서 실패하지 않습니다. 일반적인 비즈니스 응용 프로그램에서는 거의 결코 가까이 다가 가지 않습니다 .

첫 번째 이점은 다음과 같습니다.

이점 1 : 정적 분석

일반적인 어설 션과 인수 확인에는 단점이 있습니다. 코드가 실행될 때까지 연기됩니다. 반면에, 코드 계약은 코딩 단계에서 또는 애플리케이션을 컴파일하는 동안 훨씬 이전 단계에서 나타납니다. 오류를 빨리 발견할수록 오류를 수정하는 데 비용이 적게 듭니다.

이점 2 : 항상 최신 문서 종류

코드 계약은 또한 항상 최신 의 일종의 문서를 제공 합니다. 메소드의 XML 주석이 0보다 우수하거나 0이어야한다고 SetProductPrice(int newPrice)지시 newPrice하면 문서가 최신 상태가 되길 바라지 만 누군가가 메소드를 변경 newPrice = 0하여을 발생 ArgumentOutOfRangeException시키지만 해당 문서를 변경하지 않았 음을 발견 할 수도 있습니다 . 코드 계약과 코드 자체의 상관 관계를 고려할 때 동기화되지 않은 문서화 문제가 없습니다.

코드 계약에서 제공하는 문서는 XML 주석이 수용 가능한 값을 잘 설명하지 못하는 경우가 많습니다. 몇 번이나 궁금 경우였다 null거나 string.Empty또는 \r\n방법에 대한 권한이 부여 된 값이고, XML 코멘트는에 침묵했다!

결론적으로 코드 계약이 없으면 많은 코드가 다음과 같습니다.

일부 값은 허용하지만 다른 값은 허용하지 않지만 설명서가있을 경우 추측하거나 읽어야합니다. 실제로 문서를 읽지 마십시오. 구식입니다. 모든 값을 반복하면 예외가 발생하는 것을 볼 수 있습니다. 당신은 또한 반환 될 수있는 값의 범위를 추측해야합니다. 왜냐하면 내가 그것에 대해 조금 더 이야기 할지라도 지난 몇 년 동안 나에게 수백 가지의 변화가 있었기 때문에 사실이 아닐 수도 있습니다.

코드 계약을 통해 다음과 같이됩니다.

title 인수는 길이가 0..500 인 널이 아닌 문자열 일 수 있습니다. 뒤에 오는 정수는 양수 값이며, 문자열이 비어있는 경우에만 0이 될 수 있습니다. 마지막으로 IDefinitionnull을 반환 하지 않는 객체를 반환합니다 .

이점 3 : 인터페이스 계약

세 번째 이점은 코드 계약이 인터페이스에 권한을 부여한다는 것입니다. 다음과 같은 것이 있다고 가정 해 봅시다.

public interface ICommittable
{
    public ICollection<AtomicChange> PendingChanges { get; }

    public void CommitChanges();

    ...
}

어설 션과 예외 만 사용하여 비어 있지 않은 CommitChanges경우에만 호출 할 수 있도록하려면 PendingChanges어떻게해야합니까? 그것이 PendingChanges결코 결코 보장 되지 null않습니까?

이점 4 : 분석법 결과 시행

마지막으로, 네 번째 이점은 Contract.Ensure결과를 얻을 수 있다는 것 입니다. 정수를 반환하는 메서드를 작성할 때 값이 결코 열등하거나 0이 아닌지 확인하려면 어떻게해야합니까? 5 년 후 많은 개발자들의 많은 변화를 겪고 나서? 메소드가 여러 개의 리턴 포인트를 가지 자마자 Assert유지 보수의 악몽이됩니다.


코드 계약은 코드의 정확성을위한 수단 일뿐만 아니라 코드를 작성하는보다 엄격한 방법으로 고려하십시오. 비슷한 방식으로, 독점적 인 동적 언어를 사용하는 사람은 왜 언어 수준에서 유형을 적용 할 것인지 묻지 만 필요한 경우 어설 션에서 동일한 작업을 수행 할 수 있습니다. 할 수는 있지만 정적 타이핑은 사용하기 쉽고 많은 주장에 비해 오류가 적으며 자체 문서화가 가능합니다.

동적 타이핑과 정적 타이핑의 차이는 일반적인 프로그래밍과 계약에 의한 프로그래밍의 차이에 매우 가깝습니다.


3

나는 이것이 질문에 약간 늦었다는 것을 알고 있지만, Code Contracts에는 언급 할 다른 이점이 있습니다.

계약은 방법 외부에서 점검됩니다

분석법 내부에 보호 조건이있는 경우 검사가 발생하는 곳과 오류가보고되는 곳입니다. 그런 다음 스택 오류를 조사하여 실제 오류의 원인이 어디인지 확인해야합니다.

코드 계약은 메소드 내에 있지만 메소드를 호출하려고 할 때 메소드 외부에서 전제 조건을 점검합니다. 계약은 메소드의 일부가되어 호출 할 수 있는지 여부를 결정합니다. 즉, 실제 문제의 원인에 훨씬 가깝게 오류가보고됩니다.

많은 장소에서 요구되는 계약 보호 방법이 있다면 이것이 실질적인 이점이 될 수 있습니다.


2

정말 두 가지 :

  1. 툴링 지원, VS는 계약 데이터를 지능과 별도로 만들어 자동 완성 도움말의 일부가 될 수 있습니다.
  2. 서브 클래스가 메소드를 대체하면 계약을 사용하여 모든 검사 (LSP를 따르는 경우 여전히 유효해야 함)를 잃게되고 하위 클래스를 자동으로 따릅니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.