모든 조건을 충족해야하는 경우에 사다리-중복 최종 조항을 추가해야합니까?


10

이것은 내가 최근에 많이하고있는 일이다.

예:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else if (i > current) {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

종종 if / else 사다리는 이것보다 훨씬 더 복잡합니다 ...

마지막 조항을 참조하십시오? 중복입니다. 사다리는 궁극적으로 가능한 모든 조건을 잡아야합니다. 따라서 다음과 같이 다시 작성할 수 있습니다.

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

이것이 내가 코드를 작성하는 데 사용한 방법이지만이 스타일을 싫어합니다. 내 불만은 코드의 마지막 부분이 실행될 조건이 코드에서 명확하지 않다는 것입니다. 따라서이 조건을보다 분명하게 작성하기 위해 명시 적으로 작성하기 시작했습니다.

하나:

  • 명백하게 최종 소진 상태를 작성하는 것은 내 자신의 아이디어이며, 나는 내 자신의 아이디어에 대한 나쁜 경험을 가지고 있습니다. 일반적으로 사람들은 내가하고있는 일이 얼마나 끔찍한 지에 대해 비명을 지 릅니다. 차선책;
  • 이것이 나쁜 생각 일 수있는 한 가지 힌트 : Javascript에는 적용되지 않지만 다른 언어에서는 컴파일러가 함수의 끝에 도달하는 제어에 대한 경고 또는 오류를 발생시키는 경향이 있습니다. 그런 일을하는 것은 너무 인기가 없거나 잘못하고 있습니다.
    • 컴파일러 불만으로 인해 때로는 의견에 최종 조건을 쓰게되었지만 코드와 달리 의견이 실제 프로그램 의미에 영향을 미치지 않기 때문에 그렇게하는 것이 끔찍한 것 같습니다.
    } else { // i > current
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }

뭔가 빠졌습니까? 아니면 내가 묘사 한 것을하는 것이 좋습니까, 아니면 나쁜 생각입니까?


코드의 중복성이 결함 가능성을 증가 시킨다는 @Christophe의 우수 답변에 +1. 효율성 문제 도 훨씬 적습니다 . 이를 확장하기 위해 문제의 코드 예제와 관련하여 일련의 if-else-if를 다른 것이없는 경우와 별도로 별도의 것으로 작성할 수 있지만 if-else가 독자에게 독점적 대안의 개념을 제시 한 이후로는 일반적으로 그렇지 않습니다 일련의 독립적 인 조건보다는 (효율적이지 않기 때문에 모든 조건이 하나의 일치 후에도 평가되어야하므로).
Erik Eidt

@ErikEidt>는 함수에서 반환되거나 루프에서 "중단"하지 않는 한 +1과 일치하더라도 모든 조건을 평가해야한다고 말합니다 (위 예에서는 해당되지 않음).
Darek Nędza 12

1
+1, 좋은 질문입니다. 제쳐두고 NaN의 존재에서 예제가 완전한 것은 아닙니다.
모노 셀

답변:


6

두 가지 방법 모두 유효합니다. 그러나 장단점을 자세히 살펴 보겠습니다.

를 들어 if사소한 조건 쇄, 정말 중요하지 않습니다 여기에 같은 :

  • final로 else독자가 어떤 조건에서 다른 조건이 트리거되는지 알아내는 것이 분명합니다.
  • 마지막으로 else if, 독자가 else모두 다루었 으므로 추가 사항 이 필요 하지 않다는 것이 분명 합니다.

그러나 if여러 변수의 상태를 복잡한 논리식과 결합하여 더 복잡한 조건에 의존하는 많은 체인이 있습니다. 이 경우 덜 분명합니다. 그리고 각 스타일의 결과는 다음과 같습니다.

  • final else: 브랜치 중 하나가 선택되었음을 확신합니다. 하나의 사례를 잊어 버린 경우 마지막 분기를 거치므로 디버깅 중에 마지막 분기를 선택하고 다른 것을 예상 한 경우 신속하게 알아낼 수 있습니다.
  • final else if: 코드에 대한 중복 조건을 도출해야하며, 이로 인해 모든 경우를 다루지 않는 잠재적 인 오류 소스가 생성됩니다. 또한 사례를 놓친 경우 아무 것도 수행되지 않으며 무언가 누락 된 것을 찾는 것이 더 어려울 수 있습니다 (예 : 설정해야하는 일부 변수가 이전 반복에서 값을 유지하는 경우).

