읽기 좋은 코드가 좋은 코드다. 
part 2.루프와 논리를 단순화 하기 
7. 읽기 쉽게 흐름제어 만들기 
by 윤기
7. 읽기 쉽게 흐름제어 만들기 
흐름을 제어하는 조건과 루프 그리고 여타 요소를 최 
대한 ‘자연스럽게’ 만들도록 노력하라. 
코드를 읽다 다시 되돌아가서 코드를 읽지 않아도 되 
게끔 만들어야 한다.
조건문에서 인수의 순서 
 If ( length >= 10 ) 
 If ( 10 <= length )
조건문에서 인수의 순서 
전자가 읽기 좋음. 
왼쪽 : 유동적 
오른쪽 : 고정 값
조건문에서 인수의 순서 
 While ( bytes_received < bytes_expected) 
{ 
bytes_recived += recv( buffer ); 
} 
 While (bytes_expected > bytes_received ) 
{ 
bytes_recived += recv( buffer ); 
}
조건문에서 인수의 순서 
 전자가 읽기 좋음. 
왼쪽 : ‘질문을 받는(?)’ 표현 
ex) bytes_received 가 
bytes_excepted 보다 작냐? 
오른쪽 : 비교 대상으로 사용되는 표현
조건문에서 인수의 순서 
 전자의 조건이 후자 보다 더 쉽게 이해 
된다.
조건문에서 인수의 순서 
Why? 
영어 어순과 일치.
조건문에서 인수의 순서 
 요다 표기법. 
If( NULL == obj ) 
고정값인 NULL이 왼쪽, 유동값인 obj 
가 오른쪽에 위치함. 
Obj = NULL  이 오류를 막기 위해.
조건문에서 인수의 순서 
 현재까지 배운 것을 뒤엎으면서 까지 
그렇게 할 필요는 없다. 요즘에 컴파일 
러가 경고를 출력한다고 함.
조건문에서 인수의 순서 
 생각하기 편한 순서로 인수의 순서를 
정하라.
If / else 블록의 순서 
 조건문 표현에 대한 이야기. 
1. 부정이 아닌 긍정을 다루어라. 
if ( !debug ) -> if ( debug ) 
2. 간단한 것을 먼저 처리하라. 이렇게 하면 동시 
에 같은 화면에 if와 else 구문을 나타낼 수도 
있다. (먼말…??) 두개의 주문을 동시에 보는 
게 더 좋다. 
3. 더 흥미롭고, 확실한 것을 먼저 다루어라.
If / else 블록의 순서 
3. 더 흥미롭고, 확실한 것을 먼저 다루어라. 
If( !url.HasQueryParameter(“expand_all”)) 
{ 
“확장하지 않은 처리” 
} 
Else 
{ 
“확장 처리” 
} 
If( url.HasQueryParameter(“expand_all”)) 
{ 
“확장 처리” 
} 
Else 
{ 
“확장하지 않은 처리” 
}
If / else 블록의 순서 
더 흥미롭고, 확실한 것을 먼저 다루어라!! 
If( !url.HasQueryParameter(“expand_all”)) 
{ 
“확장하지 않은 처리” 
} 
Else 
{ 
“확장 처리” 
} 
If( url.HasQueryParameter(“expand_all”)) 
{ 
“확장 처리” 
} 
Else 
{ 
“확장하지 않은 처리” 
}
If / else 블록의 순서 
 빨간색 조건에 집중하느라 정작 중요 
한 “! NOT” 조건을 놓침.
If / else 블록의 순서 
 조건문에는 부정이 아닌 긍정을 다루 
되, 더 흥미롭고 중요한 것을 먼저 다루 
어라.
If / else 블록의 순서 
 2번… 이해되시는 분은 설명 점…ㅠ
(삼항 연산자로 알려진)?: 이용하 
는 조건문 표현 
 매우!! 간단한 것은 삼항 연산 이용, 아 
닌 것은 if / else
do/ while 루프를 피하라. 
do 
{ 
(실행 ) 
}while ( 조건 ) 
실행 -> 조건 
순서로 코드를 읽게 됨.
do/ while 루프를 피하라. 
While ( 조건 ) 
{ 
(실행 ) 
} 
조건 -> 실행 
일반적으로 조건 -> 실행 순으로 코드를 읽 
는 것이 편함.
do/ while 루프를 피하라. 
 부자연스럽기 때문에 피해야 한다. 
