제어 흐름으로서의 예외는 심각한 반 패턴으로 간주됩니까? 그렇다면 왜 그렇습니까?


129

90 년대 후반에 나는 흐름 제어로 예외를 사용하는 코드베이스로 꽤 일했습니다. 전화 응용 프로그램을 구동하기 위해 유한 상태 머신을 구현했습니다. 최근에 MVC 웹 앱을 사용하고 있었기 때문에 그 시절을 생각 나게합니다.

둘 다 Controller다음에 갈 곳을 결정하고 대상 로직에 데이터를 제공합니다. DTMF 톤과 같은 구식 전화 도메인의 사용자 작업은 작업 방법의 매개 변수가되었지만 ViewResult, 와 같은 것을 반환하는 대신을 던졌습니다 StateTransitionException.

가장 큰 차이점은 행동 방법이 void기능이라는 것입니다. 나는이 사실로 내가 한 모든 일을 기억하지 못하지만, 15 년 전과 같이 그 직업 이후로 다른 직업의 생산 코드에서는 이것을 보지 못했기 때문에 많은 것을 기억하는 길을 가기조차 주저했습니다 . 나는 이것이 소위 반 패턴이라는 신호라고 생각했다.

이 경우입니까? 그렇다면 왜 그렇습니까?

업데이트 : 질문을 할 때 이미 @MasonWheeler의 답변을 염두에두고 내 지식에 가장 많이 추가 된 답변을 사용했습니다. 나는 그의 대답도 옳다고 생각합니다.



25
아닙니다. 파이썬에서 예외를 컨트롤 흐름으로 사용하는 것은 "파이 토닉"으로 간주됩니다.
user16764

4
Java와 같은 일을해야 한다면 분명히 예외를 throw하지 않을 것입니다. 예외가 아닌 오류가 아닌 Throwable 계층 구조에서 파생됩니다.
Thomas Eding

2
기존 답변에 추가하려면 다음과 같은 간단한 지침을 참조하십시오.- "행복한 길"에 예외를 사용하지 마십시오. 행복한 길은 (웹의 경우) 전체 요청이거나 단순히 하나의 객체 / 메소드 일 수 있습니다. 물론 다른 모든 제정신의 규칙은 여전히 ​​적용됩니다 :)
Houen

8
예외가 항상 응용 프로그램의 흐름을 제어하지 않습니까?

답변:


109

이에 대한 자세한 내용은 Ward 's Wiki에 있습니다. 및 언어 별 (에 대한 참조 - 일반적으로, 제어 흐름에 대한 예외의 사용은 많은 주목할만한 상황을 방지 패턴입니다 예를 들어 파이썬 ) 기침 예외 기침 .

일반적으로 안티 패턴 인 이유에 대한 간단한 요약으로 :

  • 본질적으로 정교한 GOTO 문은 예외입니다.
  • 따라서 예외로 프로그래밍하면 코드를 읽고 이해하기가 더 어려워집니다
  • 대부분의 언어에는 예외를 사용하지 않고 문제를 해결하도록 설계된 기존 제어 구조가 있습니다.
  • 효율성에 대한 인수는 최신 컴파일러에서 무시할 수있는 경향이 있으며 제어 흐름에는 예외가 사용되지 않는다는 가정하에 최적화하는 경향이 있습니다.

보다 자세한 정보는 Ward의 위키에서 토론을 읽으십시오.


이 질문의 복제본도 참조 하십시오.


18
답은 모든 상황에서 예외가 나쁜 것처럼 들리지만, 퀴션은 예외 사항을 흐름 제어로 중점적으로 다룹니다.
whatsisname

14
@MasonWheeler 차이점은 for / while 루프에 흐름 제어 변경 사항이 명확하게 포함되어 있으며 코드를 쉽게 읽을 수 있다는 것입니다. 코드에 for 문이 표시되면 루프 끝에 어떤 파일이 있는지 알아낼 필요가 없습니다. 고토는 어떤 신이 말했기 때문에 나쁘지 않습니다. 그들은 루핑 구조보다 따르기가 더 어려워서 나쁩니다. 예외는 비슷하지만 불가능하지는 않지만 혼동 될 수있을 정도로 어렵습니다.
Bill K

24
그런 다음 @BillK는이를 주장하며 예외가 어떻게 발생하는지에 대한 단순한 진술을하지 않습니다.
Winston Ewert

