////
Search
Duplicate
🎄

15. 조건문 사용

조건문 다른 명령문의 실행을 제어하며 프로그래밍의 요소 중 하나인 분기의 대표적인 구현체다.
논리적으로는 whilefor도 조건문이라고 해야하지만 관례상 이 둘은 별도로 다룬다.

1. if 문

if-then 문

큰 흐름의 코드를 먼저 작성한 다음 예외 처리에 대한 코드를 작성한다.
일반적인 코드의 흐름이 분명하도록 코드를 작성한다. 특별한 경우가 일반적인 흐름을 모호하게 만들지 않도록 한다.
부등호를 조건문에 사용해야할 때, 등호에 대한 조건을 정확하게 사용하자.
정상적인 경우를 else가 아니라 if 문 다음에 입력하라.
정상적으로 처리되는 경우를 먼저 작성한다. 이는 조건 판단의 결과로부터 가능한 결정하는 위치와 가깝게 코드를 작성하는 일반적인 원칙과 일치한다.
다음 예시를 살펴보자.
OpenFile( inputFile, status ) If ( status = Status_Error ) Then errorType = FileOpenError <-- 1 오류 Else ReadFile( inputFile, fileData, status ) <-- 2 정상 If ( status = Status_Success ) Then SummarizeFileData( fileData, summaryData, status ) <-- 3 정상 If ( status = Status_Error ) Then errorType = ErrorType_DataSummaryError <-- 4 오류 Else PrintSummary( summaryData ) <-- 5 정상 SaveSummaryData( summaryData, status ) If ( status = Status_Error ) Then errorType = ErrorType_SummarySaveError <-- 6 오류 Else UpdateAllAccounts() <-- 7 정상 EraseUndoFile() errorType = ErrorType_None End If End If Else errorType = ErrorType_FileReadError End If End If
Visual Basic
복사
이 코드는 정상적인 경우와 오류가 발생한 경우가 모두 섞여 있어 흐름을 읽기 힘들다.
오류 처리가 else 절이 아니라 if 절에서 처리되는 경우가 존재하므로 if 문을 읽을 때도 예외와 정상 흐름을 확인해야 한다.
재작성한 코드에서는 일반적인 경우가 일관성있게 먼저 작성되었으며 오류가 발생한 경우는 모두 나중에 작성되었다.
OpenFile( inputFile, status ) If ( status = Status_Success ) Then ReadFile( inputFile, fileData, status ) <-- 1 If ( status = Status_Success ) Then SummarizeFileData( fileData, summaryData, status ) <-- 2 If ( status = Status_Success ) Then PrintSummary( summaryData ) <-- 3 SaveSummaryData( summaryData, status ) If ( status = Status_Success ) Then UpdateAllAccounts() <-- 4 EraseUndoFile() errorType = ErrorType_None Else errorType = ErrorType_SummarySaveError <-- 5 End If Else errorType = ErrorType_DataSummaryError <-- 6 End If Else errorType = ErrorType_FileReadError <-- 7 End If Else errorType = ErrorType_FileOpenError <-- 8 End If
Visual Basic
복사
정확성 파악을 위해 else 문을 테스트하라.
테스트 코드의 커버리지를 높이는 것은 코드의 좋은 부정 지표로서 작용한다.
else 문을 테스트할 수 있다면 꼭 그렇게 해야 한다.

연속적인 if-then-else 문