어떻게…?
do/ while 루프를 피하라. 
1안) 
//Do/while을 흉내 내기. 
(실행) 
While( 조건 ) 
{ 
(실행) 
} 
=> 코드 중복이 되기 때문에 좋지 않음.
do/ while 루프를 피하라. 
2안) 조건을 수정하여 작성 
While ( 수정된 조건 ) 
{ 
(실행 ) 
}
do/ while 루프를 피하라. 
 수정된 조건 ?
do/ while 루프를 피하라. 
do { 
(실행) 
} 
while ( --max_length > 0 );
do/ while 루프를 피하라. 
While ( max_length-- > 0) 
{ 
(실행 ) 
}
do/ while 루프를 피하라. 
do/while 문의 do 에서 한번 실행되는 
것을 while문 조건을 수정하여 실행하 
게 만듦.
do/ while 루프를 피하라. 
 (--max_length) 전위 연산자에서 
(max_length--)후위 연산자로 조건을 
수정하여, 
값을 감소시키고 0과 비교하는 조건에 
서, 0과 비교하고 값을 감소하는 조건 
으로 수정.
do/ while 루프를 피하라. 
 하지만… 완벽하게 동작이 같은 것이 아 
니다. 
(의도만 비슷하게 맞춘 것 뿐.. Do/while 
문과 while문에 대한 이야기는 현재 
chapter의 내용에서 많이 벗어나므로 뒤 
에 추가..)
do/ while 루프를 피하라. 
결국, c++의 창시자인 반얀 스트라우스트 
럽을 내세우며 마무리… 
“내 경험으로 에러와 혼동의 원인은 do문에 
있다. 그래서 나는 조건이 ‘눈에 뜨이는 곳 
에 미리’ 나타나도록 만드는 것을 선호한 
다. 결과적으로 나는 do문을 피하는 경향 
이 있다.”
do/ while 루프를 피하라. 
 조건->실행 순서로 진행되게 코드를 작 
성 하자.
함수 중간에서 반환하기 
 함수 중간에서 반환하는 것을 허용하 
되, 함수 반환 시 clean up코드는 반드 
시 실행 시키기 하자. 
C++ : destructors ( 파괴자) 
자바, 파이썬 : try finally 
파이썬 : with 
C# : using
악명 높은 goto 
 쓰지마……
중첩을 최소화하기 
 코드 중첩이 심할수록 이해하기 어렵 
다. 중첩이 일어날 때마다 코드를 읽는 
사람의 머릿속에 존재하는 ‘정신적 스 
택’에 추가적인 조건이 입력된다.
중첩을 최소화하기 
 머리에 부담 됨.
중첩을 최소화하기 
If( user_result == SUCCESS) 
{ 
if( permission != SUCCESS ) 
{ 
reply.WriteErrors(permission); 
return; 
} 
//이 시점에 굉장이 많은 생각이 필요함. 
//1. permission == SUCCESS가 올 차례다. 
//2. 없네.. 
//3. 다시 user_result == SUCCESS 내부다. 
reply.WriteErrors(“”); 
} 
Else 
{ 
reply.WriteErrors(user_result); 
}
중첩을 최소화하기 
If( user_result == SUCCESS) 
{ 
if( permission != SUCCESS ) 
{ 
reply.WriteErrors(permission); 
return; 
} 
reply.WriteErrors(“”); 
} 
Else 
{ 
reply.WriteErrors(user_result); 
}
중첩을 최소화하기 
 작성자의 수정은 일리가 있지만… 
‘수정해야 하는 상황이라면 여러분의 코 
드를 새로운 관점에서 바라보라. 뒤로 
한걸음 물러 서서 코드 전체를 보라.’
중첩을 최소화하기 
How? 
함수 중간에서 반환하여 중첩을 제거하 
라. 
‘실패한 경우들’을 최대한 빠르게 처리 
하고 함수에서 반환하여 제거!’
중첩을 최소화하기 
If( user_result != SUCCESS ) 
{ 
reply.WriteErrors( user_result); 
reply.Done(); 
return; 
} 
If( permission_result != SUCCESS) 
{ 
reply.WriteErrors(permission_result); 
reply.Done(); 
return; 
} 
reply.WriteErros(“”); 
Reply.Done();
중첩을 최소화하기 
 하지만 중간 반환이 어려울 경우는! 
예를 들어 루프 내부에서의 중첩. 
For( int i=0; i< result.size(); ++i) 
{ 
if( results[i] != NULL) 
{ 
if( result[i]->name != “ “ ) 
{ 
cout << result[i]->name << endl; 
} 
} 
}
중첩을 최소화하기 
 루프 내부에 있는 중첩 제거하기 