6
자, 그러나 진지하게, 서버 측 및 앱 개발자는 JavaScript에서 빈 catch 문으로 오류를 묻습니까? 시간이 많이 걸리는 불쾌한 표현형인데, 뛰지 않고 물어 보는 방법을 모르겠습니다. 오류는 당신의 친구입니다.
Erik Reppen

12
@ mattnz : if그리고 foreach또한 정교한 GOTOS입니다. 솔직히 goto와의 비교는 도움이되지 않는다고 생각합니다. 그것은 거의 망상적인 용어와 같습니다. GOTO 사용법은 본질적으로 악한 것이 아닙니다. 실제 문제가 있으며 예외 공유 할 수 있지만 예외 는 아닙니다. 그러한 문제를 듣는 것이 더 도움이 될 것입니다.
Eamon Nerbonne

110

예외가 사용 된 유스 케이스는 "현재 상황을 처리 할 수있는 컨텍스트가 충분하지 않기 때문에이 시점에서 제대로 처리 할 수없는 상황이 발생했습니다. 스택) 처리 방법을 알아야합니다. "

두 번째 사용 사례는 "방금 심각한 오류가 발생했기 때문에 현재 데이터 흐름이나 다른 손상을 방지하기 위해이 제어 흐름을 벗어나는 것이 계속 진행하는 것보다 중요합니다."

이 두 가지 이유 중 하나로 예외를 사용하지 않는 경우 더 좋은 방법이있을 것입니다.


18
그래도 질문에 대답하지 않습니다. 그들이 디자인 한 것은 무관합니다. 관련된 유일한 것은 제어 흐름에 사용하는 것이 좋지 않은 이유 입니다. 예를 들어 C ++ 템플릿은 한 가지 목적으로 설계되었지만 메타 프로그래밍에 사용하기에는 완벽합니다.
Thomas Bonini

6
@Krelp : 디자이너 는 우연히 Turing-complete 템플릿 시스템 으로 끝나는 등 많은 것을 예상하지 못했습니다 ! C ++ 템플릿은 여기서 사용하기에 좋은 예가 아닙니다.
메이슨 휠러

15
@Krelp-C ++ 템플릿은 메타 프로그래밍에 '완벽하지'않다. 그것들은 올바르게 얻을 때까지 악몽이며, 템플릿 천재가 아니라면 쓰기 전용 코드를 선호합니다. 더 좋은 예를 고르고 싶을 수도 있습니다.
Michael Kohne

예외는 특히 함수 구성 및 코드 간결성을 손상시킵니다. 예를 들어 경험이 부족한 동안 프로젝트에서 예외를 사용했으며 오랜 시간 문제가 발생했습니다 .1) 사람들이 그것을 기억해야하기 때문에 2) const myvar = theFunctionmyvar은 try-catch에서 작성해야하기 때문에 쓸 수 없습니다 . 따라서 더 이상 일정하지 않습니다. 그렇다고 C #에서 어떤 이유로 든 주류이므로 사용하지 않는다는 의미는 아니지만 어쨌든 줄이기 위해 노력하고 있습니다.
Hi-Angel

2
@AndreasBonini 디자인 / 컴파일러 / 런타임 구현 결정이 종종 디자인과 일치하기 때문에 설계 / 의도 된 사항. 예를 들어, 예외를 던지는 것은 누군가가 스택 추적 등과 같은 코드를 디버깅하는 데 도움이되는 정보를 수집하기 때문에 단순한 반환보다 훨씬 "비싸다"
binki

29

예외는 Continuations 및처럼 강력 GOTO합니다. 그것들은 보편적 인 제어 흐름 구조입니다.

일부 언어에서는 유일하게 범용 제어 흐름 구성입니다. 예를 들어, JavaScript에는 Continuations도없고 GOTO적절한 Tail Call도 없습니다. 자바 스크립트의 정교한 제어 흐름을 구현하고자한다면, 당신은 예외를 사용 할 수 있습니다.