따라서 최종 중복 조건은 위험의 원천입니다. 이것이 내가 파이널에 가기를 제안하는 이유 else입니다.

편집 : 고 신뢰성 코딩

높은 신뢰성을 염두에두고 개발하는 경우 예기치 않은 상황을 포착하기 위해 중복 명시 적 결승 else if을 결승 으로 완료하는 다른 변형이 필요할 수 있습니다 else.

이것은 방어적인 코딩입니다. SEI CERT 또는 MISRA 와 같은 일부 보안 사양에서 권장됩니다 . 일부 정적 분석 도구 는이를 체계적으로 검사 하는 규칙 으로 구현하기도 합니다 (컴파일러 경고를 설명 할 수 있음).


7
마지막 중복 및 조건 후에 항상 "당신은 나에게 도달해서는 안됩니다!"라는 예외를 던지는 다른 것을 추가하면 어떨까요? -접근 방식의 일부 문제를 완화 할 수 있습니까?
gaazkam

3
@gaazkam 네, 이것은 매우 방어적인 코딩 스타일입니다. 따라서 여전히 최종 조건을 계산해야하지만 복잡한 오류가 발생하기 쉬운 체인의 경우 최소한 빨리 알아낼 수 있습니다. 이 변형에서 볼 수있는 유일한 문제는 명백한 경우에 약간 과잉이라는 것입니다.
Christophe

@gaazkam 난 당신의 의견에 언급 된 추가 아이디어를 해결하기 위해 내 답변을 편집했습니다
Christophe

1
@gaazkam 예외를 던지는 것이 좋습니다. 그렇다면 메시지에 예상치 못한 값을 포함시키는 것을 잊지 마십시오. 재현하기 어려울 수 있으며 예상치 못한 값은 문제의 원인에 대한 단서를 제공 할 수 있습니다.
Martin Maat

1
또 다른 옵션은 assert결승전 에 넣는 것 입니다 else if. 그러나 스타일 가이드는 그것이 좋은 아이디어인지에 따라 다를 수 있습니다. ( assert프로그래머가 망쳐 놓지 않는 한의 상태 는 절대로 거짓 이 되어서는 안됩니다. 이것은 적어도 의도 된 목적으로이 기능을 사용하는 것입니다. 그러나 많은 사람들이 그것을 잘못 사용하여 많은 상점들이 그것을 완전히 금지 시켰습니다.)
Kevin

5

지금까지 답변에서 누락 된 것은 어떤 종류의 실패가 덜 해로운 지의 문제입니다.

당신의 논리가 좋으면 실제로 당신이하는 일이 중요하지 않으며, 중요한 경우는 버그가있는 경우에 발생합니다.

최종 조건을 생략합니다. 최종 옵션이 옳지 않은 경우에도 실행됩니다.

최종 조건을 추가하기 만하면됩니다. 상황에 따라 옵션이 실행되지 않습니다. 상황에 따라 단순히 표시에 실패하거나 (해가 적음) 나중에 나중에 null 참조 예외가 발생할 수 있습니다 (디버깅 일 수 있음) 고통.)

최종 조건부와 예외를 추가합니다.

이러한 옵션 중 가장 적합한 옵션을 결정해야합니다. 개발 코드에서 나는 이것을 생각할 필요가 없다고 생각한다. 세 번째 경우를 보라. 그러나, 아마도 circle.src를 오류 이미지로 설정하고 circle.alt를 던지기 전에 오류 메시지로 설정했을 것입니다. 누군가 나중에 어설 션을 해제하기로 결정하면이로 인해 오류가 발생하지 않습니다.

고려해야 할 또 다른 사항-복구 옵션은 무엇입니까? 때로는 복구 경로가 없습니다. 내가 생각하는 것은 이것이 Ariane V 로켓의 첫 발사입니다. 부스터가 파괴되는 잡히지 않은 / 0 (실제로 나누기 오버플로) 오류가 발생했습니다. 실제로 충돌 한 코드는 그 시점에서 어떤 목적도 달성하지 못했으며, 스트랩 온 부스터가 점등되는 순간에 무력화되었습니다. 그들이 궤도 또는 붐에 불이 들어 오면 최선을 다하고 오류를 허용 할 수 없습니다. (이로 인해 로켓이 길을 잃으면 범위 안전 요원이 열쇠를 돌립니다.)