case 문을 지원하지 않거나 부분적으로 지원하는 언어에서는 종종 if-then-else 테스트를 연속해서 작성하게 된다.
예를 들어서 문자를 분류하는 코드는 다음과 같은 연속적인 if-then-else 문을 사용할 것이다.
if ( inputCharacter < SPACE ) { characterType = CharacterType_ControlCharacter; } else if ( inputCharacter == ' ' || inputCharacter == ',' || inputCharacter == '.' || inputCharacter == '!' || inputCharacter == '(' || inputCharacter == ')' || inputCharacter == ':' || inputCharacter == ';' || inputCharacter == '?' || inputCharacter == '-' ) { characterType = CharacterType_Punctuation; } else if ( '0' <= inputCharacter && inputCharacter <= '9' ) { characterType = CharacterType_Digit; } else if ( ( 'a' <= inputCharacter && inputCharacter <= 'z' ) || ( 'A' <= inputCharacter && inputCharacter <= 'Z' ) ) { characterType = CharacterType_Letter; }
Visual Basic
복사
복잡한 테스트를 불린 함수로 대체하라.
앞선 코드가 읽기 어려운 이유는 문자열을 분류하는 조건문들이 복잡하기 때문이다.
코드를 이해하기 쉽게 이 조건문들을 불린 함수로 대체할 수 있다.
if ( IsControl( inputCharacter ) ) { characterType = CharacterType_ControlCharacter; } else if ( IsPunctuation( inputCharacter ) ) { characterType = CharacterType_Punctuation; } else if ( IsDigit( inputCharacter ) ) { characterType = CharacterType_Digit; } else if ( IsLetter( inputCharacter ) ) { characterType = CharacterType_Letter; }
Visual Basic
복사
가장 흔한 경우를 앞에 놓아라.
가장 흔한 경우를 앞에 놓으면 일반적인 흐름을 찾기 위해 읽어야 하는 예외처리의 코드의 양을 최소화할 수 있다.
모든 경우를 다루었는지 확인하라.
마지막 else 문에는 놓친 조건들을 처리할 오류 메시지나 어설션을 작성한다.
이 오류 메시지는 개발자를 위한 것이니 정보를 적절히 제공한다.
언어가 지원한다면 다른 구조를 사용하라.
문자열과 열거형, 논리함수를 사용할 수 있는 case 문이 가독성이 더 좋다.

2. case 문

case, switch 문은 언어에 따라 다르게 구현되는데 Java는 한 번에 하나의 값만 저장하는 순서형의 값에 대해서만 case를 지원한다.
다음 절에서는 case 문을 효과적으로 사용하기 위한 가이드라인을 제공한다.

가장 효과적인 case 순서의 선택

알파벳 순이나 숫자 순으로 케이스를 나열하라.
케이스의 중요도가 동일하다면 알파벳 순으로 나열하여 가독성을 향상시켜라.
가장 정상적인 경우를 앞에 놓아라.
정상적인 경우 하나와 예외적인 경우가 여럿 있는 경우 가장 일반적인 경우를 앞에 놓는다.
그리고 나머지 경우들이 모두 예외임을 주석으로 표시한다.
빈도나 우선순위에 따라서 case를 나열하라.
가장 빈번하게 실행되거나 우선순위 중요한 것을 가장 앞에 두고 가장 드물게 실행되는 경우를 마지막에 놓는다.
이러한 접근법은 가장 흔한 경우를 쉽게 찾을 수 있다는 장점을 제공한다.

case 문 사용팁

case 문이 하는 일을 간단하게 유지한다.
각 케이스와 연관된 코드를 짧게 유지하면 case 문의 구조를 명확하게하는 데 도움을 준다.
케이스의 조건이 복잡하다면 메소드로 추출해내자.
case 문에서 사용하기 위한 가짜, 임시 변수를 만들지 않는다.
case 문은 쉽게 분류될 수 있는 형태에만 사용해야 한다.
데이터가 단순하지 않다면 if-then-else를 사용해야 한다.
유효한 기본값을 찾고자 하는 경우나 오류를 검출하기 위해서 default 문을 사용한다.
일반적으로 default는 기본값을 대체해야한다. 특정한 조건에서의 값을 대변해서는 안 된다.
그 의미를 흐리게 한다.
입력되어서는 안 되는 데이터가 입력되었을 경우, 오류 메시지를 적절히 처리하기에 적합하다.
중첩된 case 문을 사용하지 않는다.
맥락에 계층이 생길수록 가독성은 떨어지기 마련이다.

요점 정리

특히 많은 오류를 처리할 때는 간단한 if-else 문에서 ifelse 문의 순서에 주의를 기울인다. 정상적인 경우가 명확하게 드러나게 한다.
if-then-else 문과 case 문에서는 가독성을 고려하여 정렬 순서를 결정한다.
오류를 잡기 위해서 case 문에서는 default, if-then-else 문에서는 else를 활용한다.
각 코드 블록에 적합한 조건문 제어 구조를 선택할 줄 알아야 한다. 은탄환은 없다.