개발자는 진술이 부정 조건을 가져서는 안되며 항상 else 블록을 가져야한다고 주장합니다.


169

나는 나보다 더 노련한 개발자입니다. 우리는 프로그래밍 관행에 대해 이야기하고 있었고 'if'문에 대한 그의 접근에 의해 뒤처졌습니다. 그는 내가 이상하다고 생각하는 if 문에 관한 몇 가지 관행을 주장합니다.

먼저 if 문 뒤에 넣을 것이 있든 없든 else 문이 와야합니다. 다음과 같은 코드가 생성됩니다.

if(condition) 
{
    doStuff();
    return whatever;
}
else
{
}

둘째 , false보다는 true 값을 테스트하는 것이 좋습니다. 즉, '! doorOpened'변수 대신 'doorClosed'변수를 테스트하는 것이 좋습니다.

그의 주장은 코드가하는 일을 더 명확하게 한다는 것 입니다.

조건을 충족하지 않을 때 무언가를하고 싶다면이 두 규칙을 조합하면 이러한 종류의 코드를 작성할 수 있기 때문에 다소 혼란 스럽습니다.

if(condition)
{
}
else
{
    doStuff();
    return whatever;
}

이것에 대한 나의 느낌은 실제로 매우 추악하거나 품질 개선이 있다면 무시할 수 있다는 것입니다. 그러나 후배로서, 나는 본능을 의심하기 쉽다.

그래서 내 질문은 : 그것은 좋은 / 나쁜 / "무관 한"연습입니까? 일반적인 관행입니까?



57
동료가 생명과 사지가 위험에 처한 배경에서 비롯 될 수 있습니까? 필자는 엄청나게 많은 테스트와 자동 분석이 코드에서 수행되고 잘못하는 것이 문자 그대로 누군가의 생명을 희생시킬 수있는 시스템에서 이런 종류의 언급을 봤다고 생각합니다.
jpmc26

11
회사 코드 스타일 가이드는 무엇을 말합니까?
Thorbjørn Ravn Andersen

4
"두 번째"질문에 대한 부분 응답. 액션 블록 중 하나가 길고 다른 블록이 짧은 경우 짧은 블록을 먼저 배치하는 조건을 테스트하여 코드를 읽을 때 놓칠 가능성이 줄어 듭니다. 그 조건은 부정 일 수도 있고, 참인지 테스트하기 위해 이름을 바꿀 수도 있습니다.
Ethan Bolker 2016 년

9
Resharper는 "코드가 중복되어 쓸모가 없습니다. 삭제 / 리팩터링하겠습니까?"
BgrWorker 2018 년

답변:


184

명시 적 else블록

첫 번째 규칙은 코드를 오염시켜 더 읽기 쉽고 오류가 발생하지 않도록합니다. 동료의 목표는 개발자가 조건이로 평가 될 수 있음을 완전히 알고 있음을 보여줌으로써 명시적인 것 false입니다. 명시 적으로 작성하는 것이 좋지만, 이러한 명시 성으로 인해 3 줄의 추가 코드 비용이 발생해서는 안됩니다 .

나는 if진술이 반드시 else또는 뒤에 하나 또는 그 뒤에 올 필요는 없다는 사실을 언급 하지도 않습니다 elif.

return진술 의 존재 는 상황을 악화시킵니다. 실제로 else블록 내에서 실행할 코드가 있더라도 다음과 같이하면 더 읽기 쉽습니다.

if (something)
{
    doStuff();
    return whatever;
}

doOtherThings();
return somethingElse;

이것은 코드가 두 줄을 덜 차지하게하고 else블록을 들여 쓰지 않습니다 . 가드 조항 이 전부입니다.

그러나 동료의 기술은 공백없이 스택 형 조건부 블록의 매우 불쾌한 패턴을 부분적으로 해결할 수 있습니다.

if (something)
{
}
if (other)
{
}
else
{
}

이전 코드에서 첫 번째 if블록 이후의 줄 바꿈이 없으면 코드를 잘못 해석하기가 매우 쉽습니다. 그러나 동료의 규칙에 따라 코드를 잘못 읽는 것이 더 어려울 수 있지만 더 쉬운 해결책은 단순히 개행을 추가하는 것입니다.

테스트 true하지 않는,false

두 번째 규칙은 의미가 있지만 현재 형식은 아닙니다.

닫힌 문을 테스트하는 것이 열리지 않은 문을 테스트하는 것보다 직관적 이라는 것은 거짓이 아닙니다 . 부정, 특히 중첩 부정은 일반적으로 이해하기 어렵습니다.

if (!this.IsMaster || (!this.Ready && !this.CanWrite))

이를 해결하려면 빈 블록을 추가하는 대신 관련성이있는 경우 추가 속성을 작성하거나 로컬 변수를 작성하십시오 .

위의 조건은 쉽게 읽을 수 있습니다.

if (this.IsSlave || (this.Synchronizing && this.ReadOnly))

169
빈 블록은 항상 실수처럼 보입니다. 즉시 관심을 끌고 '이게 왜 이래?'라고 물을 것입니다.
Nelson

50
@Neil 조건을 부정하는 데 반드시 추가 CPU 시간이 필요하지는 않습니다. x86으로 컴파일 된 C는 점프 명령을 JZ(Jump if Zero) if (foo)에서 JNZ(Jump if Not Zero)로 바꿉니다 if (!foo).
8bittree