Microsoft Volta 프로젝트는 임의의 .NET 코드를 JavaScript로 컴파일하기위한 (현재 단종 된) 연구 프로젝트였습니다. .NET에는 시맨틱이 JavaScript에 정확하게 매핑되지 않는 예외가 있지만 더 중요한 것은 Threads 가 있으며 어떻게 든 JavaScript에 매핑해야합니다. Volta는 JavaScript 예외를 사용하여 Volta Continuations를 구현 한 다음 Volta Continuations 측면에서 모든 .NET 제어 흐름 구조를 구현하여이를 수행했습니다. 그들은 가지고 있기 때문에, 제어 흐름과 같은 예외를 사용하는 다른 제어 흐름이 구성되지가 충분히 강력.

State Machines를 언급했습니다. SM은 적절한 테일 호출로 구현하기가 쉽지 않습니다. 모든 상태는 서브 루틴, 모든 상태 전환은 서브 루틴 호출입니다. SM은 GOTO또는 Coroutines 또는 Continuations로 쉽게 구현할 수도 있습니다 . 그러나 Java에는 이러한 네 가지가 없지만 예외 있습니다. 따라서 제어 흐름으로 사용하는 것이 좋습니다. (실제로 올바른 선택은 아마도 적절한 제어 흐름 구조를 가진 언어를 사용하는 것이지만 때로는 Java에 갇힐 수도 있습니다.)


7
우리가 적절한 꼬리 호출 재귀를 가졌다면 JavaScript로 클라이언트 측 웹 개발을 지배 한 다음 서버 측 및 모바일로 확산하여 와일드 파이어와 같은 궁극적 인 팬 플랫폼 솔루션으로 이어질 수 있습니다. 아아, 그러나 그것은 그렇지 않았다. 부족한 일류 기능, 폐쇄 및 이벤트 중심 패러다임을 망쳐 놓으십시오. 우리에게 정말로 필요한 것은 진짜였습니다.
Erik Reppen

20
@ErikReppen : 나는 당신이 단지 냉소적 인 것을 알고 있지만. . . 나는 정말 우리가 "자바 스크립트와 클라이언트 측 웹 개발을 주도했다"는 언어의 기능과는 아무 상관이 사실을 생각하지 않습니다. 그것은 그 시장에서 독점권을 가지고 있기 때문에 냉소로 쓸 수없는 많은 문제를 피할 수있었습니다.
ruakh

1
테일 재귀는 좋은 보너스가 될 것입니다 (향후 기능 기능을 더 이상 사용하지 않을 것입니다). 그렇습니다. 기능 관련 이유로 VB, Flash, Applets 등에서 이겼습니다. 복잡성을 줄이지 않고 손으로 정규화하지 않으면 어느 시점에서 실제 경쟁을했을 것입니다. 나는 현재 무시 무시한 C # + Java 스택을위한 21 개의 구성 파일의 재 작성을 처리하기 위해 Node.js를 실행하고 있으며, 내가 그렇게하는 유일한 사람은 아니라는 것을 알고 있습니다. 그것이 잘하는 것을 아주 잘합니다.
Erik Reppen

1
많은 언어에는 고 토스 (Goto) (유해한 것으로 간주 됨), 코 루틴 또는 연속체가 없으며 ifs, while 및 함수 호출 (또는 gosubs!)을 사용하여 완벽하게 유효한 흐름 제어를 구현합니다. 위의 모든 것을 나타내는 데 연속이 사용될 수있는 것처럼, 이들 대부분은 실제로 서로를 에뮬레이트하는 데 사용될 수 있습니다. 예를 들어, 코드를 코딩하는 방법이더라도 if를 수행하는 데 while을 사용할 수 있습니다. 따라서 고급 흐름 제어를 수행하는 데 예외가 필요하지 않습니다.
Shayne

2
글쎄, 당신은 경우에 대해 옳을 수도 있습니다. 그러나 C 스타일 형식의 "For"는 어색하게 언급 된 동안 사용될 수 있으며, 그런 다음 다른 모든 흐름 제어 양식을 에뮬레이트 할 수있는 유한 상태 기계를 구현하기 위해 if와 결합하여 사용할 수 있습니다. 다시 말하지만, 코딩 방법은 좋지만 그래. 그리고 다시, goto는 해로운 것으로 간주되었습니다. (그리고 예외가 아닌 상황에서 예외를 사용하는 것도 마찬가지입니다). 완벽하게 유효하고 매우 강력한 언어가 있으므로 예외도 제공하지 않으며 제대로 작동합니다.
Shayne

19

