저자: 한동훈
 
시작하기전에

"프로그래밍 스타일"이라는 글로 글을 쓴지 벌써 4년째가 되었고, 글 하나에 많은 일들이 있었다. 첫번째 판이 한빛미디어에 올라왔고 많은 피드백이 있었으나 사이트 개편이후로 여러분의 소중한 의견들이 모두 소실되었다.

두번째 판은 글을 작성했지만 개인 홈페이지를 없앤 이후였고, 한빛미디어에도 올라오지 않았다. 게다가, 작업의 결과물을 모아놓은 하드 디스크의 고장으로 원본 기사를 소실했다. 다행히도 한빛미디어에서 2003년도 백업판을 구할 수 있어서 세번째 판을 작성하기로 마음먹었다. 내용을 확인해보니 서문만 2판이고, 나머지는 1판과 동일했다.

두번째 판은 첫번째 판에 대한 많은 분들의 소중한 의견을 포함해서 개정했었고, 세번째 판에서는 그 이후에 프로그래밍 스타일 뿐만 아니라 개발 환경에 대한 변화를 추가하고 싶었다. 모쪼록 이 글이 프로그래밍을 하는 데 있어 도움이 되기 바란다.

카더라 통신에 의하면 프로젝트 진행시 "코딩 스타일 지침", "프로그래밍 스타일 지침"등에 자주 활용되었더라는 이야기가 있다. :)

서문

프로그래머가 되려는 사람, 프로그래밍을 하고 있는 사람, 모두에게 있어서 긴 논쟁이 되어 왔던 많은 주제들이 있다. 어떠한 언어가 더 우수하다는 것에서부터 프로그래머가 되려면 어떤 것들을 먼저 학습해야 한다는 것에 이르기까지 정말로 많은 주제들이 있다. 그리고 그 중에 하나가 아마도 프로그래밍 스타일에 대한 것일 것이다.

프로그래밍 스타일은 다르게 말하면 함수의 명명 방법이라던가, 들여쓰기 간격, 괄호의 위치와 같이 쓸데 없는 것일 수도 있다. 조금 더 심하게 말하면 '너희는 이것을 따르라'라는 독재자의 명령일 수도 있다. 하지만 프로그래머마다 프로그래밍하는 스타일이 다르기 때문에 프로그래밍 스타일은 프로그래머 각각의 개성으로 받아들여질 수 있는 것이기도 하다. 하지만 혼자서 프로그래밍하는 것이 흔한 일은 아니기 때문에 분명히 어떠한 규칙이 있어야 한다. 그렇지 않으면 저마다 만들어내는 코드들의 모양새가 다르기 때문에 분명히 혼란스러운 모습을 보이게 마련이다. 흔히 말하길, 코드는 ‘읽기 쉬워야 하고’, ‘알기 쉽게 주석은 많이 들어가야 한다’라고 얘기하지만 프로그래밍 스타일에서 다루어야 할 진짜 핵심은 어떻게 하면 조금이라도 더 ‘버그없는 프로그램’을 만들어 낼 것인가라는 것이다. 때때로 다른 프로그래머들이 다음과 같이 말하는 것을 들을 때가 있다.

"전에 회사에서 작성한 코드를 수정해야 하는데, 후임자가 그 코드를 이해하지 못해, 코드를 작성한 자신에게 물어보기 위해 찾아왔다."

자신은 자랑스러운 일이라고 생각한 모양이다. 실제로 그가 작성한 코드에 버그가 있어서인지, 이해하기 어려운 알고리즘을 구현한 것인지, 프로그래밍적 기교를 많이 사용해서 알아보기 어려운 것인지, 그 이유는 모른다. 그러나 다른 사람이 알아볼 수 없는 코드를 작성했으므로 그는 실패한 코드를 작성한 것이 된다. 아마도 이 사람이 작성한 코드는 다른 프로그래머에 의해 보다 읽기 쉬운 코드로 재작성된 뒤에 폐기처분 될 것이다. 그리고 이에 따른 피해는 모두 회사에 돌아간다. 뛰어난 프로그래머와 함께 일한다는 것은 즐거운 일이며, 진정 뛰어난 사람은 다른 사람도 쉽게 알아볼 수 있는 코드를 작성한다.

여기서 이야기 하고자 하는 프로그래밍 스타일이란 ‘어떻게 하면 버그가 없는 프로그램을 만들어 낼 것인가!’, ‘다른 사람이 이해하기 쉬운 코드를 만들려면 어떻게 해야 하는가!’에 대한 것이다. 어떻게 보면 프로그래밍 스타일이라는 것이 독재자처럼 보일지도 모른다. 그러나 여기에 있는 모든 이야기들은 그저 이렇게 하는 것이 좋다라는 하나의 방법론일 뿐, 반드시 ‘그렇게 해야 한다’는 것은 아니다. 여러분의 프로그래밍 스타일은 여러분이 작성한 코드의 길이가 5천줄, 1만줄, 10만줄, 100만줄씩 변해감에 따라 계속해서 변해가게 될 것이다. 1만줄 미만의 코드에서는 아무 문제가 없던 프로그래밍 스타일도 10만줄에서는 문제를 일으킬 수도 있기 때문이다.

