전달 된 인수로 메소드를 용서해야합니까? [닫은]


21

foo(String bar)특정 기준에 맞는 문자열에서만 작동 하는 메소드 가 있다고 가정하십시오 . 예를 들어, 소문자 여야하며 비어 있거나 공백 만 없어야하며 pattern과 일치해야합니다 [a-z0-9-_./@]+. 이 방법에 대한 설명서에는 이러한 기준이 명시되어 있습니다.

방법이이 기준에 대한 모든 편차를 기각해야합니까, 아니면 일부 기준에 대해 더 관대해야합니까? 예를 들어 초기 방법이

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
    }
    this.bar = bar;
}

그리고 두 번째 용서 방법은

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        bar = bar.toLowerCase().trim().replaceAll(" ", "_");
        if (!bar.matches(BAR_PATTERN_STRING) {
            throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
        }
    }
    this.bar = bar;
}

문서가 가능한 경우 변환되고 변환 된 값으로 설정 될 것임을 나타내도록 변경되어야합니까, 아니면 방법을 가능한 한 단순하게 유지하고 모든 편차를 거부해야합니까? 이 경우 bar응용 프로그램 사용자가 설정할 수 있습니다.

이를위한 주요 사용 사례는 특정 문자열 식별자로 저장소에서 객체에 액세스하는 사용자입니다. 저장소의 각 오브젝트에는 고유 한 문자열이 있어야 식별 할 수 있습니다. 이 리포지토리는 다양한 방법으로 (sql 서버, json, xml, 이진 등) 객체를 저장할 수 있으므로 대부분의 명명 규칙과 일치하는 가장 낮은 공통 분모를 식별하려고했습니다.


1
이것은 아마도 유스 케이스에 크게 의존합니다. 어느 쪽이든 합리적 일 수 있으며 두 가지 방법을 모두 제공하고 사용자가 결정하도록하는 클래스를 보았습니다. 이 방법 / 클래스 / 필드가 무엇을해야하는지 자세히 설명해 주시면 실제 조언을 제공 할 수 있습니까?
Ixrec

1
메소드를 호출하는 모든 사람을 알고 있습니까? 마찬가지로, 변경하면 모든 클라이언트를 확실하게 식별 할 수 있습니까? 그렇다면 성능 문제가 허용하는 한 관대하고 용서할 것입니다. 설명서를 삭제할 수도 있습니다. 그렇지 않은 경우 라이브러리 API의 일부인 경우 나중에 문서와 일치하도록 코드를 변경하면 버그 보고서가 생성되기 때문에 코드가 광고 된 API를 정확하게 구현했는지 확인합니다.
Jon Chesterfield

7
우려 분리에 따르면 필요한 경우 foo어떤 인수를 받아 들일 것인지에 대해 엄격한 함수를 사용해야하며와 함께 사용할 인수를 "정리"할 수있는 두 번째 도우미 함수가 있어야한다고 주장 할 수 있습니다 foo. 이러한 방식으로 각 방법은 자체적으로 수행해야하는 작업이 적으며보다 깨끗하게 관리하고 통합 할 수 있습니다. 이 경로를 따라 가면 예외가 많은 디자인에서 벗어나는 것이 도움이 될 것입니다. Optional대신 비슷한 것을 사용 foo하고 필요한 경우 예외 를 소비하는 함수를 가질 수 있습니다 .
gntskn

1
이것은 "누군가 나를 잘못 생각 했으니 용서해야합니까?"라고 묻는 것과 같습니다. 어느 한 곳 분명히 상황이있다 또는 다른 적절한이다. 프로그래밍은 인간 관계만큼 복잡하지는 않지만, 이와 같은 담요 처방이 효과가 없을 정도로 충분히 복잡합니다.
Kilian Foth

2
@Boggin 나는 또한 당신 이 견고성 원칙을 재고 하도록 지시 할 것이다 . 구현을 확장해야 할 때 어려움이 따르고 용서하는 구현은 확장 된 구현으로 모호한 경우를 초래합니다.

답변:


47

당신의 방법은 그것이 말한대로해야합니다.

이렇게하면 나중에 버그를 사용하거나 유지 관리자가 변경하는 동작을 방지 할 수 있습니다. 관리자는 진행 상황을 파악하는 데 많은 시간을 소비 할 필요가 없기 때문에 시간이 절약됩니다.