71
" 명확한 이름으로 추가 특성 작성 ": 도메인에 대한 심층 분석이 없으면 로컬 범위 (특정 비즈니스 규칙의 적용)를 해결하기 위해 글로벌 범위 (원래 클래스)가 변경 될 수 있습니다. 여기서 수행 할 수있는 한 가지는 "var isSlave =! this.IsMaster"와 같은 원하는 상태로 로컬 부울을 작성하고 다른 여러 특성을 작성하는 대신 로컬 부울로 if를 적용하는 것입니다. 따라서 소금 한알로 조언을하고 새로운 속성을 만들기 전에 시간을내어 도메인을 분석하십시오.
Machado

82
"세 줄의 코드"가 아니라 적절한 대상 (적어도 기본적인 프로그래밍 이해를 가진 사람)을 작성하는 것입니다. 은 if이다 이미 조건이 거짓이 될 수 있다는 사실에 대한 명시 적, 또는 당신은 그것을 위해 테스트되지 않습니다. 빈 블록은 더 이상이 아니라 더 명확하지 않습니다. 독자가 그것을 예상 할 준비가되어 있지 않기 때문에 이제는 어떻게 멈추었는지 생각해야합니다.
hobbs

15
@ 댓글이 if (!commonCase) { handle the uncommon case },있더라도 말보다 명확하지 않습니다.
Paul

62

첫 번째 규칙과 관련하여 이것은 쓸모없는 타이핑의 예입니다. 입력하는 데 시간이 오래 걸릴뿐만 아니라 코드를 읽는 사람에게 많은 혼란을 초래할 수 있습니다. 코드가 필요하지 않으면 작성하지 마십시오. else코드가 if블록 에서 반환 될 때 사용자의 경우 채워지지 않은 상태로 확장 될 수도 있습니다 .

if(condition) 
{
    doStuff();
    return whatever;
}

doSomethingElse(); // no else needed
return somethingelse;

두 번째 요점은 음수가 포함 된 부울 이름을 사용하지 않는 것이 좋습니다.

bool doorNotOpen = false; // a double negative is hard to reason
bool doorClosed = false; // this is much clearer

그러나 당신이 지적했듯이 이것을 다시 부정적인 테스트를하지 않도록 확장하면 쓸모없는 타이핑이 발생합니다. 다음은 빈 if블록을 갖는 것보다 훨씬 명확합니다 .

if(!condition)
{
    doStuff();
    return whatever;
}

120
그럼 .. 이중 부정은 아니오라고 말할 수 있습니까? ;)
Patsuan

6
@Patsuan, 매우 영리합니다. 나는 그것을 좋아한다. :)
David Arno

4
나는 많은 사람들이 if-else with return을 처리하는 방법에 대해 동의하지 않을 것이라고 생각하며, 어떤 사람들은 모든 시나리오에서 동일하게 처리해서는 안된다고 말할 수도 있습니다. 나는 나 자신을 강력하게 선호하지 않지만, 그것을하는 다른 많은 방법 뒤에있는 주장을 분명히 볼 수 있습니다.
Dukeling 2016 년

6
분명히 if (!doorNotOpen)끔찍합니다. 따라서 이름은 가능한 한 긍정적이어야합니다. if (! doorClosed)완벽하게 괜찮습니다.
David Schwartz

1
문 예제와 관련하여 두 예제 이름이 반드시 동일한 것은 아닙니다. 물리적 세계 에서 개방과 폐쇄 사이에 과도기적 상태가있는 doorNotOpen것과 동일하지 않습니다 doorClosed. 산업용 애플리케이션에서 항상 부울 상태가 물리적 센서에 의해 결정된다는 것을 알았습니다. 도어의 열린쪽에 단일 센서가있는 경우 도어가 열려 있거나 열려 있지 않다고 말할 수 있습니다. 마찬가지로 센서가 닫힌쪽에있는 경우 닫힌 상태 또는 닫힌 상태 만 말할 수 있습니다. 또한 센서 자체가 논리 상태를 확인하는 방법을 결정합니다.
피터 M

45

1. 빈 else진술 에 찬성 한 주장 .

나는 종종 첫 번째 구조와 비슷한 것을 사용하고 논쟁합니다. 프로그래머가 상황에 대해 몇 가지 생각을했다는 것을 코드 리더 (인간 및 자동 분석 도구 모두)에게 알립니다. 누락 else존재 했어야 문, 사람을 죽인 차량을 충돌하고, 수백만 달러의 비용이있다. 예를 들어, MISRA-C는 결승전 결승전이 의도적으로 의도적이라는 의견을 적어도 요구 if (condition_1) {do_this;} else if (condition_2) {do_that;} ... else if (condition_n) {do_something_else;}합니다. 다른 고 신뢰성 표준은 한층 더 발전합니다. 몇 가지 예외를 제외하고는 누락 된 진술은 금지되어 있습니다.

한 가지 예외는의 간단한 설명입니다 /* Else not required */. 이것은 다른 세 줄을 비우는 것과 같은 의도를 나타냅니다. 비어있는 것이 필요하지 않은 또 다른 예외는 코드를 읽는 사람과 불필요한 비어있는 자동화 된 분석 도구 모두에게 명백한 경우입니다. 예를 들어, if (condition) { do_stuff; return; }마찬가지로, 대신에 throw something또는 대신 goto some_label1 을 비워 둘 필요가 없습니다 return.

