C/C++ 프로그래밍 조언 : 화려함을 버려라.

프로그래밍/프로그래밍 메모장 2006/06/20 17:05

프로그래밍 조언 : 화려함을 버려라  by xevious7  2006.6.20.  

화려함은 쉽게 사람들을 유혹하는 것입니다. 하지만 일반적인 생활에서도
프로그래밍세계에서도 화려함은 그리 좋은 것은 아닌듯 합니다.
왜 당신은 애매한 문구를 쓰고 있는것입니까?  화려함은 좋지 않다라고
말할 순 없는것입니까?

네 !.

저는 경계를 벗어나는 연습을 하고 있습니다. 아니 더 정확히 말하면
저는 화려함이 좋을때도 있고 화려함이 싫을때도 있습니다.
그리고 어떤 경우에는 화려함이 훨씬 나을 때도 있고 화려함이 안좋을 수도
있다는 두가지 경우를 다 알고 있기 때문입니다.

그 두가지의 경우중 한가지 경우를 이야기 하고 있기 때문입니다.

스티브 맥과이어씨의 writing solid code 책을 보면 ? 연산자에 대한
이야기가 나옵니다.
그 단원에서  네가지 코드를 보여주면서  결론은  ?: 를 사용하지
말라 라는 이야기를 합니다. 다음은 그 내용을 나름대로 정리한 내용입니다.

일단 함수의 정의는 다음과 같습니다.

함수명 : uCycleCheckBox
함수입력 : uCur (현재상태를 나타내는 변수)
함수출력: 다음 체크상자 상태를 반환한다.
             이 함수는 0과 1사이를 토글하는 두가지 상태 체크상자와
                           2,3,4,   2 ... 를 순환하는 세가지 상태 체크상자 모두를 처리한다.