다른 사람들이 언급 한 것처럼 ( 예 :이 스택 오버플로 질문에서 ) 놀랍게도 원칙은 제어 흐름 전용 목적으로 예외를 과도하게 사용하는 것을 금지합니다. 반면에, 어떤 규칙이 100 % 정확하지 않으며, 예외가 "딱 맞는 도구가"이러한 경우는 항상있다 - 많은처럼 goto자체 방식에 의해의 형태로하는 선박 breakcontinue자바와 같은 언어로 된 종종 많이 피할 수있는 것은 아니지만 자주 중첩 된 루프에서 뛰어 내리는 완벽한 방법입니다.

다음 블로그 게시물은 로컬아닌 경우에 다소 복잡하지만 흥미로운 사용 사례를 설명합니다 ControlFlowException.

또한 jOOQ (Java 용 SQL 추상화 라이브러리) 내부 (면책 조항 : 공급 업체 에서 일함)에 대해 설명합니다 . 이러한 "예외"는 일부 "희귀 한"조건이 충족 될 때 SQL 렌더링 프로세스를 중단하는 데 때때로 사용됩니다.

이러한 조건의 예는 다음과 같습니다.

  • 바인드 값이 너무 많습니다. 일부 데이터베이스는 SQL 문에서 임의의 수의 바인드 값을 지원하지 않습니다 (SQLite : 999, Ingres 10.1.0 : 1024, Sybase ASE 15.5 : 2000, SQL Server 2008 : 2100). 이 경우 jOOQ는 SQL 렌더링 단계를 중단하고 인라인 된 바인드 값으로 SQL 문을 다시 렌더링합니다. 예:

    // Pseudo-code attaching a "handler" that will
    // abort query rendering once the maximum number
    // of bind values was exceeded:
    context.attachBindValueCounter();
    String sql;
    try {
    
      // In most cases, this will succeed:
      sql = query.render();
    }
    catch (ReRenderWithInlinedVariables e) {
      sql = query.renderWithInlinedBindValues();
    }
    

    매번 계산하기 위해 쿼리 AST에서 바인드 값을 명시 적으로 추출한 경우이 문제가 발생하지 않는 쿼리의 99.9 %에 대해 귀중한 CPU주기가 낭비됩니다.

  • 일부 로직은 "부분적으로"만 실행하려는 API를 통해 간접적으로 만 사용할 수 있습니다. 이 UpdatableRecord.store()메소드는 의 내부 플래그 에 따라 INSERTor UPDATE문을 생성합니다 Record. "외부"에서 우리는 어떤 종류의 로직 store()(예 : 낙관적 잠금, 이벤트 리스너 처리 등) 이 포함되어 있는지 알지 못 하므로 배치 레코드에 여러 레코드를 저장할 때 해당 로직을 반복하고 싶지 않습니다. 여기서는 store()SQL 문만 생성하고 실제로 실행하지는 않습니다. 예:

    // Pseudo-code attaching a "handler" that will
    // prevent query execution and throw exceptions
    // instead:
    context.attachQueryCollector();
    
    // Collect the SQL for every store operation
    for (int i = 0; i < records.length; i++) {
      try {
        records[i].store();
      }
    
      // The attached handler will result in this
      // exception being thrown rather than actually
      // storing records to the database
      catch (QueryCollectorException e) {
    
        // The exception is thrown after the rendered
        // SQL statement is available
        queries.add(e.query());                
      }
    }
    

    store()선택적으로 SQL을 실행 하지 않도록 사용자 정의 할 수있는 "재사용 가능한"API로 로직을 외부화 한 경우 유지 관리하기 어렵고 재사용하기 어려운 API를 작성하려고합니다.

결론

본질적으로, 이러한 비 로컬 gotos 의 사용법은 Mason Wheeler 가 그의 답변에서 말한 내용과 같습니다.

"이 상황에서 처리 할 수있는 컨텍스트가 충분하지 않기 때문에이 시점에서 제대로 처리 할 수없는 상황이 발생했습니다. 그러나 저를 호출 한 루틴 (또는 호출 스택의 상위 항목)은 처리 방법을 알아야합니다. "

두 가지 사용법 모두 ControlFlowExceptions대안에 비해 구현하기가 쉬웠으므로 관련 내부에서 리팩토링하지 않고도 광범위한 로직을 재사용 할 수 있습니다.