2. 선호에 대한 인수 if (condition)를 통해 if (!condition).

이것은 인적 요소입니다. 복잡한 부울 논리는 많은 사람들을 여행합니다. 노련한 프로그래머조차도 생각해야 할 것 if (!(complex || (boolean && condition))) do_that; else do_this;입니다. 최소한 이것을로 다시 작성하십시오 if (complex || (boolean && condition)) do_this; else do_that;.

3. 이것은 빈 then문장을 선호한다는 의미는 아닙니다 .

두 번째 섹션은 "네가 있어야한다"보다는 "바람직하다"고 말한다. 규칙이 아니라 지침입니다. 이 지침이 긍정적 인 if조건 을 선호하는 이유 는 코드가 명확하고 분명해야하기 때문입니다. 빈 then 절 (예 if (condition) ; else do_something;:)이이를 위반합니다. 프로그래밍이 난독 화되어 가장 노련한 프로그래머조차도 if부정한 형태로 상태를 백업하고 다시 읽습니다 . 따라서 처음에는 부정 된 형식으로 작성하고 else 문을 생략하십시오 (또는 그렇지 않으면 비워 두거나 그 영향에 대해 언급하십시오).



1 그때로 끝나는 절을 쓴 return, throw또는 goto다른 빈을 필요로하지 않습니다. else 절이 필요하지 않은 것은 분명합니다. 그러나 어떻 goto습니까? 게다가, 안전에 중요한 프로그래밍 규칙은 때때로 조기 반환을 허용하지 않으며 거의 ​​항상 예외 발생을 허용하지 않습니다. 그러나 goto제한된 형식 (예 :)으로 허용 됩니다 goto cleanup1;. 이 제한된 사용은 goto일부 장소에서 선호되는 관행입니다. 예를 들어, 리눅스 커널은 그러한 goto문장들 로 가득 차 있습니다.


6
!또한 쉽게 간과됩니다. 너무 간결합니다.
Thorbjørn Ravn Andersen

4
아니요, 다른 사람이 비어 있다고해서 프로그래머가 그것에 대한 생각을 명확하게하지는 못합니다. 그것은 더 많은 혼란을 야기한다. "일부 진술이 계획되어 있고 그것들이 잊혀지거나 왜 빈 조항이 있는가?" 의견이 훨씬 명확합니다.
Simon

9
@Simon : 전형적인 형태는 else { /* Intentionally empty */ }, 또는 그 라인을 따르는 것입니다. 비어 있으면 규칙 위반을 무심코 찾는 정적 분석기를 만족시킵니다. 이 의견은 독자들에게 비어있는 것이 의도적이라는 것을 알려줍니다. 그런 다음 노련한 프로그래머는 일반적으로 주석을 불필요한 것으로 생략하지만 비어있는 것은 아닙니다. 높은 신뢰성의 프로그래밍은 그 자체의 영역입니다. 구조는 외부인에게는 다소 이상하게 보입니다. 이러한 구조는 하드 노크, 삶과 죽음 또는 $$$$$$$$$$가있을 때 매우 어려운 노크 스쿨의 교훈 때문에 사용됩니다.
David Hammen

2
empty else 절이 비어있을 때 (empty then 절이 얼마나 나쁜지 이해하지 못합니다 (해당 스타일을 선택한다고 가정)). 알 수 있습니다if (target == source) then /* we need to do nothing */ else updateTarget(source)
Bergi

2
@ ThorbjørnRavnAndersen nope not는 다른 비트 및 논리 연산자와 마찬가지로 C ++의 키워드입니다. 대체 연산자 표현을 참조하십시오 .
Ruslan

31

아주 드문 경우에 빈 else-branch (때로는 빈 if-branch)를 사용합니다. 아무것도하지 않고. 따라서 else 조치가 필요한 코드를 읽는 사람은 무언가 빠진 것으로 즉시 의심하고 시간을 낭비합니다.

if (condition) {
    // No action needed because ...
} else {
    do_else_action()
}

if (condition) {
    do_if_action()
} else {
    // No action needed because ...
}

하지만:

if (condition) {
    do_if_action()
} else {
    // I was told that an if always should have an else ...
}

5
이. 나는 그 진술 if test succeeds -> no action needed -> else -> action needed이 의미 상 그 진술 과 매우 다른 것을 발견한다 if it applies that the opposite of a test outcome is true then an action is needed. Martin Fowler의 인용은 "누구나 코드 컴퓨터는 이해할 수 있고, 훌륭한 프로그래머는 인간이 이해할 수있는 코드는 쓸 수있다"는 말이다.
Tasos Papastylianou 2016 년

2
@TasosPapastylianou 부정 행위입니다. '테스트에 성공한 경우-> 필요한 조치 없음'의 반대는 '테스트에 실패한 경우-> 필요한 조치'입니다. 약 10 단어로 채워 넣었습니다.
Jerry B

@JerryB "테스트"에 따라 다릅니다. 때때로 부정은 (언어 적으로) 간단하지만 때로는 그렇지 않으며 혼란을 초래할 수 있습니다. 그러한 경우, "결과가 진실이 아닌 부정 / 반대"와 "결과가 진실이 아닌"에 대해 말하는 것이 더 명확합니다. 그러나 요점은 '빈'단계를 도입하거나 변수 이름의 의미를 뒤집는 것이 더 명확하다는 것입니다. 이 "드 모건"상황에서 전형적인 : 예는 if ((missing || corrupt) && !backup) -> skip -> else do stuff지금까지 명확 (+ 다른 묵시적 의도)보다if ((!missing && !corrupt) || backup) -> do stuff
Tasos Papastylianou

