메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

프로그래밍 스타일(7 - 완결)

한빛미디어

|

2005-10-26

|

by HANBIT

17,146

저자: 한동훈

[지난기사보기]
프로그래밍 스타일(6)
프로그래밍 스타일(5)
프로그래밍 스타일(4)
프로그래밍 스타일(3)
프로그래밍 스타일(2)
프로그래밍 스타일(1)

2.12 괄호 형식

괄호형식은 크게 다음과 같은 형태가 가장 많이 쓰인다.

for(int i = 0; i < 100; i++) {
   // some code
}

for(int i = 0; i < 100; i++)
{
   // some code
}

필자는 대부분의 언어에서 두번째와 같은 형식을 사용한다. 첫번째와 같은 형식은 구조가 복잡할수록 괄호의 위치를 찾기가 어려워지고, 로직보다는 괄호의 위치에 더 신경을 쓰게한다. 그러나 아직도 많은 C, Java 프로그래머들은 이러한 위치를 선호한다. 물론 첫번째와 같은 방법을 쓰면 코드의 라인수는 줄일 수 있지만, 수행 성능에는 영향을 미치지 않는다. 원하는 형식을 사용할 수 있으며, 개인적으로는 두번째와 같은 형식을 권한다.

VB, Pascal과 같은 언어에서는 위와 같은 중괄호를 사용하여 블록의 시작과 끝을 표현하지 않는다. Python과 같은 언어는 괄호 대신에 들여쓰기로 이를 대신하는 독특한 표기법을 사용한다.

2.12.1 if 문의 괄호형식

경우에 따라 다음과 같은 형태의 괄호 형식도 널리 사용된다.

if(A) {
} else if( B) {
} else {
}

일부 프로그래머는 함수 선언에는 함수 선언 다음 줄에 시작중괄호를 두고, if 문등에는 문장의 끝에 중괄호를 두는 것과 같이 두 가지 스타일을 혼용하기도 한다. 필자는 C/C++ 언어를 사용하는 경우에 이 두가지 스타일을 혼용하고 있다.

2.13 코드를 절과 단락으로 분리하기

대부분의 사람들이 작성한 코드를 살펴보면 코드들이 라인을 분리하지 않고 다닥다닥 붙여서 코딩하는 것을 쉽게 볼 수 있다.