그러나 이것이 미래의 관리자에게 약간 놀람이라는 느낌이 남아 있습니다. 코드는 다소 정교하게 느껴지고이 경우에는 올바른 선택 이었지만 로컬 제어 흐름에는 예외를 사용하지 않는 것이 좋습니다 if - else.


11

제어 흐름에 예외를 사용하는 것은 일반적으로 반 패턴 으로 간주되지만 예외가 있습니다 (말장난 의도는 없음).

예외는 예외적 인 조건에 대한 것임을 천 번 언급했습니다. 손상된 데이터베이스 연결 예외적 인 조건입니다. 숫자 만 허용해야하는 입력 필드에 문자를 입력하는 사용자 는 그렇지 않습니다 .

함수 원인이 소프트웨어의 버그는 예를 들면, 불법 인수로 호출 할 수 null없습니다가 허용 곳 입니다 예외 조건.

예외가 아닌 것에 예외를 사용함으로써, 해결하려는 문제에 대해 부적절한 추상화를 사용하고 있습니다.

그러나 성능이 저하 될 수도 있습니다. 일부 언어는 예외 처리 구현이 다소 효율적이므로 선택한 언어에 효과적인 예외 처리가없는 경우 성능이 매우 비싸고 비용이 많이들 수 있습니다 *.

그러나 Ruby와 같은 다른 언어에는 제어 흐름에 대한 예외와 유사한 구문이 있습니다. 예외 상황은 raise/ rescue연산자에 의해 처리됩니다 . 그러나 예외와 같은 제어 흐름 구성에 throw/ catch를 사용할 수 있습니다 . **.

따라서 예외는 일반적으로 제어 흐름에 사용되지 않지만 선택한 언어에는 다른 관용구가있을 수 있습니다.

* 성능 비용이 많이 드는 예외 사용의 예 : 한때 성능이 좋지 않은 ASP.NET Web Form 응용 프로그램을 최적화하도록 설정되었습니다. 큰 테이블을 렌더링하는 데 int.Parse()약 약 80 건이 호출 되었습니다. 평균 페이지에 천 개의 빈 문자열이 있습니다. 수천 가지 예외를 처리하고 있습니다. 코드를 교체하여 int.TryParse()1 초간 면도했습니다! 모든 단일 페이지 요청에 대해!

**이 모두 같은 다른 언어에서 루비 오는 프로그래머를위한 매우 혼란 스러울 수 있습니다 throwcatch다른 많은 언어에서 예외와 관련된 키워드입니다.


1
"특별하지 않은 것에 예외를 사용함으로써, 해결하려는 문제에 대해 부적절한 추상화를 사용하고 있습니다."
Giorgio

8

예외를 사용하지 않고 오류 조건을 완전히 처리 할 수 ​​있습니다. 일부 언어, 특히 C는 예외가 없으며 사람들은 여전히 ​​매우 복잡한 응용 프로그램을 만들 수 있습니다. 예외가 유용한 이유는 동일한 코드에서 두 개의 본질적으로 독립적 인 제어 흐름을 간결하게 지정할 수 있기 때문입니다. 하나는 오류가 발생하고 다른 하나는 그렇지 않은 경우입니다. 그것들이 없으면 다음과 같은 코드가 완성됩니다.

status = getValue(&inout);
if (status < 0)
{
    logError("message");
    return status;
}

doSomething(*inout);

또는 하나의 값을 가진 튜플을 오류 상태로 반환하는 것과 같이 귀하의 언어로 동등한 경우도 있습니다. "비싼"예외 처리 방법을 지적하는 사람들은 종종 if위와 같은 추가 설명을 모두 무시 하고 추가 할 경우 추가해야합니다. 예외를 사용하지 마십시오.

이 패턴은 오류나 다른 "예외 조건"을 처리 할 때 가장 자주 발생하지만 다른 상황에서 이와 같은 상용구 코드를보기 시작하면 예외 사용에 대한 꽤 좋은 주장이 있습니다. 상황과 구현에 따라 두 가지 직교 제어 흐름이 있기 때문에 상태 시스템에서 예외가 올바르게 사용되는 것을 볼 수 있습니다. 하나는 상태를 변경하는 것과 다른 하나는 상태 내에서 발생하는 이벤트를위한 것입니다.