1
@TasosPapastylianou 글을 if(!((missing || corrupt) && !backup)) -> do stuff쓰거나 더 좋을 수 if((aviable && valid) || backup) -> do stuff있습니다. (그러나 실제 예에서는 사용하기 전에 백업이 유효한지 확인해야합니다)
12431234123412341234123

2
@TasosPapastylianou 내가 말한 것에 이중 네거티브가 어디에 있습니까? 물론 변수 이름으로 손상되지 않은 것을 사용하고 있다면 분명한 점이 있습니다. 이 같은 혼합 부울 연산자에 올 때하지만, 수도 에 사용하는 임시 변수가 더 좋을 if: file_ok = !missing && !corrupt; if(file_ok || backup) do_stuff();나는 개인적으로도 명확하게 느끼는를.
Baldrickk

23

다른 모든 것은 평등을 선호합니다.

당신이 쓰지 않는 것은 아무도 읽고 이해하지 않아도됩니다.

명백한 것이 유용 할 수는 있지만, 너무 자세하게 표현하지 않은 상태에서 자신이 작성한 것이 실제로 쓰고 싶은 것이 분명한 경우에만 해당됩니다.


따라서 빈 가지를 피하십시오. 빈 가지는 쓸모 없을뿐만 아니라 드문 일이므로 혼란을 초래합니다.

또한 if-branch에서 직접 나갈 경우 else-branch를 작성하지 마십시오.

명쾌함의 유용한 적용은 스위치 케이스를 통과 할 때마다 // FALLTHRU주석을 작성하고 빈 명령문이 필요한 주석 또는 빈 블록을 사용하는 것 for(a;b;c) /**/;입니다.


7
// FALLTHRUSCREAMING CAPS 또는 txtspk abbrevs와는 다릅니다. 그렇지 않으면 본인은이 관행에 동의하고 따릅니다.
코디 그레이

7
@CodyGray-SHOUTING이 좋은 곳입니다. 대부분의 switch 문은 각 경우를로 끝 break냅니다. 그렇지 않으면 break몇 가지 놀라운 소프트웨어 오류가 발생했습니다. 폴 스루 (fall-through)가 의도적이라는 코드를 읽는 사람들에게 소리 치는 의견은 좋은 것입니다. 정적 분석 도구는 이러한 특정 패턴을 찾을 수 있으며 상황에 대한 불만을 제기하지 않아도 훨씬 더 좋습니다.
David Hammen

1
@Wossname : 방금 확인했는데의 vim변형을 인식하지 못합니다 FALLTHRU. 그리고 좋은 이유, 생각 : TODOFIXME의견은 당신이 당신의 요구 할 수 있도록하려는 때문에 grepable 할 필요가 주석입니다 git grep코드에서 당신이 알려진 결함을, 그리고 그들은 어디에 위치하고 있습니다. 무너지는 것은 결함이 아니며, 그 무엇을 위해 grep 할 이유가 없습니다.
cmaster

4
@DavidHammen 아니요, 외치는 것은 좋은 생각이 아닙니다. 예상되는 휴식 대신 // 실패가 있다면, 그것은 모든 개발자가 즉시 이해하기에 충분해야합니다. 또한, 실패는 결함에 대해 말하지 않고 단순히 상황이 고려되었다는 것과 그 중단을 나타내는 신호입니다. 누락 된 것으로 보이며 실제로는 존재하지 않는 것입니다. 이것은 순전히 정보 제공의 목적이며, 외치는 것은 없습니다.
cmaster

1
@cmaster-소리는 좋은 생각이 아니라는 것이 당신의 의견입니다. 다른 사람들의 의견은 다릅니다. 그리고해서 당신의 인식하지 않는 정력의 구성은 FALLTHRU다른 사람들이 그렇게 정력을 구성하지 않은 것을 의미하지 않는다.
David Hammen

6

본인의 지식이 아닌 IF 진술의 긍정적 또는 부정적 조건에 대한 단단하고 빠른 규칙은 없습니다. 나는 개인적 으로 부정적인 경우보다는 긍정적 인 경우를 코딩 하는 것을 선호한다 . 빈 IF 블록을 만들고 ELSE에 논리가 가득 찬 경우이 작업을 수행하지 않을 것입니다. 이러한 상황이 발생하면 다시 긍정적 사례를 테스트하기 위해 리팩토링하는 데 3 초 정도 걸립니다.

그래도 귀하의 예에서 마음에 들지 않는 점은 공백 ELSE가 차지하는 완전히 불필요한 수직 공간입니다. 이것을 할 이유가 전혀 없습니다. 논리에 아무것도 추가하지 않으며 코드가 수행하는 작업을 문서화하는 데 도움이되지 않으며 가독성을 전혀 높이 지 않습니다. 실제로, 추가 된 수직 공간은 가독성을 떨어 뜨릴 수 있다고 주장합니다 .


2
불필요한 수직 공간은 항상 중괄호를 사용하고, 다른 부재를 허용하지 않고, 들여 쓰기에 Allman 스타일을 사용해야하는 의무의 결과입니다.
David Hammen