‘continue 사용’
중첩을 최소화하기 
For( int i=0; i< result.size(); ++i) 
{ 
if( results[i] == NULL) continue; 
if( result[i]->name == “ “ ) continue; 
cout << result[i]->name << endl; 
}
중첩을 최소화하기 
 continue는 논리의 흐름을 건너뛰기 
때문에 혼란스러워보일 수 있지만, 중 
첩문을 쓰는 것 보다는 낫다.
실행 흐름을 따라 올 수 있는가? 
 자신의 프로그램에 존재하는 흐름을 상위 
수준에서 조망해 볼 필요가 있다. 
흐름을 파악하기 힘들게 만드는 구조가 
있다. 
스레딩, 시그널/인터럽트 핸들러, 예외, 함 
수 포인터 & 익명 함수 , 가상 메소드 
이러한 것을 최대한 줄이자.
요약 
 조건문에서의 인수 순서 , If / else 블록 
의 순서, 삼항 연산자, do / while, 중첩 
최소 등 결국 자연스럽게 코드를 작성 
하는 것이 중요.
do/ while 루프를 피하라. 
만약 max_length가 0이하의 값이었다 
면 do/while문에서는 한번 실행되고 
while문에서는 한번도 실행되지 않는 
다. 
while문과 같게 동작하게 만들려면 
do/while문에 조건을 추가해야 한다.
do/ while 루프를 피하라. 
do { 
if( max_length > 0 )  추가 
(실행) 
} 
while ( --max_length > 0 );
do/ while 루프를 피하라. 
 하지만, 이것은 do/while을 추가 수정하 
는 것이기 때문에 본래 취지에서 벗어 
난다…. 
(우리가 하려는 것은 do / while문은 그 
대로 두고 while문으로 전환하는 것 이 
었음… )
do/ while 루프를 피하라. 
 기존에 존재하는 do/while문을 수정 없이 while문 
으로 전환하려면, 코드 중복 밖엔 방법이 없을 것 
이다. 
do/while의 do block은 무조건 실행되는 block이고 
while문 block은 조건을 확인하고 실행되기 때문 
에. 
(물론.. Whlie(1) 조건을 주고 내부에서 비슷하게 
구현하면 가능 할지도… 하지만 내부 구현에서 코 
드 중복이 발생할 것이고..너무…억지..억지..)