즉, 정의 된 로직이 사용자에게 친숙하지 않다면 아마도 개선되어야 할 것입니다.


8
이것이 열쇠입니다. 메소드가 말한대로 정확하게 수행하면 메소드를 사용하는 코더가 특정 사용 사례를 보상합니다. 그것이 유용하다고 생각하기 때문에 메소드로 문서화되지 않은 것을 수행하지 마십시오. 변경이 필요한 경우 컨테이너를 작성하거나 문서를 변경하십시오.
Nelson

나는 그 방법이 진공 상태에서 설계되어서는 안된다는 @Nelson의 의견에 덧붙였다. 코더가 사용할 것이라고 말하지만 보상 할 것이며 보상에 범용 가치가 있다면 클래스의 일부로 고려하십시오. (예를 들면,이 foo그리고 fooForUncleanString후자는 전자에 전달하기 전에 수정을 만드는 방법.)
Blrfl

20

몇 가지 사항이 있습니다.

  1. 구현시 문서화 된 계약서의 내용을 수행해야하며 더 이상 아무것도하지 않아야합니다.
  2. 단순성은 계약과 구현 모두에 중요하지만 전자에게는 더 중요합니다.
  3. 잘못된 입력을 수정하려고하면 계약 및 구현뿐만 아니라 사용에도 반 직관적으로 복잡성이 추가됩니다.
  4. 디버깅 가능성이 향상되고 효율성이 크게 저하되지 않는 경우 오류를 조기에 발견해야합니다.
    디버그 모드에서 논리 오류를 진단하기위한 디버그 주장이 있으며, 이는 대부분 성능 문제를 완화시킵니다.
  5. 사용 가능한 시간과 비용이 단순성을 지나치게 손상시키지 않으면 서 효율성은 항상 목표입니다.

사용자 인터페이스를 구현하면 친숙한 오류 메시지 (제안 및 기타 도움말 포함)가 좋은 디자인의 일부입니다.
그러나 API는 최종 사용자가 아닌 프로그래머를위한 것입니다.


입력에 대해 애매하고 관용적 인 실제 실험은 HTML입니다.
결과적으로 모든 사람들이 약간 다르게 행동하게되었으며 사양은 이제 특수한 사례로 가득한 거대한 책으로 기록되었습니다.
참조 포스텔의 법칙 ( " . 당신은, 당신은 다른 사람으로부터 동의 것에 자유주의 수 않는 것에 보수적 ")그의 비평가 감동 ( 또는 훨씬 더 좋은 일 MichaelT는의 나를 인식하게 ).


sendmail의 저자가 쓴 또 하나의 중요한 작품 : 견고성 원칙 재고

15

분석법의 행동은 명확하고 직관적이며 예측 가능하며 단순해야합니다. 일반적으로 발신자의 입력에 대해 추가 처리를하는 것이 매우 주저 해야합니다 . 발신자가 의도 한 바에 대한 그러한 추측은 원치 않는 행동을 일으키는 많은 경우를 가지고 있습니다. 파일 경로 결합처럼 간단한 작업을 고려하십시오. 결합되는 경로 중 하나가 루팅 된 것처럼 보이면 많은 (또는 아마도 대부분의) 파일 경로 결합 기능은 이전 경로를 자동으로 버립니다! 예를 /abc/xyz들어와 결합 /evil하면 결과가됩니다 /evil. 이것은 파일 경로를 결합 할 때 거의 의도 하지 않지만 이 방법으로 작동 하지 않는 인터페이스가 없기 때문에 버그가 있거나 이러한 경우를 다루는 추가 코드를 작성해야합니다.

즉, "용서"가 방법이 될하기위한 의미가 때 드문 경우가 말했다, 그러나한다 항상 결정하는 호출자의 힘 이내 여부 이러한 처리 단계는 자신의 상황에 적용됩니다. 따라서 다양한 상황에서 인수에 적용하려는 공통 전처리 단계를 식별 한 경우 다음에 대한 인터페이스를 노출해야합니다.

  • 전처리없이 원시 기능.
  • 전처리 단계 자체 .
  • 원시 기능과 전처리의 조합.

마지막은 선택 사항입니다. 많은 통화에서 사용하는 경우에만 제공해야합니다.