글쎄, 나는 항상 중괄호를 사용하는 것이 좋은 것이라고 생각합니다. 코드를 읽을 때 추측 할 여지가 없습니다. 어리석게 들릴지 모르지만 특히 주니어 개발자를 멘토링 할 때 누락 된 괄호와 관련된 실수가 발생합니다. 나는 개인적으로 Allman 스타일 들여 쓰기의 팬이 아니 었습니다. 왜냐하면 당신이 언급 한 이유는 불필요한 수직 공간입니다. 그러나 그것은 단지 내 의견과 개인적인 스타일입니다. 처음에 배운 것이므로 항상 읽기 편합니다.
Langecrew

개인 스타일 : 내가 사용하는 중괄호 스타일 (Allman, 1TB, ...)에 관계없이 항상 중괄호를 사용합니다.
David Hammen

복잡한 조건 또는 이해하기 어렵다고 생각되는 조건은 거의 항상 자신의 방법 / 기능으로 리팩토링하여 해결할 수 있습니다. 이와 같은 것은 if(hasWriteAccess(user,file))아래에 복잡 할 수 있지만 한 눈에 결과가 무엇인지 정확히 알 수 있습니다. 예를 들어 if(user.hasPermission() && !file.isLocked()), 적절한 이름을 가진 메소드 호출 이 몇 가지 조건 일지라도 , 부정적인 점은 문제가되지 않습니다.
크리스 슈나이더

동의했다. 그리고 다시, 나는 가능할 때마다 리팩토링을 좋아합니다. :)
Langecrew

5

명시 적 else블록

나는 모든 진술을 다루는 담요 진술로 이것에 동의하지 if않지만 else습관 에서 블록을 추가하는 것이 좋은 경우가 있습니다.

if문은, 내 마음에, 실제로 두 가지 기능을 설명합니다.

우리가 무언가를해야한다면 여기에서하십시오.

이와 같은 것은 분명히 부분이 필요 하지 않습니다else .

    if (customer.hasCataracts()) {
        appointmentSuggestions.add(new CataractAppointment(customer));
    }
    if (customer.isDiabetic()) {
        customer.assignNurse(DiabeticNurses.pickBestFor(customer));
    }

경우에 따라 else오해의 소지가 있다고 주장하는 경우도 있습니다.

    if (k > n) {
        return BigInteger.ZERO;
    }
    if (k <= 0 || k == n) {
        return BigInteger.ONE;
    }

하지 와 같은

    if (k > n) {
        return BigInteger.ZERO;
    } else {
        if (k <= 0 || k == n) {
            return BigInteger.ONE;
        }
    }

기능적으로 동일하더라도. 첫 번째 if를 공란으로 쓰면 else두 번째 결과로 이어질 수 있으며 이는 불필요하게 추악합니다.

특정 상태를 확인하는 경우 빈번한 부분을 추가하여 else해당 상황을 커버하도록 상기시키는 것이 좋습니다.

        // Count wins/losses.
        if (doors[firstChoice] == Prize.Car) {
            // We would have won without switching!
            winWhenNotSwitched += 1;
        } else {
            // We win if we switched to the car!
            if (doors[secondChoice] == Prize.Car) {
                // We picked right!
                winWhenSwitched += 1;
            } else {
                // Bad choice.
                lost += 1;
            }
        }

이 규칙 은 새 코드를 작성할 때만 적용 됩니다 . IMHO else체크인 전에 빈 절을 제거해야합니다.


테스트 true하지 않는,false

다시 말하지만 이것은 일반적인 수준에서 좋은 조언이지만 많은 경우 코드가 불필요하게 복잡하고 읽기 어려워집니다.

비록 코드가

    if(!customer.canBuyAlcohol()) {
        // ...
    }

독자에게 말을 걸고 있지만

    if(customer.canBuyAlcohol()) {
        // Do nothing.
    } else {
        // ...
    }

더 나쁘지 않으면 적어도 나쁘다.

나는 몇 년 전 BCPL로 코딩하고 해당 언어에이 IFUNLESS 당신이 훨씬 더 판독 가능 등의 코드 수 있도록 절 :

    unless(customer.canBuyAlcohol()) {
        // ...
    }

이는 훨씬 나아지지만 여전히 완벽하지는 않습니다.


내 개인적인 과정

일반적으로 코드를 작성할 때 나는 종종 그 사건을 다루지 않았다는 것을 상기시키기 위해 문장에 빈 else블록을 추가합니다 if. 이것은 DFS함정을 피하는 데 도움이 되며 코드를 검토 할 때 더 많은 일이 있음을 알 수 있습니다. 그러나 일반적으로 TODO추적 할 주석을 추가합니다 .

  if (returnVal == JFileChooser.APPROVE_OPTION) {
    handleFileChosen();
  } else {
    // TODO: Handle case where they pressed Cancel.
  }

else코드 냄새가 자주 나타날 수 있으므로 일반적으로 코드에서 거의 사용 하지 않는 것으로 나타났습니다.


"빈"블록의 처리는 thngs를 구현할 때 표준 스터 빙 코드처럼 읽습니다.
Deduplicator

unless블록은 좋은 제안이며 BCPL에 거의 국한되지 않습니다.
tchrist

@TobySpeight 죄송합니다. 그것은 내가 쓴 것과 같은 ...것이 실제로 는 관심을 벗어났습니다 return. (사실, 함께 k=-1, n=-2첫 번째 복귀 촬영하지만이 크게 논쟁입니다.)
데이비드 Richerby