7.읽기 쉽게 흐름제어 만들기

  • 1.
    읽기 좋은 코드가좋은 코드다. part 2.루프와 논리를 단순화 하기 7. 읽기 쉽게 흐름제어 만들기 by 윤기
  • 2.
    7. 읽기 쉽게흐름제어 만들기 흐름을 제어하는 조건과 루프 그리고 여타 요소를 최 대한 ‘자연스럽게’ 만들도록 노력하라. 코드를 읽다 다시 되돌아가서 코드를 읽지 않아도 되 게끔 만들어야 한다.
  • 3.
    조건문에서 인수의 순서  If ( length >= 10 )  If ( 10 <= length )
  • 4.
    조건문에서 인수의 순서 전자가 읽기 좋음. 왼쪽 : 유동적 오른쪽 : 고정 값
  • 5.
    조건문에서 인수의 순서  While ( bytes_received < bytes_expected) { bytes_recived += recv( buffer ); }  While (bytes_expected > bytes_received ) { bytes_recived += recv( buffer ); }
  • 6.
    조건문에서 인수의 순서  전자가 읽기 좋음. 왼쪽 : ‘질문을 받는(?)’ 표현 ex) bytes_received 가 bytes_excepted 보다 작냐? 오른쪽 : 비교 대상으로 사용되는 표현
  • 7.
    조건문에서 인수의 순서  전자의 조건이 후자 보다 더 쉽게 이해 된다.
  • 8.
    조건문에서 인수의 순서 Why? 영어 어순과 일치.
  • 9.
    조건문에서 인수의 순서  요다 표기법. If( NULL == obj ) 고정값인 NULL이 왼쪽, 유동값인 obj 가 오른쪽에 위치함. Obj = NULL  이 오류를 막기 위해.
  • 10.
    조건문에서 인수의 순서  현재까지 배운 것을 뒤엎으면서 까지 그렇게 할 필요는 없다. 요즘에 컴파일 러가 경고를 출력한다고 함.
  • 11.
    조건문에서 인수의 순서  생각하기 편한 순서로 인수의 순서를 정하라.
  • 12.
    If / else블록의 순서  조건문 표현에 대한 이야기. 1. 부정이 아닌 긍정을 다루어라. if ( !debug ) -> if ( debug ) 2. 간단한 것을 먼저 처리하라. 이렇게 하면 동시 에 같은 화면에 if와 else 구문을 나타낼 수도 있다. (먼말…??) 두개의 주문을 동시에 보는 게 더 좋다. 3. 더 흥미롭고, 확실한 것을 먼저 다루어라.
  • 13.
    If / else블록의 순서 3. 더 흥미롭고, 확실한 것을 먼저 다루어라. If( !url.HasQueryParameter(“expand_all”)) { “확장하지 않은 처리” } Else { “확장 처리” } If( url.HasQueryParameter(“expand_all”)) { “확장 처리” } Else { “확장하지 않은 처리” }
  • 14.
    If / else블록의 순서 더 흥미롭고, 확실한 것을 먼저 다루어라!! If( !url.HasQueryParameter(“expand_all”)) { “확장하지 않은 처리” } Else { “확장 처리” } If( url.HasQueryParameter(“expand_all”)) { “확장 처리” } Else { “확장하지 않은 처리” }
  • 15.
    If / else블록의 순서  빨간색 조건에 집중하느라 정작 중요 한 “! NOT” 조건을 놓침.
  • 16.
    If / else블록의 순서  조건문에는 부정이 아닌 긍정을 다루 되, 더 흥미롭고 중요한 것을 먼저 다루 어라.
  • 17.
    If / else블록의 순서  2번… 이해되시는 분은 설명 점…ㅠ
  • 18.
    (삼항 연산자로 알려진)?:이용하 는 조건문 표현  매우!! 간단한 것은 삼항 연산 이용, 아 닌 것은 if / else
  • 19.
    do/ while 루프를피하라. do { (실행 ) }while ( 조건 ) 실행 -> 조건 순서로 코드를 읽게 됨.
  • 20.
    do/ while 루프를피하라. While ( 조건 ) { (실행 ) } 조건 -> 실행 일반적으로 조건 -> 실행 순으로 코드를 읽 는 것이 편함.
  • 21.
    do/ while 루프를피하라.  부자연스럽기 때문에 피해야 한다. 어떻게…?
  • 22.
    do/ while 루프를피하라. 1안) //Do/while을 흉내 내기. (실행) While( 조건 ) { (실행) } => 코드 중복이 되기 때문에 좋지 않음.
  • 23.
    do/ while 루프를피하라. 2안) 조건을 수정하여 작성 While ( 수정된 조건 ) { (실행 ) }
  • 24.
    do/ while 루프를피하라.  수정된 조건 ?
  • 25.
    do/ while 루프를피하라. do { (실행) } while ( --max_length > 0 );
  • 26.
    do/ while 루프를피하라. While ( max_length-- > 0) { (실행 ) }
  • 27.
    do/ while 루프를피하라. do/while 문의 do 에서 한번 실행되는 것을 while문 조건을 수정하여 실행하 게 만듦.
  • 28.
    do/ while 루프를피하라.  (--max_length) 전위 연산자에서 (max_length--)후위 연산자로 조건을 수정하여, 값을 감소시키고 0과 비교하는 조건에 서, 0과 비교하고 값을 감소하는 조건 으로 수정.
  • 29.
    do/ while 루프를피하라.  하지만… 완벽하게 동작이 같은 것이 아 니다. (의도만 비슷하게 맞춘 것 뿐.. Do/while 문과 while문에 대한 이야기는 현재 chapter의 내용에서 많이 벗어나므로 뒤 에 추가..)
  • 30.
    do/ while 루프를피하라. 결국, c++의 창시자인 반얀 스트라우스트 럽을 내세우며 마무리… “내 경험으로 에러와 혼동의 원인은 do문에 있다. 그래서 나는 조건이 ‘눈에 뜨이는 곳 에 미리’ 나타나도록 만드는 것을 선호한 다. 결과적으로 나는 do문을 피하는 경향 이 있다.”
  • 31.
    do/ while 루프를피하라.  조건->실행 순서로 진행되게 코드를 작 성 하자.
  • 32.
    함수 중간에서 반환하기  함수 중간에서 반환하는 것을 허용하 되, 함수 반환 시 clean up코드는 반드 시 실행 시키기 하자. C++ : destructors ( 파괴자) 자바, 파이썬 : try finally 파이썬 : with C# : using
  • 33.
    악명 높은 goto  쓰지마……
  • 34.
    중첩을 최소화하기 코드 중첩이 심할수록 이해하기 어렵 다. 중첩이 일어날 때마다 코드를 읽는 사람의 머릿속에 존재하는 ‘정신적 스 택’에 추가적인 조건이 입력된다.
  • 35.
    중첩을 최소화하기 머리에 부담 됨.
  • 36.
    중첩을 최소화하기 If(user_result == SUCCESS) { if( permission != SUCCESS ) { reply.WriteErrors(permission); return; } //이 시점에 굉장이 많은 생각이 필요함. //1. permission == SUCCESS가 올 차례다. //2. 없네.. //3. 다시 user_result == SUCCESS 내부다. reply.WriteErrors(“”); } Else { reply.WriteErrors(user_result); }
  • 37.
    중첩을 최소화하기 If(user_result == SUCCESS) { if( permission != SUCCESS ) { reply.WriteErrors(permission); return; } reply.WriteErrors(“”); } Else { reply.WriteErrors(user_result); }
  • 38.
    중첩을 최소화하기 작성자의 수정은 일리가 있지만… ‘수정해야 하는 상황이라면 여러분의 코 드를 새로운 관점에서 바라보라. 뒤로 한걸음 물러 서서 코드 전체를 보라.’
  • 39.
    중첩을 최소화하기 How? 함수 중간에서 반환하여 중첩을 제거하 라. ‘실패한 경우들’을 최대한 빠르게 처리 하고 함수에서 반환하여 제거!’
  • 40.
    중첩을 최소화하기 If(user_result != SUCCESS ) { reply.WriteErrors( user_result); reply.Done(); return; } If( permission_result != SUCCESS) { reply.WriteErrors(permission_result); reply.Done(); return; } reply.WriteErros(“”); Reply.Done();
  • 41.
    중첩을 최소화하기 하지만 중간 반환이 어려울 경우는! 예를 들어 루프 내부에서의 중첩. For( int i=0; i< result.size(); ++i) { if( results[i] != NULL) { if( result[i]->name != “ “ ) { cout << result[i]->name << endl; } } }
  • 42.
    중첩을 최소화하기 루프 내부에 있는 중첩 제거하기 ‘continue 사용’
  • 43.
    중첩을 최소화하기 For(int i=0; i< result.size(); ++i) { if( results[i] == NULL) continue; if( result[i]->name == “ “ ) continue; cout << result[i]->name << endl; }
  • 44.
    중첩을 최소화하기 continue는 논리의 흐름을 건너뛰기 때문에 혼란스러워보일 수 있지만, 중 첩문을 쓰는 것 보다는 낫다.
  • 45.
    실행 흐름을 따라올 수 있는가?  자신의 프로그램에 존재하는 흐름을 상위 수준에서 조망해 볼 필요가 있다. 흐름을 파악하기 힘들게 만드는 구조가 있다. 스레딩, 시그널/인터럽트 핸들러, 예외, 함 수 포인터 & 익명 함수 , 가상 메소드 이러한 것을 최대한 줄이자.
  • 46.
    요약  조건문에서의인수 순서 , If / else 블록 의 순서, 삼항 연산자, do / while, 중첩 최소 등 결국 자연스럽게 코드를 작성 하는 것이 중요.
  • 47.
    do/ while 루프를피하라. 만약 max_length가 0이하의 값이었다 면 do/while문에서는 한번 실행되고 while문에서는 한번도 실행되지 않는 다. while문과 같게 동작하게 만들려면 do/while문에 조건을 추가해야 한다.
  • 48.
    do/ while 루프를피하라. do { if( max_length > 0 )  추가 (실행) } while ( --max_length > 0 );
  • 49.
    do/ while 루프를피하라.  하지만, 이것은 do/while을 추가 수정하 는 것이기 때문에 본래 취지에서 벗어 난다…. (우리가 하려는 것은 do / while문은 그 대로 두고 while문으로 전환하는 것 이 었음… )
  • 50.
    do/ while 루프를피하라.  기존에 존재하는 do/while문을 수정 없이 while문 으로 전환하려면, 코드 중복 밖엔 방법이 없을 것 이다. do/while의 do block은 무조건 실행되는 block이고 while문 block은 조건을 확인하고 실행되기 때문 에. (물론.. Whlie(1) 조건을 주고 내부에서 비슷하게 구현하면 가능 할지도… 하지만 내부 구현에서 코 드 중복이 발생할 것이고..너무…억지..억지..)