끝으로, 이 글에 대해서 ‘옳다/옳지않다’라는 소모적인 논쟁은 하지 않길 바란다. 다만 이것을 참고로 조금이라도 버그 없는 코드를 작성하는 데 도움이 되었으면 할 뿐이다. 리누스는 리처드 스톨만의 GNU 코딩 스타일을 찾아서 불 속에 던져버리라고 하였다. GNU 코딩 스타일에 대한 리처드 스톨만과 리눅스 커널을 작성한 리누스와의 코딩 스타일에 대한 논쟁처럼 소모적인 것이 되기를 바라지 않는다.

이 글을 보는 법

하나의 언어에 대한 이야기가 아니라 프로그래밍에 있어서 공통된 이야기들을 자유롭게 썼다. 독자들의 마음에 드는 부분만을 남겨두고, 마음에 들지 않는 부분은 지워버린다. 추가할 것이 있으면 스스로 추가한다. 이와 같이 하면서 끝까지 읽어간다면 여러분 또는 팀의 프로그래밍 스타일이 완성될 것이다. 이제부터 프로그래밍 스타일에 대한 이야기를 시작해보도록 하겠다.

1. 작업 환경에 대하여

프로그래머에게 작업 환경은 두 가지로 나눌 수 있다. 프로그램을 개발하기 위한 PC와 소프트웨어에 대한 것과 사람이 작업을 하는 환경에 대한 것이다. 두 가지 모두 쉬운 것은 아니지만 때론 사람과의 관계가 모든 것을 좌우하기 때문에 가중치를 둔다면 후자에 두고 싶다. 여기서는 후자의 물질적인 작업환경에 대해 살펴볼 것이다.

1.1 시간을 관리하자

UNIX 시스템에서 프로그램을 개발하여 전국에 있는 시스템 관리자들에게 배포한다는 것은 멋진 일이다. 다른 사람이 개발한 프로그램의 버그를 찾고 수정하는 것 또한 재미있는 일이다. 전산 시스템을 운용한지가 14년 정도 되었는데, 여기서 말하는 14년이란 각기 전산 시스템을 도입하거나 업그레이드 한 시기가 다르다는 것을 의미한다. 내가 개발에 사용한 UNIX 시스템 외에 다양한 시스템들이 존재한다는 것이고 데이터의 한글 처리도 시스템마다 다르다는 이야기이다. 내가 개발한 UNIX 시스템과는 전혀 다른 시스템들도 많았으며, 내 시스템에서 문제없는 프로그램들도 다른 시스템에서는 문제가 발생하기도 했다. 이로 인해 전국의 담당자들로부터 쉴 새 없이 오는 전화 문의에 응답해 주느라 내 업무에는 손도 못 댄 적이 있다. 결국, 다른 한 사람에게 전화 응대만을 전담하고, 회의실에서 하루 5시간 동안 집중적으로 일을 마쳤다. 물론, 용건이나 프로그램에 문제가 있는 경우에도 메모 하도록 한 다음에 나중에 일괄적으로 전달받는 형태를 취했다.

프로그래밍은 단순 노동이 아니라 정신을 집중해서 해야 하는 일이다. 단순히 워드 아르바이트처럼 하루 1시간씩, 하루 10페이지씩 입력하는 일이 아니다. 아주 잠깐 1분 동안 다른 곳에 정신을 팔아도, 내가 지금 어디까지 했는지, 이 부분에 무슨 코드를 넣어야 할지 다시 고민해야 하고 신경써야 한다.

프로그래머들에게 올빼미족이 많은 것은 결코 우연이 아니다. 그들은 아무에게도 간섭받지 않고 모든 것을 잊고, 오직 코드 하나에 집중해서 작업할 수 있기를 바라는 것이다. 그러나 당신이 말단 프로그래머라면 회사에서 이렇게 멋대로(?) 행동하는 것이 어려울 수도 있다. 그렇다면 당연히 윗사람을 설득시킬 수 있어야 하고 그러한 환경을 만들어야 한다.

또 다른 얘기, 당신이 팀장이라면 팀 구성원들이 작업 보고서나 다른 업무 때문에 시간을 낭비하는 일이 없도록 해야 한다. 마찬가지로 팀장이 팀 구성원들과 필요한 얘기를 할 때마다 시시때때로 불러댄다면, 그것은 팀 내의 생산성을 헤치는 일이 될 것이다. 필요한 것이 있다면 업무 시작 전에 오늘 해야 할 일에 대해서 얘기하고, 퇴근 전에 시간을 정해서 오늘 한 일과 미처 끝내지 못한 일들에 대해서 얘기하는 것이 더 나을 것이다.