그러나 이러한 상황은 드물며 규칙에 예외를 적용하려는 경우 다른 솔루션보다 우월성을 보여줄 준비가 더 잘되어 있습니다. 그러한 정당성을 갖지 않는 편차를 반 패턴이라고합니다.


2
if 문이 '예외적 인'상황에서만 실패하는 한, 현대 CPU의 분기 예측 논리는 비용을 무시할 수 있습니다. 주의해서 매크로를 너무 많이 사용하지 않는 한 매크로가 실제로 도움을 줄 수있는 곳입니다.
James

5

파이썬에서는 예외가 생성기 및 반복 종료에 사용됩니다. 파이썬은 매우 효율적인 try / except 블록을 가지고 있지만 실제로 예외를 발생시키는 것은 약간의 오버 헤드가 있습니다.

파이썬에서 다중 레벨 나누기 또는 goto 문이 없기 때문에 때때로 예외를 사용했습니다.

class GOTO(Exception):
  pass

try:
  # Do lots of stuff
  # in here with multiple exit points
  # each exit point does a "raise GOTO()"
except GOTO:
  pass
except Exception as e:
  #display error

6
깊게 중첩 된 명령문의 어딘가에서 계산을 종료하고 일반적인 연속 코드로 이동해야하는 경우이 특정 실행 경로가 return대신로 함수로 고려 될 수 있습니다 goto.
9000

3
@ 9000 정확히 똑같은 것을 언급하려고했습니다 ... try:블록을 1 또는 2 줄로 유지하십시오 try: # Do lots of stuff.
wim

1
@ 9000, 어떤 경우에는 확실합니다. 그러나 프로세스가 일관된 선형 프로세스 인 경우 로컬 변수에 대한 액세스 권한이 손실되고 코드가 다른 위치로 이동합니다.
gahooa

4
@gahooa : 나는 너처럼 생각했었다. 내 코드의 구조가 잘못되었다는 신호였습니다. 더 많은 생각을하면 로컬 컨텍스트가 얽 히지 않고 매개 변수가 적고 코드 줄이 적고 매우 정확한 의미로 짧은 혼란으로 가득 차 있습니다. 나는 결코 뒤돌아 보지 않았다.
9000

4

이러한 예외 사용법을 스케치합시다.

알고리즘은 무언가를 찾을 때까지 재귀 적으로 검색합니다. 따라서 재귀에서 돌아와서 찾은 결과를 확인한 다음 돌아와야합니다. 그렇지 않으면 계속하십시오. 그리고 그것은 어떤 재귀 깊이에서 반복적으로오고 있습니다.

여분의 부울이 필요하고 found(그렇지 않으면 int 만 반환되었을 수있는 클래스에 압축되어야 함) 재귀 깊이에 대해 동일한 postlude가 발생합니다.

이러한 호출 스택 해제 는 예외입니다. 그래서 그것은 비 고토와 같고 더 즉각적이고 적절한 코딩 수단 인 것 같습니다. 필요하지 않고, 드문 사용법, 나쁜 스타일 일 수도 있지만, 요점까지는 그렇지 않습니다. 프롤로그 절단 작업과 비교할 수 있습니다.


흠, 실제로 반대 입장이나 불충분하거나 짧은 주장에 대한 다운 투표입니까? 정말 궁금합니다.
Joop Eggen

나는이 곤경에 정확히 직면하고 있습니다. 다음 질문에 대해 어떻게 생각하십니까? 예외를 재귀 적으로 사용하여 최상위 예외에 대한 이유 (메시지)를 누적합니다. codereview.stackexchange.com/questions/107862/…
CL22

@Jodes 나는 당신의 흥미로운 기술을 읽었지만, 나는 지금 꽤 점령되어 있습니다. 다른 사람이 문제에 대해 그녀의 빛을 비추기를 바랍니다.
Joop Eggen

4

프로그래밍은 일에 관한 것입니다

이에 대한 가장 쉬운 방법은 OOP가 수년에 걸쳐 진행 한 진전을 이해하는 것입니다. OOP (및 대부분의 프로그래밍 패러다임)에서 수행되는 모든 작업은 수행 해야 할 작업을 중심으로 모델링 됩니다 .

메소드가 호출 될 때마다 호출자는 "이 작업을 수행하는 방법을 모르지만 어떻게해야하는지 알기 때문에 나를 위해합니다"라고 말합니다.