원시 기능을 노출하면 호출자가 필요할 때 전처리 단계없이이를 사용할 수 있습니다. 프리 프로세서 단계 자체를 노출하면 호출자가 함수를 호출하지 않는 상황이나 함수 호출 하기 전에 일부 입력을 사전 처리 하려는 경우 (예 : 다른 함수에 먼저 전달하려는 경우)에이를 사용할 수 있습니다. 조합을 제공하면 발신자가 번거 로움없이 둘 다 호출 할 수 있습니다. 이는 대부분의 발신자가이 방식으로 사용할 경우 주로 유용합니다.


2
예측 가능 +1 그리고 간단하게 또 다른 +1 (원합니다). 오히려 실수를 숨기려고 시도하는 것보다 실수를 찾아 수정하도록 도와주십시오.
존 M 간트

4

다른 사람들이 말했듯이, 문자열 매칭을 "용서"한다는 것은 추가적인 복잡성을 도입하는 것을 의미합니다. 이는 매칭을 구현하는 데 더 많은 작업을 의미합니다. 예를 들어 이제 더 많은 테스트 사례가 있습니다. 네임 스페이스에 의미 적으로 동일한 이름이 없는지 확인하기 위해 추가 작업을 수행해야합니다. 복잡성이 높을수록 미래에는 더 잘못 될 것이라는 의미이기도합니다. 자전거와 같은 간단한 메커니즘은 자동차와 같은보다 복잡한 메커니즘보다 유지 관리가 덜 필요합니다.

그렇다면 추가 비용을 지불 할 가치가있는 관대 한 문자열이 있습니까? 다른 사람들이 지적했듯이 유스 케이스에 달려 있습니다. 문자열이 외부 입력의 일종이라면 제어 할 수 없으며 관대 한 일치에 대한 확실한 이점 있다면 그만한 가치가 있습니다. 아마도 공간 문자와 대문자 사용에 대해 매우 양심적이지 않은 최종 사용자가 입력 한 것일 수 있으며, 제품을보다 쉽게 ​​사용할 수 있도록하는 강력한 동기가 있습니다.

다른 한편으로, 입력이 예를 들어, 기술적 인 사람들에 의해 조립 된 속성 파일들로부터 온 "Fred Mertz" != "FredMertz"다면, 나는 그 매칭을 더 엄격하게하고 개발 비용을 절약하는 경향 이 있다는 것을 이해해야한다 .

어쨌든 선행 및 후행 공백을 자르고 무시하는 데 가치가 있다고 생각합니다. 그런 종류의 문제를 디버깅하는 데 너무 많은 시간이 낭비되는 것을 보았습니다.


3

이 질문이 나오는 맥락을 언급했습니다.

주어진 방법을 사용하면 메서드가 한 가지만 수행하고 문자열에 대한 요구 사항을 주장하고 그에 따라 실행하게합니다. 여기서는 변환하지 않습니다. 간단하게 유지하고 명확하게 유지하십시오. 문서화 하고 문서와 코드가 서로 동기화되도록 노력하십시오.

좀 더 관용적 인 방식으로 사용자 데이터베이스에서 제공되는 데이터를 변환하려면 해당 기능을 별도의 변환 방법에 넣고 기능 과 관련된 기능을 문서화하십시오 .

어떤 시점에서 기능의 요구 사항을 측정하고 명확하게 문서화해야하며 실행을 계속해야합니다. 그의 시점에서 "용서"는 약간의 음소거입니다. 그것은 디자인 결정이며, 그 주장을 변경하지 않는 함수를 주장 할 것입니다. 함수가 입력을 변경하면 클라이언트에 필요한 일부 유효성 검사가 숨겨집니다. 변이를 수행하는 기능이 있으면 클라이언트가 올바르게 처리하는 데 도움이됩니다.

여기서 가장 큰 강조점은 명확하고 코드의 기능을 문서화하는 것 입니다.


-1
  1. doSomething (), takeBackUp ()과 같은 조치에 따라 메소드 이름을 지정할 수 있습니다.
  2. 유지 보수를 쉽게하기 위해 공통된 계약과 다른 절차에 대한 검증을 유지할 수 있습니다. 사용 사례에 따라 전화하십시오.
  3. 방어 적 프로그래밍 : 당신의 프로시 저는 다음을 포함하여 광범위한 입력을 처리합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.