과연 이것만으로 모든 것이 끝나는 것일까? 미안하게도, 큰 조직내에서 업무를 하다보면 다른 부서 사람들이나 외부 사람들의 요청에 도움을 줘야 하는 경우도 있고, 반대로 도움을 받아야 하는 경우도 있다. 그러다보면 외부 요청으로 인해 작업 시간을 모두 빼앗기는 경우도 생기게 된다. 결국, 이와 같은 외부 요청에 대해서도 ‘몇 시 이후에 처리한다’와 같은 구체적인 계획을 세워야 한다. 필자의 경우, 정말로 해야 할 일이 많을 때에는 회의실에 전화기를 뽑아버리고, 문에 '절대 들어오지 마시오'라고 써 붙이고, 문을 잠궈버린 적이 있다. 비록 짧은 5시간이었지만 내가 일주일동안 한 일 보다 그 시간에 한 일이 더 많았을 때도 있었다.

일부 조직에서는 이와 같은 문제 때문에 오전 두시간을 회의도 없고, 다른 것을 하지 않으면서 오직 업무에만 집중하는 "업무 집중 시간"을 갖는 곳도 있으며, 실제로 생산성이 높아졌다고 답하는 곳도 많다.

말단 프로그래머라면 회사에서 이렇게 멋대로 행동하는 것이 어려울 수도 있다. 그렇다면 당연히 윗사람을 설득시킬 수 있어야 한다

1.2 자기 자신을 관리하라

프로그래머에게 자기 관리는 아주 중요한 문제다. 프로그래머가 자기 관리에 실패하는 경우에 생산성이 급격히 떨어질 수 밖에 없다. 따라서, 숨막히는 갑갑한 분위기는 싫지만, 어느 정도 자기 통제를 할 수 있어야 한다.

우리가 흔히 하는 실수 중에 하나는 프로젝트 초기의 여유로움과 프로젝트 마감때의 급박함이라는 것이다. 그러나 프로젝트 초기에 할 일이 없다고 빈둥대지 않았으면 한다. 실제로 이렇게 얘기하면 초기에는 내가 해야할 일이란 아무것도 없다라고 항변할 수도 있다.

그러나 프로젝트 초기에 요구 분석을 진행함과 동시에 자신만의 설계를 생각해보는 것이 좋다. 실제로 팀장과 클라이언트와의 회의 이후에 팀장은 각각의 팀원들에게 회의의 내용과 해야할 것들에 대해서 알려줄 것이고, 자신이 해야할 것이 무엇인지에 대해서 알 수 있을 것이다. 결국, 그 이외의 남는 시간에 세밀한 설계까지 생각해 볼 필요가 있다. 그것이 실제로 쓰일지, 그렇지 않든지 간에 말이다.

프로젝트 완료 시기가 다가오게 되면, 아직도 해야할 일들이 이렇게 많은데라거나 마감 시간을 맞추고 코드를 빨리 완성해야한다는 압박감 때문에 자기 통제를 쉽게 잃게 된다. 그리고 설계보다 코드를 작성하는 것에 더 우선 순위를 두게 된다. 그러나 실제로는 마감시간보다 설계에 더 높은 우선 순위를 두어야한다. 또한 점검에 우선 순위를 두어야한다. 성급하게 코드를 작성함으로써 생기는 조잡한 실수를 막도록 주의해야한다. 실제로 전체 코드에서 성급하게 완성된 코드에서 더 많은 버그가 발생할 것이다.

1.2.1 1.2의 문제점

1.2 자기 자신을 관리하라는 글이 갖는 문제점은 프로그래머 개인에 대해서만 초점을 맞췄다는 것이다. 프로젝트 초기의 여유로움과 마감의 급박함은 각 분야별로 업무 분담이 맞지 않는다는 것을 의미한다. 결국, 전체적인 프로젝트를 진행하는 절차에 문제가 있는 경우이며, 이 경우에 말단 프로그래머로서 프로토타입을 만들거나, 업무에 필요한 라이브러리와 같은 기본 도구를 개발하는 것으로 후반의 업무 집중을 쉽게 풀어보자는 데 의미를 둔 글이다.

필자와 일한 회사중에는 이를 재치있게(?) 풀어낸 회사가 있었다. 두 곳이 있었다. 한 곳은 프로젝트의 진행 상황에 따라 디자이너, 개발자를 자유자재로 고용하며 업무를 조율해 나갔다. 이렇게 하기 위해서 디자이너를 위한 지침, 개발자를 위한 지침이 준비되어 있었다. 개발자를 위한 지침을 보자면 코딩 스타일에서부터 시작해서, 프로그래밍시에 A를 처리하기 위한 방법과 같은 하우투(HowTo)를 모아놓은 개발 가이드라인 같은 것이 있었다. 어떻게 보자면 코드북, 레퍼런스, 쿡북과 같지만 자신들의 업무 도메인에 특화되어 있었다. 때문에 2주간 일하는 사람, 4주간 일하는 사람과 같은 식으로 분화되어 있었다. 장점은 업무에 따라 인력을 손쉽게 조율하며 일할 수 있었다는 점과 인건비를 효율적으로 사용한다는 것이며, 단점은 인력 관리와 전문성 문제가 있었다.

다른 한 곳은 회사에 기획자, 디자이너, 개발자가 모두 정직원으로 있었고, 꼭 필요한 경우에만 계약직을 고용했었다. 대신, 처음부터 끝까지 모든 사람이 함께하지 않고 프로세스에 따라 투입되는 분야와 인력이 달랐다. 디자이너와 개발자가 A사의 개발을 하는 동안 기획자는 B사의 기획을 하고, A사의 개발이 끝나면 B사의 개발에 투입되고, 기획자는 다시 C사를 기획하는 형태였다.