" We have another branch. Solve the branch recursively
   If Not rsSubtopics.EOF then
      Response.Write(" " + topic + "
")
      Do While Not rsSubtopics.eof
      subtopicID = rsSubtopics("topicID")
      subtopic = rsSubtopics("name")
      call SubTopicsInTree(dc, subtopicID, subtopic, depth + 1)
      rsSubtopics.movenext
      Loop
         " We have a leaf. Simply print the leaf
   Else
Response.Write(" " + topic + "
")
   End If

직관적인 코드라고 볼 수도 없으며, 단락으로 구분해야할 것을 다닥다닥 붙여놓아서 알아보기가 힘들다. 보다 읽기 쉬운 코드는 다음과 같을 것이다.

" We have another branch. Solve the branch recursively
If Not rsSubtopics.EOF Then

   Response.Write(" " + topic + "
")

   Do While Not rsSubtopics.eof?

      subtopicID = rsSubtopics("topicID")
      subtopic = rsSubtopics("name")

      Call SubTopicsInTree(dc, subtopicID, subtopic, depth + 1)
      rsSubtopics.MoveNext
   Loop

" We have a leaf. Simply print the leaf
Else
   Response.Write(" " + topic + "
")
End If

분명히 이와 같은 코드는 라인수는 더 길게 나온다. 하지만 각 코드가 단락에 따라서 구분되어 있기 때문에 코드를 보다 쉽게 읽을 수 있다. 코드는 결코 딱딱하게 머리 싸매면서 봐야하는 것이 아니다. 코드는 소설처럼 쉽게 읽을 수 있도록 절과 단락으로 적절히 구분되어 있어야한다.

2.14 주석은 코드의 내용을 기술하는 것이 아니다

먼저 2.13에서 살펴본 코드에서 if 문을 다시 한 번 보자.

If Not rsSubtopics.EOF then

이 주석에 대해서 여러분이 주석을 달게 된다면 어떻게 할까? 아마도 다음과 같이 주석에 쓰기 쉬울 것이다.

‘Subtopics 레코드셋에 레코드가 있다면

또 다른 코드를 살펴보자.

Employee = Employee + 1;

이 코드에 대한 주석은 보통 다음과 같이 할 것이다.

// Employee에 1을 더한다.

그러나 올바른 주석은 코드를 해석하는 것이 아니라, 코드가 행하는 내용이 무엇인지를 써야한다. 먼저, if 문에 대한 주석은 다음과 같을 것이다.

‘ 트리구조에서 노드를 갖고 있는 경우. 노드는 재귀적으로 해결한다.

두번째 Employee에 대한 주석은 다음과 같이 내용을 알 수 있게 바꿔야한다.

// 다음 종업원을 처리한다.

어떤 변수에 1을 더하거나 레코드셋에서 루프를 도는 것과 같은 것들은 굳이 주석으로 쓰지 않아도 알 수 있다. 그러나 그것이 어떤 의미인지 코드를 하나하나 이해하기는 어렵다. 주석에는 이 코드가 어떤 의미를 갖는지 그 내용을 쓰도록 해야한다.

심지어 필자는 단 30줄도 안되는 함수에 대한 주석을 3 페이지씩 썼던 적도 있다.

2.15 매크로 사용

예를 들어서, 엔진을 제어하는 코드를 작성한다고 할 때, 엔진의 최대속도가 80km/h이고, 엔진의 속도가 80km/h를 넘으면 엔진이 고장났다는 메시지를 출력한다고 하자.

$current_speed = 60;

if ( $current_speed < 80 )
{
   print "engine is workingn";
}

else
{
   print "engine is out of order!n";
}

그런데 엔진을 제조하는 기술이 발전해서 엔진의 최대속도가 120km/h가 되었다면 80이라는 숫자를 120으로 변경해야할 것이다. 만약, 이렇게 직접 숫자를 사용한 부분이 코드에서 여러곳이라면 모든 부분을 일일이 찾아서 수정해야한다. 이렇게 수정하다보면, 깜빡하고 수정하는 것을 잊어버린 코드도 생기게 되고, 버그의 원인이 된다. 이러한 꼉우에는 80과 같이 숫자를 직접 사용하는 대신에 전역 상수를 선언하도록 해야한다.

$SPEED_LIMIT = 100;

$current_speed = 60;

if ( $current_speed < $SPEED_LIMIT )
{
   print "engine is workingn";
}

else
{
   print "engine is out of order!n";
}

이와 같이 작성하면 나중에 엔진의 최고 속도를 수정할 필요가 생기더라도 한 곳만을 수정하면 된다.

이러한 방법은 대부분의 언어에서 모두 사용할 수 있다.(위 코드는 Perl로 작성했다)

자, 이제 다른 것을 논의해보자. 만약에 여러분의 응용 프로그램이 20명의 종업원을 다루도록 했다고 하자. 방금 배운 지식을 활용해서 다음과 같이 작성했다고 하자.

Private Const MAXEMPLOYEE = 20

Public Sub PrintAllEmployeeName()

   Dim LoopCtr As Integer
   Dim Employee(MAXEMPLOYEE) As New Employee

   For LoopCtr = 1 To UBound(Indx)
      Debug.Print Employee(LoopCtr).Name
   Next LoopCtr

End Sub

VB와 같이 대부분의 언어는 배열을 0에서 시작하기 때문에 이 경우에는 21개의 Employee 정보가 들어갈 수 있게 된다. 이와 같은 것이 혼동스럽다면 다음과 같이 조금 더 고쳐쓸 수 있다.

Private Const EMPLOYEENUMBER = 20
Private Const MAXEMPLOYEE = EMPLOYEENUMBER - 1

Public Sub PrintAllEmployeeName()

   Dim LoopCtr As Integer
   Dim Employee(MAXEMPLOYEE) As New Employee

   For LoopCtr = 1 To UBound(Indx)
      Debug.Print Employee(LoopCtr).Name
   Next LoopCtr

End Sub

위와 같이 간단한 팁을 사용하여 프로그래머가 이해하기 쉽도록 할 수 있다.

위 코드에서 한 가지 더 보아야할 것은 For 부분이다. 대부분의 프로그래머들은 이 부분을 다음과 같이 사용할 것이다.

For LoopCtr = 1 To MAXEMPLOYEE

와 같이 매크로 상수를 사용하거나 직접 숫자를 넣어서 사용할 것이다. 그러나 배열에 항상 정해진 수만큼 값이 들어있는 것은 아니다. 배열에 최대한 넣을 수 있는 값은 20개지만, 실제로는 14개만 들어가 있는 경우가 더 많을 것이다. 이러한 경우에 배열에서 가장 큰 범위값을 가져와서 이용하는 것이 보다 융통성있는 코드를 작성할 수 있도록 해준다.

2.15.1 for 루프

for( k = 0; k < 10; k++ )

for( k = 0; k != 10; k++ )

첫번째와 두번째의 차이점을 아는가? 첫번째는 k가 10번 이상만 수행되면 종료되는 루프이다. 두번째 루프는 루프가 끝난 시점에서 k = 10이 되기 때문에 k의 값이 루프를 수행한 횟수를 담고 있다는 것을 알 수 있다는 장점이 있다.

- for루프와 불변식에 대해서는 다음에 다룰 기회를 갖도록 하자

2.16 round-off 에러

최근에 VB는 부정확한 언어라고 하여 산수 계산도 제대로 못한다라는 기사를 본적이 있다. 그러한 기사가 인터넷을 통해서 전세계에 널리 퍼졌던 것을 보고 배꼽잡고 웃지 않을 수 없었던 일이 있다. 다음과 같은 코드를 실행시켜 보도록 하자.

Dim Result As Single
Dim LoopCtr As Integer
Result = 0

For LoopCtr = 1 To 10000

   Result = Result + 0.00001

   Next LoopCtr

Label1.Caption = Result

VB에서 레이블을 하나두고 다음과 같은 코드를 실행시켜보도록 한다. 0.00001을 1 만 번 반복해서 더하는 것이니 결과는 0.1이 나와야 할 것이다. 불행히도 결과는 0.0999915와 같이 된다. 이러한 오차가 생기는 것은 숫자를 이진수로 표현하는 컴퓨터의 표현 방식에 따른 것이다. 따라서 컴퓨터로는 0.1과 같은 간단한 수 조차도 제대로 표현할 수 없다. 우리가 0.1이라고 믿는 숫자는 컴퓨터에서는 실제로 0.100000000000000035와 같이 매우 작은 오차를 갖고 있을 것이다. 위와 같이 각각의 머신이 나타낼 수 최소한의 값을 머신 입실론(Machine Epsilon) 값이라 한다. 따라서 이러한 수치 오차를 줄이기 위해 Single 대신에 Double이나 Float와 같이 보다 정확한 수치 데이터 형을 사용해야하고, 위와 같은 코드의 오차를 줄이기 위한 방법을 써야한다.

C 언어에서 보자면 다음과 비슷한 코드를 사용할 수 있을 것이다. C 언어 프로그래머들에게는 꽤 익숙한 기교적인 방법일 것이다.

#include

int main(int argc, char* argv)
{
   int loopctr;
   loopctr = 0;

   while ( loopctr < 4 )
   {
      loopctr = loopctr + 4/3;
      printf("Loop : %fn", loopctr);
   }
}

이것은 C 언어 코드이다. 4/3을 통해서 루프를 4번만 돌도록 한 것이다. 이 코드에서 loopctr은 int 형으로 되어 있기 때문에 4/3의 결과에서 소수점 부분은 없어지고, 정수 부분만 남게 된다. 따라서 결과는 1, 2, 3, 4가 출력된다.

그러나 실제로 C 언어에서는 4/3의 결과는 무조건 1이 된다. 4/3의 결과인 1.3333…이 계산되도록 하려면 명시적인 타입 캐스팅을 사용해야한다.

다음은 고의적으로 round-off 문제가 일어나도록 재작성한 코드다.

#include

int main(int argc, char* argv)
{
   float loopctr;
   loopctr = 0.0;

   while ( loopctr < 4 )
   {
      loopctr = loopctr + (float)4/3;
      printf("Loop : %fn", loopctr);
   }
}

이 코드를 실행시키면 결과는 다음과 같다.

[traxacun@ns works]$ cc roundoff.c?
[traxacun@ns works]$ ./a.out
Loop : 1.333333
Loop : 2.666667
Loop : 4.000000

결과에서처럼 프로그래머가 의도한 대로 4번의 루프를 돌게되는 것이 아니라 루프는 3번만에 끝나게 된다. 또한 두번째 루프에서부터 round-off 에러에 의해서 2.666667로 되어 있는 것을 알 수 있다.(보다 자세히 확인하고 싶다면 %f대신에 %.24f를 사용하도록 한다. 32비트 데이터형은 24 비트의 mantissa 데이터를, 8 비트의 exponent 데이터를 저장한다)

이와 같이 여러분이 어떤 프로그래밍 언어를 사용하고 있더라도 round-off 문제를 일으킬 수 있다. 따라서 실수형의 데이터를 다루게 된다면 매우 조심해서 다뤄야한다. 또한, 이러한 round-off는 많은 방법으로 처리할 수 있으며, 이러한 에러 자체를 피해갈 수 있는 방법도 존재한다는 사실을 기억한다.( Machine Epsilon에 대해 더 자세히 알고 싶다면 C, C#, VC++에서의 Machine Epsilon에 대한 필자의 글을 참고하기 바란다)

재정 관련 데이터를 처리하는 프로그램을 작성하는 경우에 이와 같은 머신 입실론 값에 따른 오차 한계가 매우 중요한 문제가 된다.(적어도 돈 계산에는 오차가 용납되지 않는다. 공학에서처럼 10의 -5승과 같은 오차한계가 용납되지 않는다. ^^;)

따라서 여러분이 사용하는 시스템과 언어에 따라서 오차 한계를 정확히하고, 이러한 문제를 피하도록 한다. 이에 대한 논의는 이 글의 범위를 벗어나므로 생략하며, 관심있는 분들은 수치해석(Numerical Method) 관련서를 찾아보기 바란다.

2.17 대충 설계하지 마라

필자는 Y2K를 수정하는 작업을 담당한 적이 있으며, 하루 18시간을 UNIX 머신 앞에 앉아서 작업한 경험이 있다. 살도 빠지고, 몸무게도 줄고 있는데 배만 나오는 그 상황을 생각해 보라.

대충 설계하지 마라는 것은 대충 만들어 놓지 말라는 것과 같은 말이다. 어떤 것을 작성하는 데 있어서 나중에 해야지라는 생각은 곤란하다. 분명히 Y2K로 인해서 수정해야하는 소프트웨어들도 누군가 나중에 수정해야지라고 했을 것이다. 그리고 그것은 소프트웨어에 대재앙을 불렀을 것이다.

누군가는 종종 그런 얘기를 한다. 아무리 잘 만든 소프트웨어라 할지라도 곧 수정사항이 생기고 변경사항이 생기기 마련이므로 3년 이상 쓰는 소프트웨어란 없다고 말이다. 그러나 필자는 초기에 작성되어 계속해서 유지보수되어 20년 이상 사용되고 있는 소프트웨어들을 수도 없이 봐왔다. 그당시 최신기술들이 사용되고, 이 언어, 저 언어, 이 기술, 저 기술등이 사용되어 점점 눈덩이처럼 불어나서 아무도 시스템 전체를 이해하지 못하고, 무엇이 시스템에서 돌아가고 있는 것이며, 무엇이 돌아가는 않는 것인지 알 수 없는 상황에 직면한 적이 있다. 불행히도 그것을 정리해내고 바로 잡아서 시스템을 분석해내는 것은 아주 힘든 작업이며 시스템을 새로 개발하는 것에 버금가는 비용이 든다.

소프트웨어를 제대로 설계하고, 제대로 문서화를 해오면서 일관성을 유지한다면 유지보수에 그렇게 큰 어려움이 있지는 않을 것이다.

여러분이 어떤 소프트웨어를 작성하게 되더라도, 누군가 처음에 단지 임시로만 쓸 것이라고 얘기하더라도 여러분은 30년 동안 쓸 것을 만든다고 생각하고 만들어야한다.

2.18 대충 만들지 마라

여러분이 어떤 문제를 해결하는 데 있어서 쉽고 빠른 방법과 일반적이고 융통성있는 방법중에 한 가지를 선택하라고 한다면 일반적이고 융통성있는 방법을 선택한다.

모든 소프트웨어는 반드시 변경사항이 생겨나고 요구사항이 생긴다. 그리고 이러한 유지보수가 발생했을 때 쉽고 빠른 방법을 사용한 경우에 대개는 융통성이 없기 때문에 유지보수하기가 어려워진다. 따라서 조금 오래걸리더라도 보다 일반적이고 융통성있는 방법을 선택하도록 해야한다.

2.19 서드 파티 컴포넌트를 사용하지 않는다

서드 파티 컴포넌트를 사용함으로써 보다 나은 기능을 응용 프로그램에 구현할 수 있고, 그러한 기능을 자체적으로 개발하는 데 드는 비용을 절감할 수 있다.

그러나 응용 프로그램에 버그가 발생하여 수정하게 되었을 때, 서드 파티 컴포넌트에서 버그가 발생한 경우에 버그의 수정을 서드 파티 컴포넌트 개발사에 얘기해야하고, 최악의 경우에는 버전업된 컴포넌트를 구입해야하고, 이전 버전에 대해서는 지원을 중단하는 경우다. 이러한 경우에 여러분은 버그를 없애기 위해 같은 기능을 하는 컴포넌트를 개발해야하거나 새로운 컴포넌트를 구입해야할 것이다.

소스가 공개되어 있지 않은 상용 소프트웨어를 이용하는 경우에 문제가 있어도 여러분이 직접 수정할 수 없다. 따라서 개발하는 응용 프로그램에서 꼭 필요한 경우가 아니라면 서드 파티 컴포넌트의 사용을 자제하도록 한다.

필자의 경험에 따르면 같은 회사에서 제공한 컴포넌트의 버전에 따라서 작동하는 절차 같은 것들이 너무나 다르게 변경된 적이 있어서 고생한 경험이 있다.(믿거나 말거나 아직도 이 응용 프로그램을 유지보수하기 위해선 오래된 소프트웨어만을 사용하고 있다. 전국에 있는 각 지사 사용자에게 무엇을 받아서 설치하고 하는 등의 지시를 일일이 할 수도 없고, 또 이것만으로 다양한 환경에서 발생하는 문제를 해결하지 못한다는 것을 이미 경험을 통해서 너무나 잘 알고 있기 때문이다)

코드의 규모가 작고, 사소한 변화라면 여러분이 직접 코드를 찾아다니며 변경하고 테스트할 수 있을 것이다. 그러나 코드가 이미 한 개인이 수정하기에는 너무 커졌다면 이와 같은 변화 자체가 여러분의 프로젝트에 엄청난 재앙이 될 것이다. 따라서 서드 파티 제품의 사용은 최대한 자제하는 것이 좋다. 설령, 서드 파티 제품을 전혀 사용하지 않는다고 해도 기본 라이브러리 자체의 버그만으로도 여러분을 충분히 괴롭히고도 남을 것이다.

2.19.1 써드 파티 컴포넌트에 대한 변명

RUP가 개발자 세상을 휩쓸고 CBD가 세상을 휩쓸었던 때가 있다. 요즘은 다양한 프레임워크들이 흐름을 이끌어가는 세상이다. 개발자 한 사람이 모든 것을 개발 할 수 없고 다른 사람이 만든 솔루션을 사용할 수밖에 없다. 그렇지만 최대한 서드 파티 컴포넌트를 사용하지 않는 것이 좋다는 것도 사실이다. 쇼핑몰을 위한 결재 시스템을 직접 만드는 것은 분명 어리석다. 외부의 결재 시스템을 자신의 사이트에 덧붙이는 형태가 일반적이며, 이는 대형 쇼핑몰이나 포탈도 예외는 아니다.

3년간 사용하던 결재 시스템을 제공하던 회사가 부도가 나서 다른 곳으로 결재 시스템을 바꾼 경험이 있다. 시스템을 변경하는 동안 겪게되는 손실도 있지만 외부 솔루션을 사용한다는 것은 늘 어느 정도의 위험성을 갖고 있다는 것을 얘기한 것이다. 매우 저렴하고 훌륭한 차트 시스템을 제공하는 국내 중소기업의 컴포넌트를 이용하여 윈도우와 웹 응용 프로그램을 작성했는데 3년 후에 버전업된 컴포넌트를 구입하려하니 이미 회사가 부도가 났다. 차트 만이 아니라 버튼 컨트롤도 보다 편한 기능과 예쁜 모양을 제공하기에 세련된 인터페이스를 보여주기 위해 이러한 컴포넌트들을 자주 이용했으며, 세련된 인터페이스에 감탄을 보내곤 했다. 외국의 유명한 컴포넌트 제작 전문회사의 것을 이용했으나 이 회사는 다른 회사에 인수되어 버렸고, 이 사업 부문을 중단했다. 이로 인한 수정 작업이 그리 간단한 것이 아님은 말할 것도 없다.

또 다른 예로 동영상 스트리밍 서브시의 보안을 위해 도입한 보안 솔루션을 살펴보자. 닷넷이 나오기 전에 개발된 이 제품은 매우 저렴한 가격에 보안 기능을 제공했고, 여러 회사의 제품을 비교해서 가격대비 성능면에서 우수하다 생각해서 이 제품을 선택했다. 그러나 닷넷이 나오면서 이 솔루션은 시스템에 닷넷이 설치되어 있으면 동작하지 않는 현상을 보였다. 소스의 제어권은 우리에게 없으며 솔루션 제작 회사에 있다. 때문에 닷넷 소프트웨어 개발은 불가능하게 되었으며, 외부 솔루션 하나 때문에 전체의 발이 묶이는 현상을 경험했다. 닷넷이 나온지 횟수로 5년이 넘어도 닷넷 환경에서 수행되는 버전은 나오지 않았다. 윈도우 서버 2000에서만 수행되며 2003 서버에서는 수행되지 않는다.

때문에 윈도우 2003이 보다 나은 동영상 스트리밍 서비스를 제공한다고 해도 우리는 윈도우 2003으로 업그레이드를 할 수 없었다. 결국, 2005년도에 서버를 2003으로 변경하면서 솔루션 업체를 변경하고 말았고, 그에 따른 스트리밍 서비스를 전부 재작업해야 했다.

외부 솔루션을 사용하는 것에는 늘 위험이 따라다니며, 솔루션을 바꾼다는 것은 내가 사용하는 모든 소스 코드를 변경해야 한다는 것을 의미한다. 내가 하고 싶었던 이야기는 이러한 위험을 인지하고 꼭 필요한 만큼만 사용하는 것이 좋다는 것이다. 외부 솔루션의 변경에 대해서도 내가 작성한 프로그램의 변경사항과 코드 오염을 최소화하는 방편은 내가 만든 컴포넌트와 외부 컴포넌트 간에 하나의 레이어를 두는 방법이다. 이러한 레이어를 두는 방법으로 가장 잘 알려진 것으로는 GoF의 Adapter, Bridge, Decorator 패턴이 있다.

써드 파티 컴포넌트만 꼭 이런 문제가 있는 것은 아니다. 필자가 한 때 사용했던 PHP에서도 이런 문제가 있다. PHP에서는 Prepared statement라는 기능을 제공하지 않았는데 4.1 버전 이후부터 Prepared statement라는 것을 제공하기 시작한 것으로 기억한다. 다만, 이 기능을 사용하기 위해서는 PHP에서 사용했던 MySQL 관련 코드를 모두 수정해야했다. 예를 들어, mysql_connect, mysql_close, mysql_query와 같은 함수들은 mysqli_connect, mysqli_close, mysqli_query 함수로 바꿔야만 Prepared statement 기능을 사용할 수 있다. PHP로 개발한 솔루션을 보다 나은 성능 향상을 위해 Prepared statement 기능 하나를 사용하기 위해 전체 API를 변경하는 것은 비효율적이지 않을까?

필자가 쓴 PHP Data Access 2. 라이브러리 작성에서 처럼 하나의 레이어를 두고, 이 레이어를 이용해서 PHP 솔루션을 개발했기 때문에 필자는 간단하게 버전업을 할 수 있었지만 대부분의 개발자는 이런 상황에 모든 코드를 직접 수정해야 할 것이다.

ASP 업로드 컴포넌트를 이용하여 개발했을 때도 업로드 컴포넌트 1.5에서는 Open 메서드를 사용하지 않았는데 2.0부터는 Open 메서드를 호출한 다음에 각 폼 요소에 접근할 수 있게 변경되었다. 당연히 컴포넌트 버전에 따라 필자의 코드는 모두 깨지거나 정상적으로 동작하게 되는 이상한 프로그램이 되고 말았다. Open 메서드 하나 때문에 업로드 컴포넌트 버전에 따라 두가지 버전의 ASP 코드를 작성해야 하는가? 이 경우에도 소스의 제어권이 내가 아닌 써드 파티에 있기 때문에 참담한 기분이 되고 만다. 업로드 진행상황을 상태바로 보여주기 위한 기능을 추가하고 싶어도 추가할 수 없다. 결국, 이런 문제 때문에 직접 업로드 컴포넌트를 작성하게 된 경험이 있다.

써드 파티 컴포넌트나 프레임워크를 사용하지 않을 수는 없다. 그러나, 이러한 도구들을 사용할 때는 항상 그 위험성을 인지하고, 변경사항이 발생했을 때 그 변경사항을 최소화할 수 있는 방향으로 코드를 작성해야 한다는 것을 염두에 두어야 한다.

CBD 뿐만 아니라 객체 지향 프로그래밍에 대한 여러가지 장단점에 대해 알고 싶다면 『Component Software: Beyond Object-Oriented Programming』 (1999, Addison Wesley)를 살펴보기 바란다. - 2003년도에 2판이 출간되었다.

- 필자 기억에 1판에서 2.19 써드 파티 컴포넌트를 사용하지마라에 대한 많은 비난이 있었다는 것을 기억한다. 앞서 처음에도 밝혔듯이 이는 필자의 생각이지 이에 대한 옳다, 그르다를 따지는 것이 아니었다. 다양한 의견은 좋으나 비난만은 하지 않기를 바란다.

첫번째 판에서는 "서드 파티 컴포넌트를 사용하지 말라"고 얘기했다. 이에 대한 의견으로 올라온 것으로 "요즘은 CBD(Component Based Development: 컴포넌트 기반 개발)인데 시대에 역행하는 이야기를 하는가? 당신 무식해!" 라는 식이었다. 이를테면 같은 의견이라도 다음과 같이 완곡하게 의견을 올려달라는 것이다.
"오늘날에는 CBD 개발을 얘기하고 있기 때문에 저는 당신의 의견에 동의할 수 없습니다." "오늘날에는 CBD가 대세인데 시대에 뒤쳐진 얘기가 아닐까요?" 와 같이 말이다.

2.20 빌드 도구를 사용한다

Makefile과 같은 빌드 파일을 사용하여 다른 프로그래머가 여러분의 소스 코드를 컴파일하는 방법을 알 수 있도록 해야한다. 이와 같이 하지 않으면, 아무도 여러분의 코드를 컴파일하지 못하게 될 수도 있다.

오늘날에는 다양한 환경에 대한 다양한 빌드 도구들이 존재한다. VS의 솔루션 파일이나 프로젝트 파일을 그대로 빌드해줄 수 있는 MSBuild, XML 기반 설정 파일을 이용한 빌드 솔루션인 Ant, Ant를 닷넷 환경에 포팅한 NAnt가 있다. .NET Framework 2.0에는 MSBuild가 기본 파일로 포함되어 있다.

빌드 도구를 이용하면 빌드를 자동화하는 것 외에 일일빌드를 통해 모든 코드가 제대로 동작하는지 검증할 수 있다는 장점이 있다. 또한, 모든 직원에 퇴근한 밤 사이에 하루동안 제출된 코드를 취합해서 오랜시간이 걸리는 빌드를 자동화하는 것도 가능하다. 이러한 목적에는 CruiseControl.NET과 같은 도구가 있다.

참고. Cruise Control .NET

2.21 주석을 철저히한다

프로젝트에서 필자는 변수는 한 줄에 하나씩 선언하고 주석을 달도록 했다. 뿐만 아니라 코드 전체에 있어서 모든 주석을 달도록 한 적이 있다. 그리고 프로젝트가 끝나고, 그 회사에 코드를 넘겨줬을 때, 그들은 일반적인 코드에 사용된 주석을 불필요한 것이라하여 모두 정리하고, 꼭 필요하다고 판단한 주석만을 남겨두었다.

결국에 시간이 흘러 코드를 이해할 수 없게 되어서, 모든 코드를 다시 작성해야만 했다.

이 예에서 알 수 있는 것처럼 주석은 지나쳐서 부족한 것이 아니다. 많으면 많을수록 좋다.

2.22 주석의 거짓말

주석의 내용과 코드의 내용이 일치하지 않을 때 주석의 거짓말이라고 부르기를 필자는 좋아한다. 코드에 문제가 생겨서 변경했는데 주석만 변경하지 않은 경우 이런 현상이 발생한다. 철저한 주석만큼 중요한 것은 변경사항이 있을 때 이를 주석에 제대로 반영하는 것이다.

3. 회사 문화

3판에 짧게 낙서처럼 글을 남겨본다.

앞서 얘기가 지극히 개인적인 것들이었다면 회사문화란 상당히 정치적인 것들이다. 항상 좋은 사람들만을 만나는 것이 아니라 기상천외한 사람들을 만나고 상대하며 살아가야하는 것이 사람의 인생살이다.

많은 분들은 프로젝트가 성공하기 위해 개발 환경, 언어, 개발방법론, 프로젝트 관리방법 같은 것을 떠올린다. 불행히도 어떤 언어, 어떤 개발 방법론에도 성공과 실패는 있다. 결국에 이런 것들은 성공을 위한 필수조건이 되지 못한다. 오직 충분조건밖에 되지 못한다.

"Agile Software Development"를 보면 이런 말이 나온다.

"뛰어난 사람은 필요없다. 프로젝트가 성공하기 위해서는 적절한 사람들이 제대로 움직이는 팀이며, 이들은 주어진 프로세스나 기술에 관계없이 프로젝트를 성공시킨다. - 프로세스나 기술은 그들의 업무를 도와주거나 방해할 수는 있겠지만 -

Object Technology International 창립자인 Dave A. Thomas의 성공 방정식은 "어떤 사람들은 소프트웨어를 완성해 내놓지만 어떤 사람은 그렇지 못하다. 나는 소프트웨어를 산출해 낼 수 있는 사람을 고용하였다"라고 말했다."

참고자료
  • Code Complete, 2nd Ed.
  • Agile Software Development, Alistair Cockburn, Addison Wesley
TAG :
댓글 입력