이것은 어려움을 낳았습니다 : 호출 된 메소드가 일반적으로 작업을 수행하는 방법을 알고 있지만 항상 그렇지는 않은 경우 어떻게됩니까? 우리는 "나는 당신을 돕고 싶었지만 실제로는 그렇게 할 수 없었습니다."

이를 알리는 초기 방법론은 단순히 "쓰레기"값을 반환하는 것이 었습니다. 아마도 양의 정수를 기대할 수 있으므로 호출 된 메소드는 음수를 반환합니다. 이를 수행하는 또 다른 방법은 오류 값을 어딘가에 설정하는 것입니다. 불행하게도, 두 가지 방법으로 보일러 플레이트 let-me-check-over-here-to-make-sure-to-ever-sure-sure-sure-sure-sure-sure-kosher code가 발생했습니다. 상황이 더욱 복잡해지면서이 시스템은 무너집니다.

탁월한 비유

목수, 배관공 및 전기 기사가 있다고 가정 해 봅시다. 싱크대를 수리하기 위해 배관공을 원하기 때문에 그는 싱크대를 살펴 봅니다. 그는 만, 알 수 있다면 그것은 매우 유용 아니다 "죄송합니다, 나는 그것을 고칠 수 없습니다. 그것은 깨진입니다." 만약 그가보고 고쳐서 고칠 수 없다는 편지를 보내면 훨씬 더 나빠집니다. 이제 그가 원하는 것을하지 않았다는 것을 알기 전에 메일을 확인해야합니다.

당신이 선호하는 것은 "펌프가 작동하지 않는 것처럼 보이기 때문에 고칠 수 없었습니다."

이 정보를 통해 전기 기사가 문제를 살펴 보겠다고 결론을 내릴 수 있습니다. 아마도 전기 기사는 목수와 관련된 것을 발견 할 것이므로 목수에게 문제를 해결해야합니다.

도대체, 전기 기술자가 필요하다는 것을 알지 못할 수도 있고, 필요한 사람 을 모를 수도 있습니다 . 당신은 집 수리 사업의 중간 관리인이고 당신의 초점은 배관입니다. 그래서 당신은 당신이 문제에 대해 상사 라고 말한 다음 전기 기사에게 문제를 해결하도록 지시합니다.

이것은 예외적 인 모델링입니다 : 분리 된 방식으로 복잡한 고장 모드. 배관공은 전기 기술자에 대해 알 필요가 없습니다. 체인을 가진 사람이 문제를 해결할 수 있다는 것을 알 필요조차 없습니다. 그는 자신이 직면 한 문제에 대해서만보고합니다.

반 패턴?

좋습니다. 따라서 예외 지점 을 이해하는 것이 첫 번째 단계입니다. 다음은 반 패턴이 무엇인지 이해하는 것입니다.

안티 패턴으로 자격을 갖추려면

  • 문제를 풀다
  • 결정적으로 부정적인 결과를 초래하다

첫 번째 요점은 시스템이 제대로 작동하는 것입니다. 맞습니까?

두 번째 요점은 더 끈적 거립니다. 예외를 일반적인 제어 흐름으로 사용하는 주된 이유는 목적이 아니기 때문입니다. 프로그램의 특정 기능은 비교적 명확한 목적을 가져야하며, 그 목적을 선택하면 불필요한 혼란이 발생합니다.

그러나 그것은 결정적인 피해 가 아닙니다 . 일을하는 나쁜 방법이지만 이상하지만 반 패턴입니까? 아뇨. 그냥 ... 이상 해요.


적어도 전체 스택 추적을 제공하는 언어에서는 하나의 나쁜 결과가 있습니다. 코드가 많은 인라인으로 크게 최적화되므로 실제 스택 추적과 개발자가보고 싶어하는 스택 추적이 많이 다르므로 스택 추적 생성에 많은 비용이 듭니다. 예외를 과도하게 사용하는 것은 그러한 언어 (Java, C #)에서 성능이 매우 나쁩니다.
maaartinus

"그것은 일을하는 나쁜 방법입니다"-그것을 안티 패턴으로 분류하기에 충분하지 않습니까?
Maybe_Factor

@Maybe_Factor 개미 패턴의 정의에 따라, no.
MirroredFate
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.