아마도 다양한 방법이 있겠지만 실제로 이들 회사가 운영하는 방법은 인상깊었다. 하지만, 한편으로는 빡빡한 한국의 SI에서 살아남기 위한 자구책으로 이해되기도 했다.

To be continued...


[출처 : http://www.hanb.co.kr/network/view.html?bi_id=1128]
제공 : 한빛 네트워크
저자 : 문우식
출처 : Blog2Book, 패턴 그리고 객체지향적 코딩의 법칙

구조적으로 더 나은 방법

C로 작성할 경우 기본적으로 지켜야 할 규칙들을 간단히 정리해보면 아래와 같다.
  • 관련된 구조체와 함수를 쉽게 연관지을 수 있는가?
  • 구조체의 변수들은 어떻게 수정되어야 하는가?
  • 의도되지 않은 수정이 이루어졌을 경우 어떻게 동작해야 하는가?
  • 사용해야 될 함수와 말아야 될 함수들은 어떻게 구분하는가?
복잡한 객체지향의 여러 개념은 일단 생각하지 말기로 하자. 우선 중요한 점은 객체란 무엇인가를 이해하는 것이다. 우리를 혼란스럽게만 만드는 어설픈 자동차, 비행기 예제는 넣어 두기로 하겠다. 어설픈 비유로 혼란을 겪어서는 안된다. 바로 눈 앞에 보이는 객체를 다루어 보자.

C++에서는 객체를 클래스(class)로 표현한다. 결론적으로 위에 언급한 4가지를 모두 클래스를 사용하면 쉽게 만족시킬 수 있다. C는 데이터와 함수가 분리되어 있는 언어이므로 언어적으로 이 둘을 묶을 수 없다. 그래서 이 둘을 묶기 위해서 C에서는 구조체에 함수 포인터를 넣는 방법을 사용할 수 있지만 C++은 그런 복잡한 과정 없이 언어 자체에서 데이터와 코드를 묶어서 사용할 수 있는 기능을 제공한다.

어설픈 객체지향의 혼란은“자동차를 예로 들었을 때 바퀴는 속성(Attribute). 시동을 거는 것 따위를 행위(Behavior)”라고 설명하면서부터 시작한다. 전통적인 프로그래밍의 기본은 데이터를 함수로 조작하는 것이다.

반면 객체지향 언어에서 객체라는 것은 메모리상의 데이터를 직접적으로 다루는 로우 레벨(Low-Level)인 기계적 개념이 아닌 좀 더 하이 레벨(High-Level)의 논리적 개념이 기본이 된다. 이 것을 이해하고 나서 여러 가지 객체지향 언어가 가지는 특성을 이해하는 것이 중요한 것이지 정작 객체에 대한 모호한 개념만 가진 채 상속이니 다형성이니 하는 특성만 이해하는 것은 바람직한 방법이 아니다.

왜 C에서 C++로 발전했는지와 위에서 봤던 GIMP코드의 함수 모양을 연관 시켜보면 이해가 빠를 것이다. 개발자가 일일이 신경써 주면서 GIMP처럼 이해하기 쉽도록 만드는데 드는 비용이 100이라면 객체지향 언어에서 제공하는 클래스라는 도구를 이용하면 그 비용을 50 정도로 줄일 수 있다. 이것은 생산성의 문제이다. 객체지향이라는 도구를 이용하면 데이터와 코드를 쉽게 모을 수 있고 의도되지 않은 행동으로부터 데이터를 보호할 수 있다. 이런 기본 개념을 토대로 구조적 프로그래밍으로 개발하면서 필요한 여러 가지 기법(재사용성이나 확장성)들을 C문법 안에서 테크닉적으로 활용하는 차원이 아닌 언어에서 지원해 주는 기본 기능으로 만들어 모든 개발자들이 더 쉽고 생산성 있게 개발할 수 있는 방법이 언어적 관점의 객체지향 개발 방법인 것이다.

C로 만든 String 예제

C를 이용하여 간단한 스트링을 구현해 보자. 우선 스트링을 저장하기 위해 아래와 같은 구조체를 정의하였다. 구체적인 설명은 주석을 참조하자.
typedef struct _ST_STRBUF
{
   intm_nLen; // 스트링 길이
   char* m_pStr; // 스트링 데이터의 힙(Heap)메모리 주소
} ST_STRBUF, * PST_STRBUF;
이 구조체를 다루기 위해 아래와 같은 함수를 추가하였다.
// a_nStrLen만큼 a_pstStr구조체를 초기화한다.
int mystr_new(ST_STRBUF* a_pstStr, int a_nStrLen);

// 문자열 a_pStr을 a_pstStr의 문자열에 할당한다.
int mystr_assign(ST_STRBUF* a_pstStr, char* a_pStr);

// 문자열 a_pStr를 a_pstStr문자열 뒤에 붙인다.
int mystr_append(ST_STRBUF* a_pstStr, char* a_pStr);

// 문자 a_chFind를 a_pstStr에서 찾는다.
int mystr_find(ST_STRBUF* a_pstStr, char a_chFind);

// a_pstStr를 삭제한다.
int mystr_delete(ST_STRBUF* a_pstStr);
작성한 함수는 모두 스트링 구조체(ST_STRBUF)를 다루기 위한 함수들이다. 스트링 구조체와 함수를 이용해서 간단한 샘플 코드를 작성해 보자(리턴값은 무시하겠다).
int main()
{

   ST_STRBUF stStrBuf = { 0, };
   
   mystr_new(&stStrBuf, 256);

   // 초기화를 안한다면 아래 호출되는 모든 함수는 오동작 할 것이다.
   mystr_assign(&stStrBuf, “abc”);
   mystr_append(&stStrBuf, “def”);

   // mystr_assign을 먼저 호출 하지 않았다면 오동작 할 것이다.
   mystr_find(&stStrBuf, ‘d’);
   
   // 2번째 파라미터가 문자가 아닐 경우 오동작 할 수 있다.
   // 문자인지 판단하는 함수가 필요하다.
   mystr_delete(&stStrBuf);

   return 0;
}
위 소스에 혹시나 발생할 수 있는 오동작 가능성에 대해 적어 보았다. 실제 개발을 하다 보면 에러 처리를 위해 코드의 덩치가 커지는 경우가 많다. 이런 경우 모든 예외상황에 맞추어 함수를 하나씩 늘려 가다 보면 어떤 함수를 어떤 경우에 호출해야 하는지를 판단하는 것조차 헷갈리게 된다. 위와 같이 스트링에 관련된 데이터와 함수만을 뽑아 놓고 봤을 때는 복잡하지 않기 때문에 지금 당장 이들을 연관시키는 것이 어렵지 않을 것이다. 하지만 코드가 수만 줄이 넘어가고 프로젝트가 커지면서 점차 ST_STRBUF 구조체를 어떤 식으로 다루어야 하는지 정확히 알 수 없게 될 것이다. 또 커뮤니케이션의 부재로 인해 ST_STRBUF 구조체를 약속된 함수가 아닌 임의의 방식 으로 조작하여 프로그램이 오동작하는 결과를 초래할 수도 있다. ST_STRBUF 구조체를 전혀 연관성 없는 다른 함수에 대입시켜서 데이터가 깨졌다면 그 원인이 mystr 계열 함수 때문인지 아니면 개발자의 단순한 실수인지 파악하기도 쉬운 일은 아니다.

C++로 만든 스트링 클래스 예제

C++을 사용하여 위와 동일한 기능을 하는 스트링을 구현해 보자.
class CMyString
{
public:
   int Assign(char* a_pStr);
   int Append(char* a_pStr);
   int Find(char a_chFind);

public:
   CMyString(int a_nSize);
   ~CMyString();

private:
   int m_nLen;
   char* m_pStr;
};
스트링과 관련된 변수와 함수를 모아서 CMyString 클래스 안에 집어넣었다. 이 클래스를 활용해서 샘플 코드를 작성해 보자.
int main()
{
   CMyString str(256);
   
   str.Assign("abc");
   str.Append("def");
   str.Find('d');

   return 0;
}
우선 호출되는 함수가 어떤 클래스 소속인지 명확하므로 프로젝트가 커진다고 해서 어떤 함수를 호출해야 하는지 헷갈릴 가능성이 훨씬 줄어들었다(없다라는 뜻은 아니다). 그리고 변수를 private 영역에 넣어 클래스 외부에서 접근이 불가능하도록 만들었으므로 변수를 잘못 조작해서 프로그램이 오동작 할 가능성을 없앴다. 또 힙(Heap)메모리의 생성과 소멸도 CMyString 클래스의 생성자, 파괴자 안에서 알아서 동작할 것이므로 직접적으로 메모리를 다루어서 발생할 수 있는 문제점을 제거하였다.

같은 기능을 C와 C++코드로 예를 들었지만 진정한 객체지향의 힘은 위에 보여지는 코드 몇 줄을 비교한다고 얻어지는 것이 아니다. 개발을 해 나가면서 코드를 추가하고 기능을 확장할 때 객체지향 언어가 지원해 주는 막강한 기능을 활용한다면 더 안정적이고 쉽게 덩치를 키워 나갈 수 있다.

정리

백 줄짜리 코드를 디버깅하고 확장하는데 백 원이 든다면 천 줄짜리 코드를 디버깅하고 확장하는 데는 천원이 아닌 만원이 든다. 그 이상은 코드의 줄 수에 따른 단순 비례가 아닌 기하급수적으로 늘어나는 비용을 지불하게 될 것이다. 사실 천줄 단위의 프로그램은 구조적 프로그래밍을 통해 작성하나 객체지향 프로그래밍을 통해 작성하나 그 효과는 별반 차이가 없다. 많은 오해가 이런 간단한 예제를 통해서 형성되는데 현실적으로 최소한 수 만줄 이상의 코드를 작성할 때 진정한 개발 방법론의 가치를 알수 있다.

C가 처음 세상에 나왔을 때 C는 기존 프로그래밍의 단점을 혁신적으로 보강해서 나온 언어였다. 그 당시의 프로그램은 현재의 프로그램과 그 형태나 크기가 많이 달라 구조적 프로그래밍만으로도 개발하는데 문제가 없었다. 하지만 프로그램이 점점 커지자 구조적 프로그래밍만으로는 너무 많은 비용이 소모되었다. 이를 극복하기 위해 더 좋은 방법에 대한 탐구가 모색되어 왔고 그 결과 객체지향 프로그래밍이 등장한 것이다. 객체지향 프로그래밍은 구조적 프로그래밍이 가지는 단점을 보완하면서 더 큰 프로그램을 개발하는데 적합한 개념과 여러 가지 언어적 지원이 덧붙여진 연구와 경험의 산물이다.

본 장에서는 C와 C++을 사용하여 아주 기초적인 부분에서의 비교만을 해보았을 뿐이다. 여러분들이 실전에서 큰 프로그램을 작성할 때 느끼는 근본적인 개발 방법론의 차이는 훨씬 더 크다고 할 수 있다. 하지만 오해하지 말아야 할 점은 두 방법 중 어느 한 방법에 도저히 극복할 수 없는 치명적 결함이 있다는 것은 아니라는 것이다. 객체지향이 더 나중에 나온 방법이긴 하지만 구조적 프로그래밍 역시 당당히 오랫동안 쌓아 온 위치를 지켜 왔으며 그 오랜 시간 만큼 단점들을 극복할 수 있는 여러 가지 기법들이 개발되어 왔다. 반면 객체지향은 더 나중에 나온 만큼 기존의 어렵고 높은 레벨의 개발자들만이 영유했던 개념이나 테크닉들을 언어적으로 지원해서 생산성을 높인 방법이라고 할 수 있다. 막연히 서로 다른 방법이라고 보지 말고 언어가 발전해 온 역사를 이해하라. 또 현재 진행형으로 발전해 가는 모습을 통해 어떤 부분들이 추가, 삭제되는지를 살펴 본다면 언어에 대해 근본적으로 이해하는데 많은 도움이 될 것이다.


[출처 : http://www.hanb.co.kr/network/view.html?bi_id=1465]
제공 : 한빛 네트워크
저자 : 문우식
출처 : Blog2Book, 패턴 그리고 객체지향적 코딩의 법칙

개발팀에 새로 합류한 신입사원 나초보씨는 어느 날 팀장으로부터 간단한 계산 모듈을 만들라는 지시를 받았다. 팀장은 객체지향으로 개발하라는 당부의 말도 잊지 않았는데, C밖에 모르는 나초보씨는 고민에 빠졌다. 간단한 모듈이라서 익숙한 C로 만들면 3일이면 될 것 같았기 때문이다. 하지만 팀장의 말도 있고 해서 일단 객체지향을 공부해 보기로 했다. 하지만 클래스를 비롯해서 C++만의 문법을 익히는 도중에도, 근본적으로 도대체 왜 C가 아닌 꼭 C++로 만들어야 하는지 나초보씨는 납득할 수가 없었다.

나초보 : C로 개발하면 안되나요?
팀장 : 객체지향으로 개발하는 것이 좋으니 C++로 만드세요.
나초보 : 아니 아무리 생각해도 함수가 동작하는 것은 똑같은데 왜 굳이 제가 익숙치 도 않은 C++을 사용해야 하는지 모르겠습니다. 또 제가 왜 객체지향을 공부 해야 하는지도 모르겠습니다.
팀장 : 나초보씨 뿐만 아니라 다른 팀원들도 C++로 개발하니 그냥 C++을 사용하는 것 입니다.
나초보 : 회사의 방침이기 때문에 C++을 사용해야 된다는 건가요?
팀장 : ......
나초보 : 회사의 방침이 아니라면 왜 굳이 제가 익숙치도 않은 C++로 개발해야 되는 건가요? C로 개발하면 안되나요?

나초보씨처럼 객체지향 때문에 한번쯤은 왜 구조적 프로그래밍 언어인 C가 아닌 객체지향 언어인 C++로 개발해야 하는가에 대해 근본적인 의문을 가져본 적이 있는가? 아무 생각 없이 많은 사람들이“객체지향이 대세다!”라고 외치기 때문에 막연히 좋은가보다 하며 유행을 따르다 보니 객체지향을 공부하는 것인가? C++이 C의 모든 기능을 포함한 언어의 확장이기 때문에 더 능숙하게 사용하면 폼나 보이기 때문일까? 왜 객체지향 개발 방법이 권장되고 있는지에 대해 현실적인 관점에서 알아보도록 하자.

의문점

모든 프로젝트를 한가지 언어만으로 개발할 수는 없다. 개발을 시작할 때 가장 먼저 결정해야 하는 일은 프로젝트 성격에 맞는 가장 적합한 언어를 선정하는 것이다. C/C++이 최고의 언어라며 Web Application을 개발하는데 ASP, PHP, JSP 등을 무시한 채 오로지 C-CGI(Common Gateway Interface)로 개발하는 것도 정답이 아니고 UI 중심이나 데이터베이스 관련 프로그램을 개발하면서 Visual Basic이나 Delphi, Power Builder등을 무시하는 행동도 또한 정답이 아니다.

언어를 선택하는 것이 우선이고 선택된 언어가 C/C++이라고 한다면 개발 방법을 C 중심으로 할 것인지 객체지향을 활용하기 위해 C++을 사용할 것인지 결정해야 한다. 이 대목에서 많은 개발자들은 자신에게 익숙한 언어를 먼저 염두에 두기 마련이다. C/C++을 모든 개발자가 능수능란하게 사용할 수 있다면 별 문제 아니겠지만 개발자마다 실력의 차이나 개발했었던 환경의 차이로 인해 C나 C++중 더 익숙한 환경이 있을 것이다(물론 가장 좋은 경우는 이 두 가지 모두 익숙한 경우이겠지만 말이다).

단순히 팀이나 회사의 방침이 객체지향 개발이기 때문에 익숙하지도 않은 객체지향 언어를 공부하면서까지 개발해야 하는 것일까? 더 심각한 문제는 닥쳐서 공부를 한다고 해서 하루 아침에 객체지향에 능숙해지지 않는다는 점이다. 적지 않은 시간 동안 시행착오를 겪고 관련 공부를 많이 하고 나서야 객체지향에 능숙해 질 것이다. 이런 노력이 없다면 C++로 개발해도 C로 개발하는 것과는 별반 다를 바가 없을 것이다. 당장 내가 C로 잘 만들 수 있는데 왜 굳이 객체지향 언어인 C++, Java를 배워야 하는 걸까?

Why not?

정말 당신이 C에 능숙하다면 C로 개발하라. 안될 이유가 없지 않은가? 모든 팀원들이 C에 능숙하고 코드의 확장이나 유지 보수 그리고 배포에 문제가 없다면 C로 개발하는 것이 정답이다. 실제로 퍼포먼스(Performance) 면에서는 C가 더 빠르다.

많은 개발자들이 왜 C++로 개발하는 것이 C보다 좋은지 명확한 답을 내주지 못한다. 단순히“C++은 상속, 캡슐화, 다형성 그리고 그밖에 디자인 패턴으로 대변되는 여러 가지 유용한 테크닉이 존재하기 때문에 C++로 개발해야 한다”라고 이야기하는 것은 C++에 익숙해 지고 나서 활용에 관한 부분이고 우리는 보다 근본적인 대답이 필요하다. 테크닉은 테크닉일 뿐 결국 기본이 중요하다. 개발 방법의 기본은 아래와 같다.
  • 개발을 체계적으로 진행할 수 있는가?
  • 개발하기 쉬운가?
  • 관리하기 쉬운가?
  • 확장하기 쉬운가?
  • 안정적인가?
하지만 C++이 등장하기 이전이나 지금이나 많은 프로젝트들이 C로 진행되고 있는 것이 사실이다. 또 대부분의 오픈 소스들이 대부분 C로 개발되는 것도 간과할 수 없는 사실이다.

이해를 돕기 위해 오픈 소스의 구체적인 예를 들어보자. 오픈 소스로 유명한 프로그램 중에 리눅스의 포토샵이라고 불리는 GIMP(GNU Image Manipulation Program의 약어)라는 프로그램이 있다. GIMP의 코드 중 일부를 잠깐 살펴보자.
gdouble gimp_brushes_get_opacity (void);
gboolean gimp_brushes_set_opacity (gdouble opacity);
gboolean gimp_brushes_set_paint_mode
          (GimpLayerModeEffects paint_mode);
gboolean gimp_brushes_set_brush (const gchar *name);
GimpLayerModeEffects gimp_brushes_get_paint_mode (void);
위의 코드는 GIMP 2.2.14의 gimpbrushes.h파일의 함수 선언 내용 전부이다. 함수 선언 형태만 봐도 해당 함수가 어떤 기능을 수행하는지 또 어떤 범주에 속해 있는지 쉽게 감이 온다(GimpLayerModeEffects라는 구조체가 사용된다는 것도 알 수 있다. gdouble이나 gboolean과 같은 기본 타입들은 double이나 bool과 같은 의미로 이해하자). 아마 파일 이름을 몰라도 헤더 선언만 보고도 brush에 관한 함수라는 것을 알 수 있을 것이다. 당연히 gimpbrushes.h에 선언된 함수들은 gimpbrushes.c에 구현되어 있다.

누구나 GIMP소스를 본다면 언어를 떠나서 높은 가독성과 확장성에 놀랄 것이다(GIMP를 깊게 다루려고 하는 것은 아니다. 하지만 GIMP소스에 관심 있는 독자들은 GIMP홈페이지(http://www.gimp.org/에서 소스를 다운받아 볼 수 있다). 우리가 GIMP 의 예를 통해 이해해야 하는 점은 전 세계의 여러 개발자가 공동으로 작업하는 오픈소스가 마치 한 사람이 만든 것처럼 코드의 표기법을 비롯해 확장성 있는 소스의 구조와 높은 가독성을 가지고 있다는 점이다. 현실적으로 갓 개발에 입문한 새내기 개발자가 오픈 소스에 참여해서 세계적인 개발자들과 어깨를 나란히 하고 개발을 할 수 있을리 없다. 즉 이 정도 소스는 현실적으로 개발에 정통한 개발자들이 규칙을 정하고 그 규칙을 정확히 잘 지킬 수 있을 때 얻을 수 있다.

개발 현실은?

위에서 좋은 예로 GIMP를 언급했다. 하지만 실제로 C로 만들었어도 알아보기 힘든 소스가 많이 있다. 구조적 프로그래밍은 결국 데이터와 데이터 조작 이 두 단어로 표현할 수 있고 이는 C의 구조체와 함수로 표현할 수 있다. 구조체를 통해 메모리를 할당하고 함수를 통해 이 구조체 값을 변경하고 구조체 값에 기반해 원하는 기능을 수행한다. 하지만 익숙하지 않은 라이브러리나 생소한 코드를 접할 때 처음 부딪히는 문제는‘어떤 구조체를 사용해야 하는가’이다. 오픈 소스(Open Source)를 다운로드 받아 헤더를 열어 보니 너무나 많은 구조체가 존재한다. 이 중 과연 어떤 구조체를 사용해야 하는가는 알 수 없다. 다행히 샘플 코드를 참조해서 어떤 구조체를 중심으로 사용해야 하는지 알았다고 해도 아래와 같은 문제점이 있다.
  • 수를 호출해야 되는가?
  • 어떤 함수를 호출하면 안되는가?
  • 구조체의 변수들은 어떻게 변경해야 하는가? 직접 혹은 함수를 통해서?
  • 구조체 변수들이 의도되지 않게 변경됐을 때 프로그램은 어떻게 동작하는가?
Win32로 윈도우즈 프로그래밍을 해본 경험이 있는 독자라면 처음 윈도우를 띄우기 위해서 어떤 구조체를 선언하고 어떤 함수를 호출해야 되는지 막막했던 경험이 있을 것이다. 이 때 친절한 책들과 인터넷상에 있는 많은 자료들이 우리를 도와줬겠지만 실제로 프로젝트를 수행할 때는 이런 책들과 자료들이 언제나 존재한다고 볼 수 없다. 오히려 존재하지 않는 경우가 더욱 많다.

특정 구조체와 관련된 함수를 언어적으로 묶어 주는 개념이 있으면 좋을 것 같다. 그런 방법이 존재한다면 사용하고자 하는 구조체를 어떤 함수를 통해서 다루어야 하는지 헷갈릴 필요가 없을 테니 말이다. 위에 GIMP의 예를 보면 gimp_brushes_get_opacity 함수는 이름만으로‘GIMP의 Brushes에서 Opacity를 Get하는 함수’라는 것을 알 수 있다. 또 다른 gimp_brushes_set_paint_mode 함수는‘GIMP의 Brushes에서 Paint Mode를 Set하는 함수’임을 알 수 있다. 그리고 이 함수들이 하나의 헤더에 같이 있으므로 비슷한 부류의 함수라는 것을 쉽게 알 수 있다. 프로그램이 여러 사람에 의해 동시 다발적으로 수정되고 추가되고 삭제되면서 이런 통일성을 지속적으로 지킬 수 있는 것은 정말 높은 수준을 의미한다고 할 수 있다.

개발하기에 가장 좋은 방법은 수준 높은 개발자들 여럿이서 서로 원하는 수준에서 활발히 커뮤니케이션을 하면서 일하는 것이다. 하지만 우리가 일하는 현실을 돌아보자. 회사 내에서 모든 개발자가 같은 수준에서 개발할 수는 없다. 중급 개발자와 초급 개발자가 똑같은 수준에서 개발을 할 수는 없을 것이다. 중급 개발자가 별도의 코멘트(Comment)없이 마우스 제어 관련 기능 함수 선언을 mouse.h라는 파일에 모아 놨는데 초급 개발자가 아무 생각 없이 keyboard_input( ) 함수를 mouse.h에 넣을 수도 있다. 그렇다고 초급 개발자가 만든 코드를 매번 중급 개발자가 검토하고 잘못된 사항을 고쳐 주고 관리하는 것도 정답이 아니다. 또 모든 개발자들의 스타일이 제각각인데 이런 부분을 규칙으로 정해 놓고 지키도록 자율성에 맡길 수도 없는 노릇이다.

위에서 다소 생소할 수 있는 GIMP의 예를 굳이 꺼낸 이유는 소스가 몇 백줄 또는 몇 천줄까지는 어떤 방법으로 개발한다 해도 코드의 양이 적기 때문에 쉽게 수정할 수 있다. 하지만 사용자들에게 릴리즈되는 제품은 코드가 최소 몇 만줄 이상이므로 이런 큰 코드를 여러 개발자가 동시 작업하면서도 일관성 있는 코드를 만드는 것은 절대 쉬운 일이 아니다. 현실은 우리의 생각만큼 아름답지 못하다.


[출처 : http://www.hanb.co.kr/network/view.html?bi_id=1463]

+ Recent posts