4

내가 추천하는 것은 assert마지막 두 가지 스타일 중 하나를 사용하는 것입니다.

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else {
        assert i > current
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

또는 데드 코드 어설 션 :

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else if (i > current) {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    } else {
        assert False, "Unreachable code"
    }
}

코드 범위 도구는 종종 범위 보고서에서 "assert False"와 같은 코드를 무시하도록 구성 될 수 있습니다.


조건을 어설 션에 넣으면 분기의 조건을 명시 적으로 문서화 할 수 있지만 주석과 달리 어설 션 조건을 실제로 확인할 수 있으며 개발 중이나 프로덕션 환경에서 어설 션을 사용하도록 설정하면 실패합니다 (일반적으로 어설 션을 사용하도록 설정하는 것이 좋습니다) 성능에 너무 영향을 미치지 않으면 프로덕션에서).


1
나는 첫 번째 옵션이 마음에 들지 않으며 두 번째 옵션은 불가능해야한다는 것이 훨씬 명확합니다.
Loren Pechtel

0

조건을 평가하는 "어설 션 된"매크로를 정의했으며 디버그 빌드에서는 디버거에 속합니다.

따라서 세 가지 조건 중 하나에 해당되는지 100 % 확신한다면 다음과 같이 씁니다.

If condition 1 ...
Else if condition 2 .,,
Else if asserted (condition3) ...

따라서 하나의 조건이 충족되고 어설 션에 대한 추가 분기가 필요하지 않다는 것이 명확 해집니다.


-2

나는 완전히 다른 것을 피하는 것이 좋습니다 . 사용하여 if코드 블록이 손잡이로되어 있는지를 선언하고, 기능을 종료하여 블록을 종료합니다.

결과적으로 매우 명확한 코드가 생성됩니다.

setCircle(circle, i, { current })
{
    if (i == current)
    {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
        return
    }
    if (i < current)
    {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
        return
    }
    if (i > current)
    {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
        return
    }
    throw new Exception("Condition not handled.");
}

마지막 if은 물론 중복입니다 ... 오늘. 미래의 일부 개발자가 블록을 다시 정렬하면 매우 중요한 생각이 될 수 있습니다. 거기에두면 도움이됩니다.


1
첫 번째 브랜치를 실행하면 두 번째 테스트의 결과가 변경 될 수 있는지 고려해야하므로 실제로는 매우 불분명합니다. 무의미한 복수 반환. 또한 조건이 사실이 아닐 수도 있습니다.
gnasher729

실제로 의도적으로 여러 사례를 취할 수있을 때 이와 같은 if 문을 작성합니다. 대체를 허용하지 않는 switch 문이있는 언어에서 특히 유용합니다. 나는 선택이 상호 배타적이라면 사례가 상호 배타적이라는 것을 분명히하기 위해 작성되어야한다고 생각합니다 (다른 것을 사용하여). 그리고 만약 그렇게 작성되지 않았다면, 그 사례는 상호 배타적이지 않다는 것입니다 (이를 통해 가능합니다).
Jerry Jeremiah

@ gnasher729 나는 당신의 반응을 완전히 이해합니다. 나는 "다른 사람들을 피하고" "초기 돌아 오는"문제를 겪었던 매우 똑똑한 사람들을 알고 있습니다. 이러한 아이디어는 객관적이고 측정 가능하게 복잡성을 감소시키기 때문에 시간을내어 아이디어에 익숙해지고 아이디어를 살펴 보는 것이 좋습니다. 조기 반품은 실제로 첫 번째 요점을 해결합니다 (분기가 다른 테스트를 변경할 수 있는지 고려해야 함). 그리고 "조건이없는 가능성"은 여전히 ​​관계없이 존재합니다. 이 스타일을 사용하면 숨겨진 논리 결함이 아닌 명백한 예외가 발생합니다.
존 우

그러나 두 스타일의 순환 복잡성이 정확히 동일하지 않습니까? 즉 조건 수와 동일
gaazkam
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.