현대 펄은 가지고 ifunless. 더구나, 그것은 또한 진술 후에 이것들을 허용하므로, 당신은 말 print "Hello world!" if $born;하거나 print "Hello world!" unless $dead;둘 다 당신이 생각하는 것을 정확하게 할 것입니다.
CVn

1

첫 번째로, IF 문을 이런 식으로 사용하도록하는 언어 (오팔에서는 GUI 프런트 엔드를 메인 프레임 시스템에 배치하기위한 메인 프레임 스크린 스크레이퍼 뒤에있는 언어)와 IF에 한 줄만 사용하는 언어를 사용했습니다. 그리고 ELSE. 즐거운 경험이 아니 었습니다!

컴파일러가 그러한 추가 ELSE 절을 최적화 할 것으로 기대합니다. 그러나 라이브 코드의 경우 아무것도 추가하지 않습니다 (개발 중에는 추가 코드의 유용한 마커가 될 수 있음).

CASE / WHEN 유형 처리를 사용할 때 이러한 추가 절과 같은 것을 사용하는 시간입니다. 비어있는 경우에도 항상 기본 절을 추가합니다. 이것은 그러한 조항을 사용하지 않으면 오류가 발생하는 언어의 장기적인 습관이며 실제로 상황을 극복 해야하는지에 대한 생각을 강요합니다.

오래 전 메인 프레임 (예 : PL / 1 및 COBOL) 연습에서는 부정적인 검사가 덜 효율적이라는 것이 인정되었습니다. 요즘에는 미세 최적화로 무시되는 훨씬 더 중요한 효율성 절감 효과가 있지만, 이는 두 번째 요점을 설명 할 수 있습니다.

부정적인 논리는 읽기 쉬운 경향이 없지만, 단순한 IF 문에서는 그리 많지는 않습니다.


2
나는 어느 시점에서 일반적인 관행 이었다고 본다 .
Patsuan

@Patsuan-예, 어느 정도입니다. 메인 프레임 어셈블러가 성능 결정적인 코드를 대체 할 수있는 중요한시기였습니다.
킥 스타트

1
"오래 전에 ... 부정적인 점검이 덜 효율적이라는 것이 인정되었습니다." 글쎄, 그들은 이다 컴파일러가 최적화하지 않는 한 if !A then B; else Cif A then C; else B. 조건의 부정을 계산하는 것은 추가 CPU 명령입니다. (당신이 말한대로하지만,이 될 가능성이 훨씬 덜 효율적.)
데이비드 Richerby

@DavidRicherby 그리고 우리가 일반적으로 이야기한다면, 일부 언어는 그러한 최적화를 정말로 어렵게 만들 수 있습니다. 예를 들어 오버로드 !==연산자가있는 C ++을 사용하십시오 . 누군가가 실제로 그렇게 해서는 안된다는 것을 명심하십시오.
CVn

1

나는 빈 else블록이 사실상 항상 전자 잉크의 유해한 폐기물 이라는 대부분의 대답을지지 할 것 입니다. 빈 공간이 전혀 없어야하는 이유가없는 한 추가하지 마십시오. 빈 블록이 비어 있으면 안되는 이유를 설명하는 주석이 포함되어야합니다.

음수를 피하는 문제는 좀 더주의를 기울여야합니다. 일반적으로 부울 값을 사용해야 할 때마다 코드가 설정 될 때 작동 할 코드 블록이 설정되어 있고 설정되지 않은 경우 작동해야하는 다른 블록이 필요합니다. 따라서 음수가 아닌 규칙을 시행 if() {} else {...}하는 경우 빈 if블록 이있는 명령문 을 사용하거나 해당 값이 포함 된 각 부울에 대해 두 번째 부울을 작성합니다. 두 가지 옵션 모두 독자를 혼동하기 때문에 나쁩니다.

유용한 정책은 다음과 같습니다. 부울 이름 안에 부정 형식을 사용하지 말고 부정을 단일로 표현하십시오 !. 같은 문장은 if(!doorLocked), 같은 성명 완벽하게 분명하다 if(!doorUnlocked)노트 두뇌. 후자의 유형의 표현은 조건 !에서 단일의 존재가 아니라 모든 비용을 피해야 하는 if()것입니다.


0

나는 그것이 나쁜 습관이라고 말할 것입니다. else 문을 추가하면 코드에 무의미한 줄을 추가하여 아무것도하지 않고 읽기가 더 어려워집니다.


1
기간 당 생산 된 SLOC를 기준으로 성과를 평가하는 고용주를 위해 일한 적이 없다고 들었습니다.
CVn

0

빈 if-block이있는 두 번째 경우를 처리하는 방법에 대해서는 아직 언급되지 않은 또 다른 패턴이 있습니다. 이를 처리하는 한 가지 방법은 if ​​블록으로 돌아가는 것입니다. 이처럼 :

void foo()
{
    if (condition) return;

    doStuff();
    ...
}

이것은 오류 조건을 확인하기위한 일반적인 패턴입니다. 긍정적 인 경우는 여전히 사용되며, 그 내부는 더 이상 비어 있지 않아 미래 프로그래머가 no-op가 의도적인지 아닌지 궁금해합니다. 또한 새로운 기능을 만들어야 할 수도 있으므로 가독성을 향상시킬 수 있습니다 (따라서 큰 기능을 더 작은 개별 기능으로 나눕니다).