함수출력에 대해서 좀더 설명하쟈면 다음과 같습니다.
입력은 두가지 체크상자 상태중에 하나가 될수 있다는 이야기이고( 0,1를 토클하는 체크상자
또는  2,3,4 중 하나를 상태값을 가지되 순서되로 2->3->4 순환하는 체크상자 의 현재
상태라는 이야기 입니다. 따라서 반환값은 입력값에 따라 체크상자의 다음상태를
판단해서 반환하면 되는 함수입니다.

프로그래밍 언어의 문법을 조금만 알면 금방 풀 수 있는 문제입니다.


그 첫번째 코드는 아래와 같이  ? 연산자를 남발한 코드 입니다.
아시다시피 ? 연산자는 : 과 함께 if else 의 효과를 가지는 C언어의 연산자입니다.
소스 1의 소스는 기능상 아무런 문제가 없습니다.

unsigned uCycleCheckBox(unsigned uCur)
{
return ((uCur <=1) ? (uCur?0:1) : (uCur==4)?2:(uCur+1));
}

[ 소스 1 ]

하지만 전혀 아무런 정보가 없는 상태에서 이 소스를 보면 이해를 위해서 조금은 한참
보아야 할 것 같군요.

두번째 소스는 위의 소스를 풀어쓴 소스입니다.

unsigned uCycleCheckBox(unsigned uCur)
{
    unsigned uRet;

    if (uCur <= 1)
    {
          if (uCur != 0)
                  uRet = 0;
          else
                  uRet = 1;
     }
     else
     {
           if (uCur == 4)
                  uRet = 2;
           else
                  uRet = uCur + 1;
      }
      return (uRet);
}

[소스 2]

길이는 훨씬 길어졌지만 훨씬 이해가 쉽지 않습니까?
그런데 여기서 중요한 문제는 이해가 쉬운 것이 문제가 아니라 ? 연산자를 써서
애초부터 코딩한 이후의 문제입니다.
? 연산자로 코딩한 소스 1은  가독성문제 뿐만아니라 더 이상 수정할 여지가
없는 형태
가 되버린 것입니다.

반면 우리는 소스 2를 보고 좀더 다른 알고리즘을 생각하여 다음과 같은 소스 3를
생성할 수 있습니다.

writing solid code 책에서는 이것을 다음처럼 말합니다.

?: 연산자의 문제점은 , 겉으로는 단순하게 보이며 사용하기가 쉽다는 점이다.
마치 코드를 효율적으로 작성하기에 적합한 것처럼 보이기 때문에 ,
프로그래머들이 더 좋은 방법을 생각하려 하지 않고 이 연산자를 사용하는 것이다.
더 심각한 것은, if 문이 사용된 코드를 보다 효율적으로 개선한다면서 ?: 연산자를
사용한다는 점이다. 사실은 전혀 그렇지 않은데도 말이다. 지폐 한장을 동전으로
바꾸면 돈이 더 많은 것처럼 보이는 것과 마찬가지이다. 프로그래머들이 이같이
사소한 변경을 위해 낭비하는 시간을 보다 나은 알고리즘을 찾는데 사용한다면
훨씬 명료하면서도 효율적인 함수가 태어날 것이다.

unsigned uCycleCheckBox(unsigned uCur)
{
  ASSERT(uCur >=0 && uCur <= 4); // 이 함수의 입력은  0보다 크고 4보다 작은 경우만 실행된다.

  if(uCur == 1)
     return (0);
  if(uCur == 4)
     return (2);

  return( uCur + 1);
}

[소스 3]

결국 ? 연산자의 사용은 이러한 곳 즉 명확하게 정의되었을때만 즉 이미 최적화 된 경우만
쓰는 게 올바를 것 같습니다. 결국 원래의 목적인 단순성을 위해서 쓰여져야 된다는것입니다.

소스 3 에서 플로우 중심의 알고리즘에 벗어나 좀더 다른각도로 바라보면
다음과 같은 소스 4를 만들어 낼 수 있습니다.

unsigned uCycleCheckBox(unsigned uCur)
{
  static const unsigned uNextState[] = { 1,0,3,4,2 };

  ASSERT(uCur >= 0 && uCur <= 4);
  return(uNextState[uCur]);
}

[소스 4]

위 소스는 입력값이 5가지 경우라는 것을 생각하고 5가지 경우에 따라
미리 계산된 값을 배열에 넣고 입력값을 첨자로 결과값을 리턴하는 소스입니다.


앞서 글들에서도 말했듯이 저는 프로그래밍의 세계는 상호교환(trade-off)의 세계라고
생각합니다. 위의 소스도 메모리를 써서 빠른 모듈을 만들어 낸 경우입니다.
메모리를 낭비하는 대신에 속도를 개선하는 것이죠. 판단은 여러분의 몫입니다.

저는 위의 마지막 소스 4가 진실로 화려한 소스라고 생각합니다.
저는 화려함이 좋다니깐요 ^.^

거짓 화려함에 빠지지 않는 지혜를  복습해 보았습니다.

PS. 소스 1 - 소스 4 는   스티브 맥과이어씨의 Writing Solid Code 의 6장 위험한 사업
에서 인용했습니다.

From Xevious7.  http://www.xevious7.com


top

Trackback Address :: http://xevious7.com/trackback/87

  1. 날자고도 2006/06/20 23:49 MODIFY/DELETE REPLY

    ((uCur <=1) ? (uCur?0:1) : (uCur==4)?2:(uCur+1));

    저도 이런문장을 싫어합니다.
    이해하는데, 너무 많은 시간을 필요로 하는거
    같아서요.

    잘된 코딩은 초보자가봐도 로직이 이해되기
    쉽게 만든 거라고 생각합니다. ^^

  2. xevious7 2006/06/21 00:23 MODIFY/DELETE REPLY

    날자고도 // 네 ^^ 저도 항상 심플한것을 좋아합니다. KISS 의 법칙 !

  3. 풍류혈 2006/06/30 11:35 MODIFY/DELETE REPLY

    저도 심플에 백만표. 그리고 유연성.

Write a comment