0

다른 답변에서 보지 못한 "항상 else 절이 있습니다"라는 주장을 고려할 때 한 가지 점이 있습니다. 함수형 프로그래밍 스타일에서는 의미가 있습니다. 일종의.

함수형 프로그래밍 스타일에서는 문장보다는 표현식을 다루게됩니다. 따라서 모든 코드 블록에는 if-then-else식을 포함하여 반환 값이 있습니다. 그러나 그것은 빈 else블록을 배제합니다 . 예를 들어 보겠습니다.

var even = if (n % 2 == 0) {
  return "even";
} else {
  return "odd";
}

이제 C 스타일 또는 C 스타일에서 영감을 얻은 구문 (예 : Java, C # 및 JavaScript 등)을 사용하는 언어에서는 이상하게 보입니다. 그러나 다음과 같이 작성하면 훨씬 더 친숙해 보입니다.

var even = (n % 2 == 0) ? "even" : "odd";

else여기에 브랜치를 비워 두면 기능을 프로그래밍 할 때 유효한 경우가 아닌 대부분의 경우 값이 정의되지 않습니다. 완전히 빠져 나가는 것과 같습니다. 그러나 반복적으로 프로그래밍 할 때 항상 else블록을 가질 이유가 거의 없습니다 .


0

... if 문 뒤에 else 문이 있어야합니다.

동의 if (a) { } else { b(); }를 다시 써야 if (!a) { b(); }하고 if (a) { b(); } else { }로 다시 써야합니다 if (a) { b(); }.

그러나 빈 분기가 거의없는 것을 지적 할 가치가 있습니다. 이것은 일반적으로 다른 빈 지점으로 갔다는 것을 기록하기 때문입니다. 이 방법으로 순전히 로그 메시지를 개발할 수 있습니다. 디버거는 거의 사용하지 않습니다. 프로덕션 환경에서는 디버거가 없습니다. 개발에 사용하는 것과 동일한 도구를 사용하여 생산 문제를 해결할 수있는 것이 좋습니다.

두 번째로, 거짓보다는 실제 값을 테스트하는 것이 좋습니다. 즉, '! doorOpened'변수 대신 'doorClosed'변수를 테스트하는 것이 좋습니다.

나는 이것에 대해 여러 가지 감정을 가지고 있습니다. 가진의 단점 doorCloseddoorOpened잠재적 인 당신이 알아야 할 단어 / 용어의 수를 두 배로. 또 다른 단점은 시간이 지남의 의미 doorCloseddoorOpened(다른 개발자 후 오는)과 더 이상 서로의 정확한 부정없는 두 가지 속성으로 끝낼 수 있습니다 변경 될 수 있습니다. 부정을 피하는 대신 코드 언어 (클래스 이름, 변수 이름 등)를 비즈니스 사용자의 어휘와 요구 사항에 맞게 조정하는 것이 좋습니다. 피하기 위해 완전히 새로운 용어를 만들고 싶지 않습니다.!해당 용어가 비즈니스 사용자가 이해하지 못하는 개발자에게만 의미가있는 경우 개발자가 요구 사항을 작성하는 사용자 및 사용자와 동일한 언어를 사용하기를 원합니다. 이제 새로운 용어로 모형을 단순화하는 것이 중요하지만 요구 사항이 마무리되기 전에 처리해야합니다. 개발은 코딩을 시작하기 전에이 문제를 처리해야합니다.

나는 본능을 의심하기 쉽다.

계속해서 스스로 질문하는 것이 좋습니다.

좋은 / 나쁜 / "무관 한"연습입니까?

어느 정도는이 문제가 중요하지 않습니다. 코드를 검토하고 팀에 적응하십시오. 일반적으로 옳은 일입니다. 팀의 모든 사람이 특정 방식으로 코드를 작성하려는 경우 해당 방식으로 수행하는 것이 가장 좋습니다 (1 명-자신을 변경하는 것이 그룹을 변경하는 것보다 적은 스토리 포인트를 사용함).

일반적인 관행입니까?

빈 지점을 본 기억이 없습니다. 그래도 사람들이 부정을 피하기 위해 속성을 추가하는 것을 봅니다.


0

이 질문의 두 번째 부분 만 다룰 것입니다. 이것은 산업 시스템에서 작업하고 실제 세계에서 장치를 조작한다는 관점에서 비롯됩니다.

그러나 이것은 어쨌든 대답이 아닌 확장 된 의견입니다.

그것이 언급 될 때

두 번째로, 거짓보다는 실제 값을 테스트하는 것이 좋습니다. 즉, '! doorOpened'변수 대신 'doorClosed'변수를 테스트하는 것이 좋습니다.

그의 주장은 코드가하는 일을 더 명확하게한다는 것입니다.

내 관점에서 볼 때 문 상태가 실제로는 삼항 상태 일 때 이진 상태라고 가정합니다.

  1. 문이 열려 있습니다.
  2. 문이 완전히 열리지 않았거나 완전히 닫히지 않았습니다.
  3. 그 문은 닫혀있다.

따라서 단일 이진 디지털 센서의 위치에 따라 두 가지 개념 중 하나만 추측 할 수 있습니다.

  1. 센서가 도어 의 열린 쪽에있는 경우 : 도어가 열려 있거나 열려 있지 않습니다
  2. 센서가 도어 의 닫힌 쪽에있는 경우 : 도어가 닫혔거나 닫히지 않았습니다.

이진 부정을 사용하여 이러한 개념을 서로 바꿀 수는 없습니다. 따라서 doorClosed!doorOpened가능성이 동의어가 아니며, 그들은 동의어 척하려는 시도는 실제로 존재하는 것보다 시스템 상태의 더 큰 지식을 가정 잘못된 생각이다.

귀하의 질문으로 돌아 가면 변수가 나타내는 정보의 출처와 일치하는 언어를 지원합니다. 따라서 정보가 문의 닫힌 쪽에서 파생 된 경우 doorClosedetc 로 가십시오 . 이는 필요에 따라 다양한 설명에서 필요에 따라 doorClosed또는 !doorClosed필요에 따라 암시의 사용 과 혼동을 일으킬 수 있습니다. 그러나 그것이하지 않는 것은 시스템 상태에 대한 가정을 암시 적으로 전파하는 것입니다.


내가하는 작업에 대한 토론 목적으로, 시스템 상태에 대해 사용할 수있는 정보의 양은 전체 시스템 자체에 필요한 기능에 따라 다릅니다.

때때로 나는 문이 닫혔는지 닫히지 않으면 안됩니다. 이 경우 단일 이진 센서만으로 충분합니다. 그러나 다른 경우에는 문이 열려 있거나 닫혀 있거나 전환 중임을 알아야합니다. 그러한 경우, 2 개의 이진 센서 (각각의 극한 동작에서-동시에 도어가 열리고 닫히는 것에 대한 오류 점검)가 있거나 도어가 어떻게 '열렸'는지 측정하는 아날로그 센서가있을 것입니다.

첫 번째 예는 전자 레인지의 문입니다. 도어가 닫히거나 닫히지 않은 상태에서 오븐 작동이 가능합니다. 문이 얼마나 열려 있는지 상관하지 않습니다.

두 번째 예는 간단한 모터 구동 식 액추에이터입니다. 액츄에이터가 완전히 꺼지면 모터를 전진 구동하지 못합니다. 그리고 액츄에이터가 완전히 들어갈 때 모터를 역으로 구동하는 것을 금지합니다.

기본적으로 센서의 수와 유형은 필요한 기능을 달성하는 데 필요한 사항에 대한 요구 사항 분석과 비교하여 센서의 비용 분석을 실행합니다.


"내 관점에서 가정은 실제로는 적어도 원 상태 인 경우 문 상태가 진 상태임을 여기에서되고있다"당신은 폐쇄 여부되는 문에 따라 오븐의 작동을 가능하게 " "문이 얼마나 열려 있는지 상관하지 않습니다." 서로 모순된다. 또한 문과 센서에 관한 질문은 전혀 없다고 생각합니다.
Sanchises

@Sanchises 문장을 문맥에서 벗어난 것처럼 모순되지 않습니다. 첫 번째 진술은 삼항 상태에 대한 두 개의 반대되는 이진 측정이 이진 부정을 통해 교환 될 수 없다는 맥락에서입니다. 두 번째 진술은 3 원 상태에 대한 부분 지식만으로도 응용 프로그램이 올바르게 작동하기에 충분할 수 있다는 내용입니다. 문에 관해서는 OPs 질문은 문이 열리고 닫히는 것을 언급했습니다. 데이터 처리 방법에 영향을 줄 수있는 명백한 가정을 지적하고 있습니다.
Peter M

-1

구체적인 스타일 규칙은 항상 나쁩니다. 지침은 좋지만 결국 지침을 따르지 않는 것을 수행하여 더 명확하게 할 수있는 경우가 종종 있습니다.

즉, 비어있는 "줄을 낭비" "추가 입력"에 대한 증오가 많이 있습니다. 실제로 세로 공간이 필요한 경우 대괄호를 같은 줄로 옮길 수 있다는 주장을 할 수 있지만 문제가되는 경우 {를 별도의 줄에 두지 않아야합니다.

다른 곳에서 언급했듯이 else 블록을 사용하면 다른 경우에는 아무 일도 일어나지 않기를 명시 적으로 나타내는 데 매우 유용합니다. @OldCurmudgeon이 언급 한 것처럼 실제로 두 가지 다른 사용 사례가 있다고 언급하지만 많은 기능 프로그래밍 (다른 곳이 필요한 경우)을 수행 한 후 if를 작성할 때 항상 else를 고려해야한다는 것을 배웠습니다. 하나는 다른 것을 가져야하고, 다른 것을 가져서는 안됩니다. 안타깝게도, 린 터는 물론, 한눈에 알 수 있듯이 교리 적 '항상 else 블록을 넣습니다'라는 말이 항상 한 눈에 알 수있는 것은 아닙니다.

'네거티브 없음'에 관해서는 다시 절대 규칙이 나쁘다. 비어있는 if를 갖는 것은 이상 할 수 있습니다. 특히 그것이 필요하지 않은 타입이라면 특히! 또는 == false가 잘못되었습니다. 즉, 부정적인 의미가 많은 경우가 있습니다. 일반적인 예는 값을 캐싱하는 것입니다.

static var cached = null

func getCached() {
    if !cached {
        cached = (some calculation, etc)
    }

    return cached
}

실제 (mental / english) 논리에 부정이 포함 된 경우 if 문도 마찬가지입니다.

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